Files
go-omni/cmd/go-omni/apigen/shared_test.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")
}
}