From ac9d1e4ca0c0c8c128dfb9937d2f77855437b857 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 29 May 2019 09:57:21 -0600 Subject: [PATCH] GraphQL library upgrade changes. (#1508) * GraphQL library upgrade changes. one more NPE path for GraphQL sniffed out. With more tests. Signed-off-by: Adrian Sutton --- .../ethereum/graphql/GraphQLHttpService.java | 15 +++-- .../AbstractEthGraphQLHttpServiceTest.java | 1 + .../graphql/EthGraphQLHttpBySpecTest.java | 2 +- .../GraphQLHttpServiceHostWhitelistTest.java | 4 +- .../graphql/GraphQLHttpServiceTest.java | 65 ++++++++++++++++--- 5 files changed, 70 insertions(+), 17 deletions(-) diff --git a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpService.java b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpService.java index 667a1c2b4c..bae9f088a6 100644 --- a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpService.java +++ b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpService.java @@ -37,6 +37,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; +import com.google.common.net.MediaType; import graphql.ExecutionInput; import graphql.ExecutionResult; import graphql.GraphQL; @@ -65,6 +66,7 @@ public class GraphQLHttpService { private static final InetSocketAddress EMPTY_SOCKET_ADDRESS = new InetSocketAddress("0.0.0.0", 0); private static final String APPLICATION_JSON = "application/json"; + private static final MediaType MEDIA_TYPE_JUST_JSON = MediaType.JSON_UTF_8.withoutParameters(); private static final String EMPTY_RESPONSE = ""; private static final TypeReference> MAP_TYPE = @@ -263,14 +265,19 @@ public class GraphQLHttpService { } break; case POST: - if (request.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(APPLICATION_JSON)) { - + final String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE); + if (contentType != null && MediaType.parse(contentType).is(MEDIA_TYPE_JUST_JSON)) { final String requestBody = routingContext.getBodyAsString().trim(); final GraphQLJsonRequest jsonRequest = Json.decodeValue(requestBody, GraphQLJsonRequest.class); query = jsonRequest.getQuery(); operationName = jsonRequest.getOperationName(); - variables = jsonRequest.getVariables(); + Map jsonVariables = jsonRequest.getVariables(); + if (jsonVariables != null) { + variables = jsonVariables; + } else { + variables = Collections.emptyMap(); + } } else { // treat all else as application/graphql query = routingContext.getBodyAsString().trim(); @@ -298,7 +305,7 @@ public class GraphQLHttpService { }, false, (res) -> { - response.putHeader("Content-Type", APPLICATION_JSON); + response.putHeader("Content-Type", MediaType.JSON_UTF_8.toString()); if (res.failed()) { response.setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()); response.end( diff --git a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java index 3b780f21bb..11e95c441c 100644 --- a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -85,6 +85,7 @@ public abstract class AbstractEthGraphQLHttpServiceTest { String baseUrl; final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8"); private MutableBlockchain blockchain; diff --git a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/EthGraphQLHttpBySpecTest.java b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/EthGraphQLHttpBySpecTest.java index 9131b55437..210c4c812e 100644 --- a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/EthGraphQLHttpBySpecTest.java +++ b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/EthGraphQLHttpBySpecTest.java @@ -116,7 +116,7 @@ public class EthGraphQLHttpBySpecTest extends AbstractEthGraphQLHttpServiceTest EthGraphQLHttpBySpecTest.class.getResource(testSpecFile), Charsets.UTF_8); final JsonObject spec = new JsonObject(json); final String rawRequestBody = spec.getString("request"); - final RequestBody requestBody = RequestBody.create(JSON, rawRequestBody); + final RequestBody requestBody = RequestBody.create(GRAPHQL, rawRequestBody); final Request request = new Request.Builder().post(requestBody).url(baseUrl).build(); importBlocks(1, BLOCKS.size()); diff --git a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceHostWhitelistTest.java b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceHostWhitelistTest.java index 56699e93e2..89459178d2 100644 --- a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceHostWhitelistTest.java +++ b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceHostWhitelistTest.java @@ -51,7 +51,7 @@ public class GraphQLHttpServiceHostWhitelistTest { private static GraphQLHttpService service; private static OkHttpClient client; private static String baseUrl; - private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8"); private final GraphQLConfiguration graphQLConfig = createGraphQLConfig(); private final List hostsWhitelist = Arrays.asList("ally", "friend"); @@ -135,7 +135,7 @@ public class GraphQLHttpServiceHostWhitelistTest { } private int doRequest(final String hostname) throws IOException { - final RequestBody body = RequestBody.create(JSON, "{protocolVersion}"); + final RequestBody body = RequestBody.create(GRAPHQL, "{protocolVersion}"); final Request build = new Request.Builder() diff --git a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceTest.java b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceTest.java index 9d4ef41d08..da59acd25a 100644 --- a/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceTest.java +++ b/ethereum/graphql/src/test/java/tech/pegasys/pantheon/ethereum/graphql/GraphQLHttpServiceTest.java @@ -61,6 +61,7 @@ public class GraphQLHttpServiceTest { private static OkHttpClient client; private static String baseUrl; protected static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + protected static final MediaType GRAPHQL = MediaType.parse("application/graphql; charset=utf-8"); private static BlockchainQuery blockchainQueries; private static Synchronizer synchronizer; private static GraphQL graphQL; @@ -165,18 +166,62 @@ public class GraphQLHttpServiceTest { @Test public void handleInvalidQuerySchema() throws Exception { - final RequestBody body = RequestBody.create(JSON, "{gasPrice1}"); + final RequestBody body = RequestBody.create(GRAPHQL, "{gasPrice1}"); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { - // assertThat(resp.code()).isEqualTo(200); // Check general format of result final JsonObject json = new JsonObject(resp.body().string()); - testHelper.assertValidGraphQLError(json); // Check result final + testHelper.assertValidGraphQLError(json); + assertThat(resp.code()).isEqualTo(400); } } @Test - public void getGasprice() throws Exception { - final RequestBody body = RequestBody.create(JSON, "{gasPrice}"); + public void query_get() throws Exception { + final Wei price = Wei.of(16); + when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(price); + + try (final Response resp = client.newCall(buildGetRequest("?query={gasPrice}")).execute()) { + assertThat(resp.code()).isEqualTo(200); + final JsonObject json = new JsonObject(resp.body().string()); + testHelper.assertValidGraphQLResult(json); + final String result = json.getJsonObject("data").getString("gasPrice"); + assertThat(result).isEqualTo("0x10"); + } + } + + @Test + public void query_jsonPost() throws Exception { + final RequestBody body = RequestBody.create(JSON, "{\"query\":\"{gasPrice}\"}"); + final Wei price = Wei.of(16); + when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(price); + + try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { + assertThat(resp.code()).isEqualTo(200); // Check general format of result + final JsonObject json = new JsonObject(resp.body().string()); + testHelper.assertValidGraphQLResult(json); + final String result = json.getJsonObject("data").getString("gasPrice"); + assertThat(result).isEqualTo("0x10"); + } + } + + @Test + public void query_graphqlPost() throws Exception { + final RequestBody body = RequestBody.create(GRAPHQL, "{gasPrice}"); + final Wei price = Wei.of(16); + when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(price); + + try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { + assertThat(resp.code()).isEqualTo(200); // Check general format of result + final JsonObject json = new JsonObject(resp.body().string()); + testHelper.assertValidGraphQLResult(json); + final String result = json.getJsonObject("data").getString("gasPrice"); + assertThat(result).isEqualTo("0x10"); + } + } + + @Test + public void query_untypedPost() throws Exception { + final RequestBody body = RequestBody.create(null, "{gasPrice}"); final Wei price = Wei.of(16); when(miningCoordinatorMock.getMinTransactionGasPrice()).thenReturn(price); @@ -226,10 +271,10 @@ public class GraphQLHttpServiceTest { @Test public void responseContainsJsonContentTypeHeader() throws Exception { - final RequestBody body = RequestBody.create(JSON, "{gasPrice}"); + final RequestBody body = RequestBody.create(GRAPHQL, "{gasPrice}"); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { - assertThat(resp.header("Content-Type")).isEqualTo("application/json"); + assertThat(resp.header("Content-Type")).isEqualTo(JSON.toString()); } } @@ -248,7 +293,7 @@ public class GraphQLHttpServiceTest { final String query = "{block(hash:\"" + blockHash.toString() + "\") {ommerCount}}"; - final RequestBody body = RequestBody.create(JSON, query); + final RequestBody body = RequestBody.create(GRAPHQL, query); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final String jsonStr = resp.body().string(); @@ -272,7 +317,7 @@ public class GraphQLHttpServiceTest { final String query = "{block(number:\"3\") {ommerCount}}"; - final RequestBody body = RequestBody.create(JSON, query); + final RequestBody body = RequestBody.create(GRAPHQL, query); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final String jsonStr = resp.body().string(); @@ -296,7 +341,7 @@ public class GraphQLHttpServiceTest { final String query = "{block {ommerCount}}"; - final RequestBody body = RequestBody.create(JSON, query); + final RequestBody body = RequestBody.create(GRAPHQL, query); try (final Response resp = client.newCall(buildPostRequest(body)).execute()) { assertThat(resp.code()).isEqualTo(200); final String jsonStr = resp.body().string();