You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

278 lines
7.5 KiB

  1. // Copyright 2016 Google LLC
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package disco
  5. import (
  6. "io/ioutil"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. )
  11. var stringSchema = &Schema{
  12. Type: "string",
  13. Kind: SimpleKind,
  14. }
  15. func TestDocument(t *testing.T) {
  16. bytes, err := ioutil.ReadFile("testdata/test-api.json")
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. got, err := NewDocument(bytes)
  21. if err != nil {
  22. t.Fatal(err)
  23. }
  24. want := &Document{
  25. ID: "storage:v1",
  26. Name: "storage",
  27. Version: "v1",
  28. Title: "Cloud Storage JSON API",
  29. RootURL: "https://www.googleapis.com/",
  30. ServicePath: "storage/v1/",
  31. BasePath: "/storage/v1/",
  32. DocumentationLink: "https://developers.google.com/storage/docs/json_api/",
  33. Auth: Auth{
  34. OAuth2Scopes: []Scope{
  35. {"https://www.googleapis.com/auth/cloud-platform",
  36. "View and manage your data across Google Cloud Platform services"},
  37. {"https://www.googleapis.com/auth/cloud-platform.read-only",
  38. "View your data across Google Cloud Platform services"},
  39. {"https://www.googleapis.com/auth/devstorage.full_control",
  40. "Manage your data and permissions in Google Cloud Storage"},
  41. {"https://www.googleapis.com/auth/devstorage.read_only",
  42. "View your data in Google Cloud Storage"},
  43. {"https://www.googleapis.com/auth/devstorage.read_write",
  44. "Manage your data in Google Cloud Storage"},
  45. },
  46. },
  47. Features: []string{"dataWrapper"},
  48. Schemas: map[string]*Schema{
  49. "Bucket": {
  50. Name: "Bucket",
  51. ID: "Bucket",
  52. Type: "object",
  53. Description: "A bucket.",
  54. Kind: StructKind,
  55. Properties: []*Property{
  56. {"cors", &Schema{
  57. Type: "array",
  58. Kind: ArrayKind,
  59. ItemSchema: &Schema{
  60. Type: "object",
  61. Kind: StructKind,
  62. Properties: []*Property{
  63. {"maxAgeSeconds", &Schema{
  64. Type: "integer",
  65. Format: "int32",
  66. Kind: SimpleKind,
  67. }},
  68. {"method", &Schema{
  69. Type: "array",
  70. Kind: ArrayKind,
  71. ItemSchema: stringSchema,
  72. }},
  73. },
  74. },
  75. }},
  76. {"id", stringSchema},
  77. {"kind", &Schema{
  78. Type: "string",
  79. Kind: SimpleKind,
  80. Default: "storage#bucket",
  81. }},
  82. },
  83. },
  84. "Buckets": {
  85. ID: "Buckets",
  86. Name: "Buckets",
  87. Type: "object",
  88. Kind: StructKind,
  89. Properties: []*Property{
  90. {"items", &Schema{
  91. Type: "array",
  92. Kind: ArrayKind,
  93. ItemSchema: &Schema{
  94. Kind: ReferenceKind,
  95. Ref: "Bucket",
  96. RefSchema: nil,
  97. },
  98. }},
  99. },
  100. },
  101. "VariantExample": {
  102. ID: "VariantExample",
  103. Name: "VariantExample",
  104. Type: "object",
  105. Kind: StructKind,
  106. Variant: &Variant{
  107. Discriminant: "type",
  108. Map: []*VariantMapItem{
  109. {TypeValue: "Bucket", Ref: "Bucket"},
  110. {TypeValue: "Buckets", Ref: "Buckets"},
  111. },
  112. },
  113. },
  114. },
  115. Methods: MethodList{
  116. &Method{
  117. Name: "getCertForOpenIdConnect",
  118. ID: "oauth2.getCertForOpenIdConnect",
  119. Path: "oauth2/v1/certs",
  120. HTTPMethod: "GET",
  121. Response: &Schema{Ref: "Bucket", Kind: ReferenceKind},
  122. },
  123. },
  124. Resources: ResourceList{
  125. &Resource{
  126. Name: "buckets",
  127. FullName: ".buckets",
  128. Methods: MethodList{
  129. &Method{
  130. Name: "get",
  131. ID: "storage.buckets.get",
  132. Path: "b/{bucket}",
  133. HTTPMethod: "GET",
  134. Description: "d",
  135. Parameters: ParameterList{
  136. &Parameter{
  137. Name: "bucket",
  138. Schema: Schema{
  139. Type: "string",
  140. },
  141. Required: true,
  142. Location: "path",
  143. },
  144. &Parameter{
  145. Name: "ifMetagenerationMatch",
  146. Schema: Schema{
  147. Type: "string",
  148. Format: "int64",
  149. },
  150. Location: "query",
  151. },
  152. &Parameter{
  153. Name: "projection",
  154. Schema: Schema{
  155. Type: "string",
  156. Enums: []string{"full", "noAcl"},
  157. EnumDescriptions: []string{
  158. "Include all properties.",
  159. "Omit owner, acl and defaultObjectAcl properties.",
  160. },
  161. },
  162. Location: "query",
  163. },
  164. },
  165. ParameterOrder: []string{"bucket"},
  166. Response: &Schema{Ref: "Bucket", Kind: ReferenceKind},
  167. Scopes: []string{
  168. "https://www.googleapis.com/auth/cloud-platform",
  169. "https://www.googleapis.com/auth/cloud-platform.read-only",
  170. "https://www.googleapis.com/auth/devstorage.full_control",
  171. "https://www.googleapis.com/auth/devstorage.read_only",
  172. "https://www.googleapis.com/auth/devstorage.read_write",
  173. },
  174. SupportsMediaDownload: true,
  175. MediaUpload: &MediaUpload{
  176. Accept: []string{"application/octet-stream"},
  177. MaxSize: "1GB",
  178. Protocols: map[string]Protocol{
  179. "simple": {
  180. Multipart: true,
  181. Path: "/upload/customDataSources/{customDataSourceId}/uploads",
  182. },
  183. "resumable": {
  184. Multipart: true,
  185. Path: "/resumable/upload/customDataSources/{customDataSourceId}/uploads",
  186. },
  187. },
  188. },
  189. },
  190. },
  191. },
  192. },
  193. }
  194. // Resolve schema references.
  195. bucket := want.Schemas["Bucket"]
  196. want.Schemas["Buckets"].Properties[0].Schema.ItemSchema.RefSchema = bucket
  197. want.Methods[0].Response.RefSchema = bucket
  198. want.Resources[0].Methods[0].Response.RefSchema = bucket
  199. for k, gs := range got.Schemas {
  200. ws := want.Schemas[k]
  201. if !reflect.DeepEqual(gs, ws) {
  202. t.Fatalf("schema %s: got\n%+v\nwant\n%+v", k, gs, ws)
  203. }
  204. }
  205. if len(got.Schemas) != len(want.Schemas) {
  206. t.Errorf("want %d schemas, got %d", len(got.Schemas), len(want.Schemas))
  207. }
  208. compareMethodLists(t, got.Methods, want.Methods)
  209. for i, gr := range got.Resources {
  210. wr := want.Resources[i]
  211. compareMethodLists(t, gr.Methods, wr.Methods)
  212. if !reflect.DeepEqual(gr, wr) {
  213. t.Fatalf("resource %d: got\n%+v\nwant\n%+v", i, gr, wr)
  214. }
  215. }
  216. if len(got.Resources) != len(want.Resources) {
  217. t.Errorf("want %d resources, got %d", len(got.Resources), len(want.Resources))
  218. }
  219. if !reflect.DeepEqual(got, want) {
  220. t.Errorf("got\n%+v\nwant\n%+v", got, want)
  221. }
  222. }
  223. func compareMethodLists(t *testing.T, got, want MethodList) {
  224. if len(got) != len(want) {
  225. t.Fatalf("got %d methods, want %d", len(got), len(want))
  226. }
  227. for i, gm := range got {
  228. gm.JSONMap = nil // don't compare the raw JSON
  229. wm := want[i]
  230. if !reflect.DeepEqual(gm, wm) {
  231. t.Errorf("#%d: got\n%+v\nwant\n%+v", i, gm, wm)
  232. }
  233. }
  234. }
  235. func TestDocumentErrors(t *testing.T) {
  236. for _, in := range []string{
  237. `{"name": "X"`, // malformed JSON
  238. `{"id": 3}`, // ID is an int instead of a string
  239. `{"auth": "oauth2": { "scopes": "string" }}`, // wrong auth structure
  240. } {
  241. _, err := NewDocument([]byte(in))
  242. if err == nil {
  243. t.Errorf("%s: got nil, want error", in)
  244. }
  245. }
  246. }
  247. func TestSchemaErrors(t *testing.T) {
  248. for _, s := range []*Schema{
  249. {Type: "array"}, // missing item schema
  250. {Type: "string", ItemSchema: &Schema{}}, // items w/o array
  251. {Type: "moose"}, // bad kind
  252. {Ref: "Thing"}, // unresolved reference
  253. } {
  254. if err := s.init(nil); err == nil {
  255. t.Errorf("%+v: got nil, want error", s)
  256. }
  257. }
  258. }
  259. func TestErrorDoc(t *testing.T) {
  260. bytes, err := ioutil.ReadFile("testdata/error.json")
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. if _, err := NewDocument(bytes); err == nil {
  265. t.Error("got nil, want error")
  266. } else if !strings.Contains(err.Error(), "404") {
  267. t.Errorf("got %v, want 404", err)
  268. }
  269. }