| // Copyright 2016 Google LLC |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package disco |
| |
| import ( |
| "io/ioutil" |
| "reflect" |
| "strings" |
| "testing" |
| ) |
| |
| var stringSchema = &Schema{ |
| Type: "string", |
| Kind: SimpleKind, |
| } |
| |
| func TestDocument(t *testing.T) { |
| bytes, err := ioutil.ReadFile("testdata/test-api.json") |
| if err != nil { |
| t.Fatal(err) |
| } |
| got, err := NewDocument(bytes) |
| if err != nil { |
| t.Fatal(err) |
| } |
| want := &Document{ |
| ID: "storage:v1", |
| Name: "storage", |
| Version: "v1", |
| Title: "Cloud Storage JSON API", |
| RootURL: "https://www.googleapis.com/", |
| ServicePath: "storage/v1/", |
| BasePath: "/storage/v1/", |
| DocumentationLink: "https://developers.google.com/storage/docs/json_api/", |
| Auth: Auth{ |
| OAuth2Scopes: []Scope{ |
| {"https://www.googleapis.com/auth/cloud-platform", |
| "View and manage your data across Google Cloud Platform services"}, |
| {"https://www.googleapis.com/auth/cloud-platform.read-only", |
| "View your data across Google Cloud Platform services"}, |
| {"https://www.googleapis.com/auth/devstorage.full_control", |
| "Manage your data and permissions in Google Cloud Storage"}, |
| {"https://www.googleapis.com/auth/devstorage.read_only", |
| "View your data in Google Cloud Storage"}, |
| {"https://www.googleapis.com/auth/devstorage.read_write", |
| "Manage your data in Google Cloud Storage"}, |
| }, |
| }, |
| Features: []string{"dataWrapper"}, |
| Schemas: map[string]*Schema{ |
| "Bucket": { |
| Name: "Bucket", |
| ID: "Bucket", |
| Type: "object", |
| Description: "A bucket.", |
| Kind: StructKind, |
| Properties: []*Property{ |
| {"cors", &Schema{ |
| Type: "array", |
| Kind: ArrayKind, |
| ItemSchema: &Schema{ |
| Type: "object", |
| Kind: StructKind, |
| Properties: []*Property{ |
| {"maxAgeSeconds", &Schema{ |
| Type: "integer", |
| Format: "int32", |
| Kind: SimpleKind, |
| }}, |
| {"method", &Schema{ |
| Type: "array", |
| Kind: ArrayKind, |
| ItemSchema: stringSchema, |
| }}, |
| }, |
| }, |
| }}, |
| {"id", stringSchema}, |
| {"kind", &Schema{ |
| Type: "string", |
| Kind: SimpleKind, |
| Default: "storage#bucket", |
| }}, |
| }, |
| }, |
| "Buckets": { |
| ID: "Buckets", |
| Name: "Buckets", |
| Type: "object", |
| Kind: StructKind, |
| Properties: []*Property{ |
| {"items", &Schema{ |
| Type: "array", |
| Kind: ArrayKind, |
| ItemSchema: &Schema{ |
| Kind: ReferenceKind, |
| Ref: "Bucket", |
| RefSchema: nil, |
| }, |
| }}, |
| }, |
| }, |
| "VariantExample": { |
| ID: "VariantExample", |
| Name: "VariantExample", |
| Type: "object", |
| Kind: StructKind, |
| Variant: &Variant{ |
| Discriminant: "type", |
| Map: []*VariantMapItem{ |
| {TypeValue: "Bucket", Ref: "Bucket"}, |
| {TypeValue: "Buckets", Ref: "Buckets"}, |
| }, |
| }, |
| }, |
| }, |
| Methods: MethodList{ |
| &Method{ |
| Name: "getCertForOpenIdConnect", |
| ID: "oauth2.getCertForOpenIdConnect", |
| Path: "oauth2/v1/certs", |
| HTTPMethod: "GET", |
| Response: &Schema{Ref: "Bucket", Kind: ReferenceKind}, |
| }, |
| }, |
| Resources: ResourceList{ |
| &Resource{ |
| Name: "buckets", |
| FullName: ".buckets", |
| Methods: MethodList{ |
| &Method{ |
| Name: "get", |
| ID: "storage.buckets.get", |
| Path: "b/{bucket}", |
| HTTPMethod: "GET", |
| Description: "d", |
| Parameters: ParameterList{ |
| &Parameter{ |
| Name: "bucket", |
| Schema: Schema{ |
| Type: "string", |
| }, |
| Required: true, |
| Location: "path", |
| }, |
| &Parameter{ |
| Name: "ifMetagenerationMatch", |
| Schema: Schema{ |
| Type: "string", |
| Format: "int64", |
| }, |
| Location: "query", |
| }, |
| &Parameter{ |
| Name: "projection", |
| Schema: Schema{ |
| Type: "string", |
| Enums: []string{"full", "noAcl"}, |
| EnumDescriptions: []string{ |
| "Include all properties.", |
| "Omit owner, acl and defaultObjectAcl properties.", |
| }, |
| }, |
| Location: "query", |
| }, |
| }, |
| ParameterOrder: []string{"bucket"}, |
| Response: &Schema{Ref: "Bucket", Kind: ReferenceKind}, |
| Scopes: []string{ |
| "https://www.googleapis.com/auth/cloud-platform", |
| "https://www.googleapis.com/auth/cloud-platform.read-only", |
| "https://www.googleapis.com/auth/devstorage.full_control", |
| "https://www.googleapis.com/auth/devstorage.read_only", |
| "https://www.googleapis.com/auth/devstorage.read_write", |
| }, |
| SupportsMediaDownload: true, |
| MediaUpload: &MediaUpload{ |
| Accept: []string{"application/octet-stream"}, |
| MaxSize: "1GB", |
| Protocols: map[string]Protocol{ |
| "simple": { |
| Multipart: true, |
| Path: "/upload/customDataSources/{customDataSourceId}/uploads", |
| }, |
| "resumable": { |
| Multipart: true, |
| Path: "/resumable/upload/customDataSources/{customDataSourceId}/uploads", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| // Resolve schema references. |
| bucket := want.Schemas["Bucket"] |
| want.Schemas["Buckets"].Properties[0].Schema.ItemSchema.RefSchema = bucket |
| want.Methods[0].Response.RefSchema = bucket |
| want.Resources[0].Methods[0].Response.RefSchema = bucket |
| for k, gs := range got.Schemas { |
| ws := want.Schemas[k] |
| if !reflect.DeepEqual(gs, ws) { |
| t.Fatalf("schema %s: got\n%+v\nwant\n%+v", k, gs, ws) |
| } |
| } |
| if len(got.Schemas) != len(want.Schemas) { |
| t.Errorf("want %d schemas, got %d", len(got.Schemas), len(want.Schemas)) |
| } |
| compareMethodLists(t, got.Methods, want.Methods) |
| for i, gr := range got.Resources { |
| wr := want.Resources[i] |
| compareMethodLists(t, gr.Methods, wr.Methods) |
| if !reflect.DeepEqual(gr, wr) { |
| t.Fatalf("resource %d: got\n%+v\nwant\n%+v", i, gr, wr) |
| } |
| } |
| if len(got.Resources) != len(want.Resources) { |
| t.Errorf("want %d resources, got %d", len(got.Resources), len(want.Resources)) |
| } |
| if !reflect.DeepEqual(got, want) { |
| t.Errorf("got\n%+v\nwant\n%+v", got, want) |
| } |
| } |
| |
| func compareMethodLists(t *testing.T, got, want MethodList) { |
| if len(got) != len(want) { |
| t.Fatalf("got %d methods, want %d", len(got), len(want)) |
| } |
| for i, gm := range got { |
| gm.JSONMap = nil // don't compare the raw JSON |
| wm := want[i] |
| if !reflect.DeepEqual(gm, wm) { |
| t.Errorf("#%d: got\n%+v\nwant\n%+v", i, gm, wm) |
| } |
| } |
| } |
| |
| func TestDocumentErrors(t *testing.T) { |
| for _, in := range []string{ |
| `{"name": "X"`, // malformed JSON |
| `{"id": 3}`, // ID is an int instead of a string |
| `{"auth": "oauth2": { "scopes": "string" }}`, // wrong auth structure |
| } { |
| _, err := NewDocument([]byte(in)) |
| if err == nil { |
| t.Errorf("%s: got nil, want error", in) |
| } |
| } |
| } |
| |
| func TestSchemaErrors(t *testing.T) { |
| for _, s := range []*Schema{ |
| {Type: "array"}, // missing item schema |
| {Type: "string", ItemSchema: &Schema{}}, // items w/o array |
| {Type: "moose"}, // bad kind |
| {Ref: "Thing"}, // unresolved reference |
| } { |
| if err := s.init(nil); err == nil { |
| t.Errorf("%+v: got nil, want error", s) |
| } |
| } |
| } |
| |
| func TestErrorDoc(t *testing.T) { |
| bytes, err := ioutil.ReadFile("testdata/error.json") |
| if err != nil { |
| t.Fatal(err) |
| } |
| if _, err := NewDocument(bytes); err == nil { |
| t.Error("got nil, want error") |
| } else if !strings.Contains(err.Error(), "404") { |
| t.Errorf("got %v, want 404", err) |
| } |
| } |