From f50074f5928c3afa3f70af8086523116ed6d71de Mon Sep 17 00:00:00 2001 From: Andrea Lin Date: Mon, 5 Jun 2017 14:03:04 -0700 Subject: [PATCH] Nodeify Discovery objects (#1322) * merge master to Discogapic (#1304) * Fix JSON pretty print in Ruby sample (#1254) * Ruby: README Overhaul (feat. examples) (#1245) * go: use new metadata methods (#1262) Updates GoogleCloudPlatform/google-cloud-go#624. metadata.FromContext and metdata.NewContext are replaced by metadata.{New,From}{Incoming,Outgoing}Context. Generated unit tests now verify that x-goog-api-client header is inserted. Additionally, clients now save a string slice containing x-goog-api-client header value instead of the value by itself. This is a small optimization so that we don't create a new slice every time. * Change media body from an object to a string (#1256) Samples fail before sending a request if the media body is an object. * Fix NONE auth Go sample (#1261) * Change Node.js unit test require. (#1264) * Ruby: Allow doc gapic generation to generate tests. (#1266) * Ruby: Remove aliasing from method samples and tests (#1253) * Ruby: Fix broken baselines from aliasing fix (#1269) * Remove unused code (#1270) * Python: README overhaul. (#1263) * Ruby: Update gemspec and add useful metadata files (#1258) * Ruby: Update gemspec and add useful metadata files * Specify HTTP client when constructing client (#1275) If a HTTP client is not passed to `build`, the Google API Python client will create a default one and attempt to authenticate it. This causes failures in environments where ADC auth is not available (Travis). In any case, it's not useful to access any auth code in the mock tests. This commit removes that possibility. * Fix JSON print in Ruby (#1274) It turns out that `to_h` is not a method available on every object returned by the samples at the moment. Also, there's some kind of decoding bug showing up in certain samples where the JSON module is unable to unparse the response. It's troublesome to have so much boilerplate just to pretty print. This commit removes the pretty calls in favor of the vanilla `to_json` method implemented by the base model class in the Ruby client. In the future, once the bugs w.r.t `pretty_generate` have been resolved, we can revert. * NodeJS: Update version index to support partial veneers (#1267) * NodeJS: Updates to package.json (#1268) * Migrate import disambiguation to Python MVVM (#1243) * Fix Node package.json (#1282) * go: use time.UnixNano instead of testutil.UIDSpace (#1279) Since generated code should be testable from api-client-staging repo, we want to reduce dependency on other cloud.google.com/go packages, especially internal ones. Clients will still depend on testutil for ProjID and TokenSource. This is OK, since they can be easily reimplemented in google-client-staging repo itself. * Update Java grpc metadata for new staging structure (#1265) * PHP: share credentials with operations client (#1283) * java: move CredentialProvider up to ClientSettings (#1251) This implements the client side changes to support googleapis/gax-java#305. * NodeJS: generate readme. (#1240) * NodeJS: Small additions to the package.json (#1289) * NodeJS: Use fileheader for copyright lines. (#1293) * NodeJS: Use correct casing for partial veneers (#1295) * NodeJS: Small readme fix from GCN reviews (#1294) * go: make longrunning methods use generated longrunning client (#1288) The cloud.google.com/go/longrunning package will need to change slightly to accomodate this change. xGoogHeader is now gone from the generated longrunnging types, as the header will be automatically inserted by LROClient itself. * NodeJS: Update partial veneer surface to add api documentation. (#1296) * NodeJS: Metadata updates. (#1298) * Readme: Update readme templates to add api summaries. (#1299) * Add PHP Exception tests (#951) * Add exception tests * Remove unnecessary checks in exception tests * Process markdown cloud links for PHP (#1091) * Process markdown cloud links for PHP * Restructure comment formatting * go: return error creating LRO client instead of panicking (#1300) * fails b/c Node.empty() uses null params * one test passes * all current tests pass * tests for Node parent() * Test * removed Method.empty(): * reordering methods for convention * made Node.from(Node, path) methods package private * removed path() from Document, Schema, and Method * removed static constructors with empty parent node --- .../api/codegen/discovery/Document.java | 76 +++++++++++++------ .../google/api/codegen/discovery/Method.java | 61 ++++++++++----- .../google/api/codegen/discovery/Node.java | 28 +++++++ .../google/api/codegen/discovery/Schema.java | 74 +++++++++++------- .../api/codegen/discovery/DocumentTest.java | 16 ++-- .../api/codegen/discovery/MethodTest.java | 8 +- .../api/codegen/discovery/SchemaTest.java | 18 +++-- .../codegen/discoverytestdata/document_.json | 1 + 8 files changed, 190 insertions(+), 92 deletions(-) create mode 100644 src/main/java/com/google/api/codegen/discovery/Node.java diff --git a/src/main/java/com/google/api/codegen/discovery/Document.java b/src/main/java/com/google/api/codegen/discovery/Document.java index f788e56f30..77ea38dba6 100644 --- a/src/main/java/com/google/api/codegen/discovery/Document.java +++ b/src/main/java/com/google/api/codegen/discovery/Document.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.discovery; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.auto.value.AutoValue; import java.util.ArrayList; @@ -21,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; /** * A representation of a Discovery Document. @@ -29,7 +31,7 @@ * example, this class combines all methods in the Discovery Document into one list for convenience. */ @AutoValue -public abstract class Document { +public abstract class Document implements Node { // TODO(saicheems): Assert that all references link to a valid schema? @@ -54,8 +56,9 @@ public static Document from(DiscoveryNode root) { } String canonicalName = root.getString("canonicalName"); String description = root.getString("description"); + String id = root.getString("id"); Map schemas = parseSchemas(root); - List methods = parseMethods(root, ""); + List methods = parseMethods(root); Collections.sort(methods); // Ensure methods are ordered alphabetically by their ID. String name = root.getString("name"); if (canonicalName.isEmpty()) { @@ -68,21 +71,32 @@ public static Document from(DiscoveryNode root) { String version = root.getString("version"); boolean versionModule = root.getBoolean("version_module"); - return new AutoValue_Document( - "", // authInstructionsUrl (only intended to be overridden). - authType, - canonicalName, - description, - "", // discoveryDocUrl (only intended to be overridden). - methods, - name, - revision, - rootUrl, - schemas, - servicePath, - title, - version, - versionModule); + Document thisDocument = + new AutoValue_Document( + "", // authInstructionsUrl (only intended to be overridden). + authType, + canonicalName, + description, + "", // discoveryDocUrl (only intended to be overridden). + id, + methods, + name, + revision, + rootUrl, + schemas, + servicePath, + title, + version, + versionModule); + + for (Schema schema : schemas.values()) { + schema.setParent(thisDocument); + } + for (Method method : methods) { + method.setParent(thisDocument); + } + + return thisDocument; } /** @@ -105,20 +119,17 @@ public Schema dereferenceSchema(Schema schema) { return schema; } - private static List parseMethods(DiscoveryNode root, String path) { + private static List parseMethods(DiscoveryNode root) { List methods = new ArrayList<>(); DiscoveryNode methodsNode = root.getObject("methods"); List resourceNames = methodsNode.getFieldNames(); - if (!path.isEmpty()) { - path += "."; - } for (String name : resourceNames) { - methods.add(Method.from(methodsNode.getObject(name), path + "methods." + name)); + methods.add(Method.from(methodsNode.getObject(name), null)); } DiscoveryNode resourcesNode = root.getObject("resources"); resourceNames = resourcesNode.getFieldNames(); for (String name : resourceNames) { - methods.addAll(parseMethods(resourcesNode.getObject(name), path + "resources." + name)); + methods.addAll(parseMethods(resourcesNode.getObject(name))); } return methods; } @@ -127,11 +138,23 @@ private static Map parseSchemas(DiscoveryNode root) { Map schemas = new HashMap<>(); DiscoveryNode schemasNode = root.getObject("schemas"); for (String name : schemasNode.getFieldNames()) { - schemas.put(name, Schema.from(schemasNode.getObject(name), "schemas." + name)); + schemas.put(name, Schema.from(schemasNode.getObject(name), null)); } return schemas; } + /** @return the parent Node that contains this node. */ + @JsonIgnore @Nullable private Node parent; + + public Node parent() { + return parent; + } + + // Package private for use by other Node objects. + void setParent(Node parent) { + this.parent = parent; + } + /** @return the auth instructions URL. */ @JsonProperty("authInstructionsUrl") public abstract String authInstructionsUrl(); @@ -152,6 +175,11 @@ private static Map parseSchemas(DiscoveryNode root) { @JsonProperty("discoveryDocUrl") public abstract String discoveryDocUrl(); + /** @return the ID of the Discovery document for the API. */ + @Override + @JsonProperty("id") + public abstract String id(); + /** @return the list of all methods. */ @JsonProperty("methods") public abstract List methods(); diff --git a/src/main/java/com/google/api/codegen/discovery/Method.java b/src/main/java/com/google/api/codegen/discovery/Method.java index 1168c571a1..d7ddbff1d6 100644 --- a/src/main/java/com/google/api/codegen/discovery/Method.java +++ b/src/main/java/com/google/api/codegen/discovery/Method.java @@ -28,16 +28,15 @@ *

Note that this class is not necessarily a 1-1 mapping of the official specification. */ @AutoValue -public abstract class Method implements Comparable { +public abstract class Method implements Comparable, Node { /** * Returns a method constructed from root. * * @param root the root node to parse. - * @param path the full path to this node (ex: "resources.foo.methods.bar"). * @return a method. */ - public static Method from(DiscoveryNode root, String path) { + public static Method from(DiscoveryNode root, Node parent) { String description = root.getString("description"); String httpMethod = root.getString("httpMethod"); String id = root.getString("id"); @@ -49,7 +48,7 @@ public static Method from(DiscoveryNode root, String path) { DiscoveryNode parametersNode = root.getObject("parameters"); HashMap parameters = new HashMap<>(); for (String name : root.getObject("parameters").getFieldNames()) { - Schema schema = Schema.from(parametersNode.getObject(name), path + ".parameters." + name); + Schema schema = Schema.from(parametersNode.getObject(name), null); // TODO: Remove these checks once we're sure that parameters can't be objects/arrays. // This is based on the assumption that these types can't be serialized as a query or path parameter. Preconditions.checkState(schema.type() != Schema.Type.ANY); @@ -58,11 +57,11 @@ public static Method from(DiscoveryNode root, String path) { parameters.put(name, schema); } - Schema request = Schema.from(root.getObject("request"), path + ".request"); + Schema request = Schema.from(root.getObject("request"), null); if (request.reference().isEmpty()) { request = null; } - Schema response = Schema.from(root.getObject("response"), path + ".response"); + Schema response = Schema.from(root.getObject("response"), null); if (response.reference().isEmpty()) { response = null; } @@ -73,18 +72,30 @@ public static Method from(DiscoveryNode root, String path) { boolean supportsMediaDownload = root.getBoolean("supportsMediaDownload"); boolean supportsMediaUpload = root.getBoolean("supportsMediaUpload"); - return new AutoValue_Method( - description, - httpMethod, - id, - parameterOrder, - parameters, - path, - request, - response, - scopes, - supportsMediaDownload, - supportsMediaUpload); + Method thisMethod = + new AutoValue_Method( + description, + httpMethod, + id, + parameterOrder, + parameters, + request, + response, + scopes, + supportsMediaDownload, + supportsMediaUpload); + + thisMethod.parent = parent; + if (request != null) { + request.setParent(thisMethod); + } + if (response != null) { + response.setParent(thisMethod); + } + for (Schema schema : parameters.values()) { + schema.setParent(thisMethod); + } + return thisMethod; } @Override @@ -92,6 +103,17 @@ public int compareTo(Method other) { return id().compareTo(other.id()); } + /** @return the parent Node. */ + private Node parent; + + void setParent(Node parent) { + this.parent = parent; + } + + public Node parent() { + return parent; + } + /** @return the description. */ public abstract String description(); @@ -107,9 +129,6 @@ public int compareTo(Method other) { /** @return the map of parameter names to schemas. */ public abstract Map parameters(); - /** @return the fully qualified path to this method. */ - public abstract String path(); - /** @return the request schema, or null if none. */ @Nullable public abstract Schema request(); diff --git a/src/main/java/com/google/api/codegen/discovery/Node.java b/src/main/java/com/google/api/codegen/discovery/Node.java new file mode 100644 index 0000000000..53ad496622 --- /dev/null +++ b/src/main/java/com/google/api/codegen/discovery/Node.java @@ -0,0 +1,28 @@ +/* Copyright 2017 Google Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.api.codegen.discovery; + +import javax.annotation.Nullable; + +/** Represents a node in a tree of nodes. */ +public interface Node { + /** @return the ID of this node. */ + @Nullable + String id(); + + /** @return the immediate parent of this node. */ + @Nullable + Node parent(); +} diff --git a/src/main/java/com/google/api/codegen/discovery/Schema.java b/src/main/java/com/google/api/codegen/discovery/Schema.java index 136b325b4c..f19ff89ee5 100644 --- a/src/main/java/com/google/api/codegen/discovery/Schema.java +++ b/src/main/java/com/google/api/codegen/discovery/Schema.java @@ -14,6 +14,7 @@ */ package com.google.api.codegen.discovery; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.auto.value.AutoValue; import java.util.HashMap; import java.util.Map; @@ -25,7 +26,7 @@ *

Note that this class is not necessarily a 1-1 mapping of the official specification. */ @AutoValue -public abstract class Schema { +public abstract class Schema implements Node { /** * Returns true if this schema contains a property with the given name. @@ -41,15 +42,13 @@ public boolean hasProperty(String name) { * Returns a schema constructed from root, or an empty schema if root has no children. * * @param root the root node to parse. - * @param path the full path to this node (ex: "methods.foo.parameters.bar"). * @return a schema. */ - public static Schema from(DiscoveryNode root, String path) { + public static Schema from(DiscoveryNode root, Node parent) { if (root.isEmpty()) { return empty(); } - Schema additionalProperties = - Schema.from(root.getObject("additionalProperties"), path + ".additionalProperties"); + Schema additionalProperties = Schema.from(root.getObject("additionalProperties"), null); if (additionalProperties.type() == Type.EMPTY && additionalProperties.reference().isEmpty()) { additionalProperties = null; } @@ -58,7 +57,7 @@ public static Schema from(DiscoveryNode root, String path) { Format format = Format.getEnum(root.getString("format")); String id = root.getString("id"); boolean isEnum = !root.getArray("enum").isEmpty(); - Schema items = Schema.from(root.getObject("items"), path + ".items"); + Schema items = Schema.from(root.getObject("items"), null); if (items.type() == Type.EMPTY && items.reference().isEmpty()) { items = null; } @@ -68,8 +67,7 @@ public static Schema from(DiscoveryNode root, String path) { Map properties = new HashMap<>(); DiscoveryNode propertiesNode = root.getObject("properties"); for (String name : propertiesNode.getFieldNames()) { - properties.put( - name, Schema.from(propertiesNode.getObject(name), path + ".properties." + name)); + properties.put(name, Schema.from(propertiesNode.getObject(name), null)); } String reference = root.getString("$ref"); @@ -77,22 +75,34 @@ public static Schema from(DiscoveryNode root, String path) { boolean required = root.getBoolean("required"); Type type = Type.getEnum(root.getString("type")); - return new AutoValue_Schema( - additionalProperties, - defaultValue, - description, - format, - id, - isEnum, - items, - location, - path, - pattern, - properties, - reference, - repeated, - required, - type); + Schema thisSchema = + new AutoValue_Schema( + additionalProperties, + defaultValue, + description, + format, + id, + isEnum, + items, + location, + pattern, + properties, + reference, + repeated, + required, + type); + thisSchema.parent = parent; + if (items != null) { + items.setParent(thisSchema); + } + for (Schema schema : properties.values()) { + schema.setParent(thisSchema); + } + if (additionalProperties != null) { + additionalProperties.setParent(thisSchema); + } + + return thisSchema; } public static Schema empty() { @@ -106,7 +116,6 @@ public static Schema empty() { null, "", "", - "", new HashMap(), "", false, @@ -114,6 +123,18 @@ public static Schema empty() { Type.EMPTY); } + @JsonIgnore @Nullable private Node parent; + + /** @return the {@link Node} that contains this Schema. */ + @Nullable + public Node parent() { + return parent; + } + + void setParent(Node parent) { + this.parent = parent; + } + /** @return the schema of the additionalProperties, or null if none. */ @Nullable public abstract Schema additionalProperties(); @@ -142,9 +163,6 @@ public static Schema empty() { /** @return the location. */ public abstract String location(); - /** @return the fully qualified path to this schema. */ - public abstract String path(); - /** @return the pattern. */ public abstract String pattern(); diff --git a/src/test/java/com/google/api/codegen/discovery/DocumentTest.java b/src/test/java/com/google/api/codegen/discovery/DocumentTest.java index 1674e24cb4..837b1363b8 100644 --- a/src/test/java/com/google/api/codegen/discovery/DocumentTest.java +++ b/src/test/java/com/google/api/codegen/discovery/DocumentTest.java @@ -52,21 +52,22 @@ public void testDocumentFromJson() throws IOException { Truth.assertThat(methods.get(0).description()).isEqualTo("Get a baz."); Truth.assertThat(methods.get(0).id()).isEqualTo("myapi.bar.baz.get"); Truth.assertThat(methods.get(0).parameterOrder()).isEqualTo(Collections.singletonList("p1")); - Truth.assertThat(methods.get(0).path()).isEqualTo("resources.bar.methods.baz"); + Truth.assertThat(methods.get(0).parent() instanceof Document); + Truth.assertThat(methods.get(0).parent()).isEqualTo(document); Map parameters = methods.get(0).parameters(); Truth.assertThat(parameters.get("p1").type()).isEqualTo(Schema.Type.BOOLEAN); Truth.assertThat(parameters.get("p1").required()).isTrue(); Truth.assertThat(parameters.get("p1").location()).isEqualTo("query"); - Truth.assertThat(parameters.get("p1").path()) - .isEqualTo("resources.bar.methods.baz.parameters.p1"); + Truth.assertThat(parameters.get("p1").parent() instanceof Method); + Truth.assertThat(parameters.get("p1").parent()).isEqualTo(methods.get(0)); Truth.assertThat(methods.get(1).description()).isEqualTo("Insert a foo."); Truth.assertThat(methods.get(1).id()).isEqualTo("myapi.foo.insert"); Truth.assertThat(methods.get(1).parameters().isEmpty()).isTrue(); Truth.assertThat(methods.get(1).request()).isNull(); Truth.assertThat(methods.get(1).response()).isNull(); - Truth.assertThat(methods.get(1).path()).isEqualTo("methods.foo"); + Truth.assertThat(methods.get(1).id()).isEqualTo("myapi.foo.insert"); Truth.assertThat(document.name()).isEqualTo("myapi"); Truth.assertThat(document.canonicalName()).isEqualTo("My API"); @@ -76,9 +77,10 @@ public void testDocumentFromJson() throws IOException { Map schemas = document.schemas(); Truth.assertThat(schemas.get("GetBazRequest").type()).isEqualTo(Schema.Type.STRING); - Truth.assertThat(schemas.get("GetBazRequest").path()).isEqualTo("schemas.GetBazRequest"); - Truth.assertThat(schemas.get("GetBazRequest").properties().get("foo").path()) - .isEqualTo("schemas.GetBazRequest.properties.foo"); + Truth.assertThat(schemas.get("GetBazRequest").properties().get("foo").parent()) + .isEqualTo(schemas.get("GetBazRequest")); + Truth.assertThat(schemas.get("GetBazRequest").parent() instanceof Document); + Truth.assertThat(schemas.get("GetBazRequest").parent()).isEqualTo(document); Truth.assertThat(schemas.get("Baz").type()).isEqualTo(Schema.Type.STRING); diff --git a/src/test/java/com/google/api/codegen/discovery/MethodTest.java b/src/test/java/com/google/api/codegen/discovery/MethodTest.java index dc74e6b206..837dceb492 100644 --- a/src/test/java/com/google/api/codegen/discovery/MethodTest.java +++ b/src/test/java/com/google/api/codegen/discovery/MethodTest.java @@ -35,7 +35,7 @@ public void testMethodFromJson() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(reader); - Method method = Method.from(new DiscoveryNode(root), "root"); + Method method = Method.from(new DiscoveryNode(root), null); Truth.assertThat(method.description()).isEqualTo("Get a baz!"); Truth.assertThat(method.httpMethod()).isEqualTo("GET"); @@ -46,7 +46,7 @@ public void testMethodFromJson() throws IOException { Truth.assertThat(parameters.get("p1").type()).isEqualTo(Schema.Type.STRING); Truth.assertThat(parameters.get("p1").required()).isTrue(); Truth.assertThat(parameters.get("p1").location()).isEqualTo("path"); - Truth.assertThat(parameters.get("p1").path()).isEqualTo("root.parameters.p1"); + Truth.assertThat(parameters.get("p1").parent().id()).isEqualTo("foo.bar.baz.get"); Truth.assertThat(parameters.get("p2").type()).isEqualTo(Schema.Type.STRING); Truth.assertThat(parameters.get("p2").location()).isEqualTo("query"); @@ -57,8 +57,8 @@ public void testMethodFromJson() throws IOException { Truth.assertThat(method.request().reference()).isEqualTo("GetBazRequest"); Truth.assertThat(method.response().reference()).isEqualTo("Baz"); - Truth.assertThat(method.request().path()).isEqualTo("root.request"); - Truth.assertThat(method.response().path()).isEqualTo("root.response"); + Truth.assertThat(method.request().parent().id()).isEqualTo("foo.bar.baz.get"); + Truth.assertThat(method.response().parent().id()).isEqualTo("foo.bar.baz.get"); Truth.assertThat(method.scopes()) .isEqualTo(Arrays.asList("https://www.example.com/foo", "https://www.example.com/bar")); diff --git a/src/test/java/com/google/api/codegen/discovery/SchemaTest.java b/src/test/java/com/google/api/codegen/discovery/SchemaTest.java index aa22ec5beb..2769840350 100644 --- a/src/test/java/com/google/api/codegen/discovery/SchemaTest.java +++ b/src/test/java/com/google/api/codegen/discovery/SchemaTest.java @@ -34,7 +34,7 @@ public void testSchemaFromJson() throws IOException { ObjectMapper mapper = new ObjectMapper(); JsonNode root = mapper.readTree(reader); - Schema schema = Schema.from(new DiscoveryNode(root), "root"); + Schema schema = Schema.from(new DiscoveryNode(root), null); Truth.assertThat(schema.description()).isEqualTo("My Foo."); Truth.assertThat(schema.id()).isEqualTo("Foo"); @@ -95,16 +95,18 @@ public void testSchemaFromJson() throws IOException { Truth.assertThat(properties.get("uint64").format()).isEqualTo(Schema.Format.UINT64); // Test path. - Truth.assertThat(schema.path()).isEqualTo("root"); - Truth.assertThat(schema.properties().get("array").path()).isEqualTo("root.properties.array"); - Truth.assertThat(schema.properties().get("array").items().path()) - .isEqualTo("root.properties.array.items"); - Truth.assertThat(schema.properties().get("object").additionalProperties().path()) - .isEqualTo("root.properties.object.additionalProperties"); + Truth.assertThat(schema.id()).isEqualTo("Foo"); + Truth.assertThat(schema.properties().get("array").parent()).isEqualTo(schema); + Truth.assertThat(schema.properties().get("array").items().parent()) + .isEqualTo(schema.properties().get("array")); + + Truth.assertThat(schema.properties().get("object").additionalProperties().parent()) + .isEqualTo(schema.properties().get("object")); } @Test public void testSchemaFromEmptyNode() { - Truth.assertThat(Schema.from(new DiscoveryNode(null), "").type()).isEqualTo(Schema.Type.EMPTY); + Truth.assertThat(Schema.from(new DiscoveryNode(null), null).type()) + .isEqualTo(Schema.Type.EMPTY); } } diff --git a/src/test/java/com/google/api/codegen/discoverytestdata/document_.json b/src/test/java/com/google/api/codegen/discoverytestdata/document_.json index 8abbfd38cb..293367a7e6 100644 --- a/src/test/java/com/google/api/codegen/discoverytestdata/document_.json +++ b/src/test/java/com/google/api/codegen/discoverytestdata/document_.json @@ -1,4 +1,5 @@ { + "id": "discovery#document", "auth": { "oauth2": { "scopes": {