97 lines
4.3 KiB
Go
97 lines
4.3 KiB
Go
package apigen
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestControlledSharedContracts(t *testing.T) {
|
|
root := t.TempDir()
|
|
shared := filepath.Join(root, "shared")
|
|
writeFile(t, filepath.Join(shared, "response.api"), "response Common (codeType: int32; successCode: 0; errorCode: 9999; dataMode: always)\ntype Item { Name string `json:\"name\"` }\n")
|
|
for _, service := range []string{"api", "id"} {
|
|
dir := filepath.Join(root, service)
|
|
entry := filepath.Join(dir, "api/service.api")
|
|
writeFile(t, entry, "import \"@common/response.api\"\n@app(defaultResponse: Common)\nservice demo {\n@handler get\nget /get returns (Item)\n}\n")
|
|
config := `{"roots":{"common":{"path":"../../shared","version":"1.0.0"}}}`
|
|
writeFile(t, filepath.Join(dir, "api/omni.imports.json"), config)
|
|
spec, err := Parse(entry)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(spec.Sources) != 2 || len(spec.SourcePaths) != 2 {
|
|
t.Fatalf("%+v", spec)
|
|
}
|
|
pin := sharedHash(spec.Sources, "common")
|
|
config = strings.Replace(config, `"version":"1.0.0"`, `"version":"1.0.0","sha256":"`+pin+`"`, 1)
|
|
writeFile(t, filepath.Join(dir, "api/omni.imports.json"), config)
|
|
o := Options{Dir: dir, API: entry, Module: "example.com/" + service, FrameworkDir: frameworkRoot(t)}
|
|
if _, err = Generate(o); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
o.Check = true
|
|
if _, err = Generate(o); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = os.Stat(filepath.Join(dir, "api/@common")); !os.IsNotExist(err) {
|
|
t.Fatal("shared contract copied into service")
|
|
}
|
|
document := readFile(t, filepath.Join(dir, "docs/openapi.json"))
|
|
if !strings.Contains(document, pin) || !strings.Contains(document, "@common/response.api") {
|
|
t.Fatal("missing provenance")
|
|
}
|
|
writeFile(t, filepath.Join(dir, "api/omni.imports.json"), strings.Replace(config, pin, strings.Repeat("0", 64), 1))
|
|
if _, err = Parse(entry); err == nil {
|
|
t.Fatal("checksum mismatch accepted")
|
|
}
|
|
}
|
|
// An undeclared alias, traversal, symlink escape and cycle are all rejected.
|
|
for _, imp := range []string{"@missing/response.api", "@common/../outside.api", "../shared/response.api", "@common/escape.api", "@common/cycle.api"} {
|
|
local := filepath.Join(root, "consumer")
|
|
writeFile(t, filepath.Join(local, "omni.imports.json"), `{"roots":{"common":{"path":"../shared"}}}`)
|
|
writeFile(t, filepath.Join(root, "outside.api"), "type Outside {}\n")
|
|
_ = os.Symlink(filepath.Join(root, "outside.api"), filepath.Join(shared, "escape.api"))
|
|
writeFile(t, filepath.Join(shared, "cycle.api"), "import \"cycle.api\"\n")
|
|
entry := filepath.Join(local, "service.api")
|
|
writeFile(t, entry, "import "+strconvQuote(imp)+"\nservice demo{\n@handler get\nget /get\n}\n")
|
|
if _, err := Parse(entry); err == nil {
|
|
t.Fatal("unsafe import accepted", imp)
|
|
}
|
|
}
|
|
}
|
|
func strconvQuote(value string) string { data, _ := json.Marshal(value); return string(data) }
|
|
func TestCatalogDocumentExportDoesNotGenerateRuntimeRegistry(t *testing.T) {
|
|
dir := t.TempDir()
|
|
entry := filepath.Join(dir, "service.api")
|
|
writeFile(t, entry, "@app(defaultResponse: Common)\nresponse Common(codeType: int32; successCode: 0; errorCode: 9999; messageField: msg; dataMode: always)\nservice demo{\n@handler get\nget /get returns (null)\n}\n")
|
|
var exported bytes.Buffer
|
|
err := apierrors.ExportCatalog(&exported, apierrors.Catalog{DefaultStatus: 200, Definitions: map[string]apierrors.Definition{"TOO_LONG": {Code: 400002, Message: "{label}不能超过{max}个字符", Params: []apierrors.Parameter{{Name: "label", Type: "string", Example: "企业名称"}, {Name: "max", Type: "int", Example: 100}}}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
writeFile(t, filepath.Join(dir, "omni.errors.json"), exported.String())
|
|
spec, err := Parse(entry)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c, err := Compile(spec)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(c.Spec.Errors) != 0 || !strings.Contains(string(c.Document), "企业名称不能超过100个字符") {
|
|
t.Fatal(string(c.Document))
|
|
}
|
|
target := filepath.Join(t.TempDir(), "catalog")
|
|
if _, err = Generate(Options{Dir: target, API: entry, Module: "example.com/catalog", FrameworkDir: frameworkRoot(t)}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = os.Stat(filepath.Join(target, "internal/apierrors/errorsGen.go")); !os.IsNotExist(err) {
|
|
t.Fatal("document metadata became a runtime error registry")
|
|
}
|
|
}
|