|  | // 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) | 
|  | } | 
|  | } |