From 1d0b85a6f678556bd60a3de4147db57a68801697 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Wed, 10 Jul 2019 16:02:33 +0300 Subject: [PATCH 1/8] [ECR-3223] LC: port is optional; Added functional for specifying prefix url --- .../java/com/exonum/client/ExonumClient.java | 13 +++- .../com/exonum/client/ExonumHttpClient.java | 50 +++++-------- .../java/com/exonum/client/HttpUrlHelper.java | 65 +++++++++++++++++ .../com/exonum/client/HttpUrlHelperTest.java | 70 +++++++++++++++++++ 4 files changed, 166 insertions(+), 32 deletions(-) create mode 100644 exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java create mode 100644 exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java diff --git a/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java b/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java index 6a7f382741..17d1dfd3a5 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java +++ b/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java @@ -18,6 +18,7 @@ package com.exonum.client; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; import com.exonum.binding.common.hash.HashCode; import com.exonum.binding.common.message.TransactionMessage; @@ -176,6 +177,7 @@ class Builder { private URL exonumHost; private OkHttpClient httpClient = DEFAULT_CLIENT; + private String prefix = ""; /** * Sets Exonum host url. @@ -210,13 +212,22 @@ public Builder setHttpClient(OkHttpClient client) { return this; } + /** + * Optionally, sets prefix url to be applied to all requests made by the client. + * Can be helpful in case of using middleware routing proxy on the blockchain node side. + */ + public Builder setPrefix(String prefix) { + this.prefix = requireNonNull(prefix); + return this; + } + /** * Creates Exonum client instance. * @throws IllegalStateException if required fields weren't set */ public ExonumClient build() { checkRequiredFieldsSet(); - return new ExonumHttpClient(httpClient, exonumHost); + return new ExonumHttpClient(httpClient, exonumHost, prefix); } private void checkRequiredFieldsSet() { diff --git a/exonum-light-client/src/main/java/com/exonum/client/ExonumHttpClient.java b/exonum-light-client/src/main/java/com/exonum/client/ExonumHttpClient.java index e59d59ad4c..5fa6179a15 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/ExonumHttpClient.java +++ b/exonum-light-client/src/main/java/com/exonum/client/ExonumHttpClient.java @@ -18,12 +18,12 @@ package com.exonum.client; import static com.exonum.client.ExonumApi.MAX_BLOCKS_PER_REQUEST; -import static com.exonum.client.ExonumUrls.BLOCK; import static com.exonum.client.ExonumUrls.BLOCKS; import static com.exonum.client.ExonumUrls.HEALTH_CHECK; import static com.exonum.client.ExonumUrls.MEMORY_POOL; import static com.exonum.client.ExonumUrls.TRANSACTIONS; import static com.exonum.client.ExonumUrls.USER_AGENT; +import static com.exonum.client.HttpUrlHelper.getFullUrl; import static com.exonum.client.request.BlockFilteringOption.INCLUDE_EMPTY; import static com.exonum.client.request.BlockFilteringOption.SKIP_EMPTY; import static com.exonum.client.request.BlockTimeOption.INCLUDE_COMMIT_TIME; @@ -31,6 +31,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static java.util.Collections.emptyMap; import com.exonum.binding.common.hash.HashCode; import com.exonum.binding.common.message.TransactionMessage; @@ -41,6 +42,7 @@ import com.exonum.client.response.BlocksResponse; import com.exonum.client.response.HealthCheckInfo; import com.exonum.client.response.TransactionResponse; +import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.net.URL; import java.util.HashMap; @@ -63,15 +65,17 @@ class ExonumHttpClient implements ExonumClient { private final OkHttpClient httpClient; private final URL exonumHost; + private final String prefix; - ExonumHttpClient(OkHttpClient httpClient, URL exonumHost) { + ExonumHttpClient(OkHttpClient httpClient, URL exonumHost, String prefix) { this.httpClient = httpClient; this.exonumHost = exonumHost; + this.prefix = prefix; } @Override public HashCode submitTransaction(TransactionMessage transactionMessage) { - Request request = post(toFullUrl(TRANSACTIONS), + Request request = post(url(TRANSACTIONS), ExplorerApiHelper.createSubmitTxBody(transactionMessage)); return blockingExecuteAndParse(request, ExplorerApiHelper::parseSubmitTxResponse); @@ -79,21 +83,21 @@ public HashCode submitTransaction(TransactionMessage transactionMessage) { @Override public int getUnconfirmedTransactionsCount() { - Request request = get(toFullUrl(MEMORY_POOL)); + Request request = get(url(MEMORY_POOL)); return blockingExecuteAndParse(request, SystemApiHelper::parseMemoryPoolJson); } @Override public HealthCheckInfo healthCheck() { - Request request = get(toFullUrl(HEALTH_CHECK)); + Request request = get(url(HEALTH_CHECK)); return blockingExecuteAndParse(request, SystemApiHelper::parseHealthCheckJson); } @Override public String getUserAgentInfo() { - Request request = get(toFullUrl(USER_AGENT)); + Request request = get(url(USER_AGENT)); return blockingExecutePlainText(request); } @@ -101,11 +105,8 @@ public String getUserAgentInfo() { @Override public Optional getTransaction(HashCode id) { HashCode hash = checkNotNull(id); - HttpUrl url = urlBuilder() - .encodedPath(TRANSACTIONS) - .addQueryParameter("hash", hash.toString()) - .build(); - Request request = get(url); + Map query = ImmutableMap.of("hash", hash.toString()); + Request request = get(url(TRANSACTIONS, query)); return blockingExecute(request, response -> { if (response.code() == HTTP_NOT_FOUND) { @@ -131,11 +132,8 @@ public long getBlockchainHeight() { @Override public BlockResponse getBlockByHeight(long height) { checkArgument(0 <= height, "Height can't be negative, but was %s", height); - HttpUrl url = urlBuilder() - .encodedPath(BLOCK) - .addQueryParameter("height", String.valueOf(height)) - .build(); - Request request = get(url); + Map query = ImmutableMap.of("height", String.valueOf(height)); + Request request = get(url(BLOCKS, query)); return blockingExecuteAndParse(request, ExplorerApiHelper::parseGetBlockResponse); } @@ -192,11 +190,7 @@ private BlocksResponse doGetBlocks(int count, BlockFilteringOption blockFilter, if (heightMax != null) { query.put("latest", String.valueOf(heightMax)); } - - HttpUrl.Builder httpRequest = urlBuilder().encodedPath(BLOCKS); - query.forEach(httpRequest::addQueryParameter); - - Request request = get(httpRequest.build()); + Request request = get(url(BLOCKS, query)); return blockingExecuteAndParse(request, ExplorerApiHelper::parseGetBlocksResponse); } @@ -215,18 +209,12 @@ private static Request post(HttpUrl url, String jsonBody) { .build(); } - private HttpUrl toFullUrl(String relativeUrl) { - return urlBuilder() - .encodedPath(relativeUrl) - .build(); + private HttpUrl url(String path, Map query) { + return getFullUrl(exonumHost, prefix, path, query); } - private HttpUrl.Builder urlBuilder() { - - return new HttpUrl.Builder() - .scheme(exonumHost.getProtocol()) - .host(exonumHost.getHost()) - .port(exonumHost.getPort()); + private HttpUrl url(String path) { + return url(path, emptyMap()); } private T blockingExecute(Request request, Function responseHandler) { diff --git a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java new file mode 100644 index 0000000000..32035a8c98 --- /dev/null +++ b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019 The Exonum Team + * + * 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.exonum.client; + +import static java.util.Objects.requireNonNull; + +import java.net.URL; +import java.util.Map; +import okhttp3.HttpUrl; +import okhttp3.HttpUrl.Builder; + +final class HttpUrlHelper { + + static HttpUrl getFullUrl(URL host, String prefix, String relativeUrl, + Map query) { + requireNonNull(query); + Builder builder = urlHostBuilder(host) + .addPathSegments(normalize(prefix)) + .addPathSegments(normalize(relativeUrl)); + query.forEach(builder::addEncodedQueryParameter); + + return builder.build(); + } + + private static HttpUrl.Builder urlHostBuilder(URL host) { + requireNonNull(host); + HttpUrl.Builder builder = new HttpUrl.Builder() + .scheme(host.getProtocol()) + .host(host.getHost()); + if (host.getPort() != -1) { + builder.port(host.getPort()); + } + return builder; + } + + /** + * Removes heading slash from the path. + * Useful because underlying OkHttp applies slashes when constructing paths. + */ + private static String normalize(String path) { + requireNonNull(path); + if (path.startsWith("/")) { + return path.substring(1); + } else { + return path; + } + } + + private HttpUrlHelper() { + } +} diff --git a/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java new file mode 100644 index 0000000000..70601397d8 --- /dev/null +++ b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 The Exonum Team + * + * 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.exonum.client; + +import static java.util.Collections.emptyMap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.params.provider.Arguments.of; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Map; +import okhttp3.HttpUrl; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class HttpUrlHelperTest { + + @ParameterizedTest + @MethodSource("source") + void getFullUrl(String expectedUrl, + String host, String prefix, String path, Map query) + throws MalformedURLException { + HttpUrl url = HttpUrlHelper.getFullUrl(new URL(host), prefix, path, query); + + assertThat(url.toString(), is(expectedUrl)); + } + + /** + * Provides a combination of parameters by the following rules: + * - port is optional + * - prefix is optional + * - paths can start either with or without heading slash + * - query params is optional. + */ + private static List source() { + Map noQuery = emptyMap(); + return ImmutableList.of( + of("http://localhost/path/to/source", + "http://localhost", "", "/path/to/source", noQuery), + of("http://localhost/prefix/path/to/source", + "http://localhost", "prefix", "path/to/source", noQuery), + of("http://localhost:8080/prefix/path/to/source", + "http://localhost:8080", "/prefix", "/path/to/source", noQuery), + of("http://localhost:8080/pre/fix/path/to/source", + "http://localhost:8080", "/pre/fix", "/path/to/source", noQuery), + of("http://localhost:8080/pre/fix/path/to/source?key=value", + "http://localhost:8080", "/pre/fix", "/path/to/source", ImmutableMap.of("key", "value")) + ); + } + +} From b024ff4a0d5741914c36c94f4a4237bdd2e30607 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Thu, 11 Jul 2019 13:43:38 +0300 Subject: [PATCH 2/8] fix PR comments --- .../java/com/exonum/client/ExonumClient.java | 6 ++-- .../java/com/exonum/client/HttpUrlHelper.java | 36 +++++++++---------- .../com/exonum/client/HttpUrlHelperTest.java | 17 ++++----- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java b/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java index 17d1dfd3a5..c62988460d 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java +++ b/exonum-light-client/src/main/java/com/exonum/client/ExonumClient.java @@ -18,7 +18,6 @@ package com.exonum.client; import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Objects.requireNonNull; import com.exonum.binding.common.hash.HashCode; import com.exonum.binding.common.message.TransactionMessage; @@ -213,11 +212,12 @@ public Builder setHttpClient(OkHttpClient client) { } /** - * Optionally, sets prefix url to be applied to all requests made by the client. + * Sets an optional URL prefix to be applied to all requests made by the client. * Can be helpful in case of using middleware routing proxy on the blockchain node side. + * There is no prefix by default. */ public Builder setPrefix(String prefix) { - this.prefix = requireNonNull(prefix); + this.prefix = checkNotNull(prefix); return this; } diff --git a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java index 32035a8c98..f1cefee186 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java +++ b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java @@ -16,8 +16,9 @@ package com.exonum.client; -import static java.util.Objects.requireNonNull; +import static com.google.common.base.Preconditions.checkNotNull; +import java.net.URI; import java.net.URL; import java.util.Map; import okhttp3.HttpUrl; @@ -26,18 +27,18 @@ final class HttpUrlHelper { static HttpUrl getFullUrl(URL host, String prefix, String relativeUrl, - Map query) { - requireNonNull(query); - Builder builder = urlHostBuilder(host) - .addPathSegments(normalize(prefix)) - .addPathSegments(normalize(relativeUrl)); - query.forEach(builder::addEncodedQueryParameter); - - return builder.build(); + Map encodedQueryParameters) { + checkNotNull(encodedQueryParameters); + Builder urlBuilder = urlHostBuilder(host) + .addPathSegments(prefix) + .addPathSegments(relativeUrl); + encodedQueryParameters.forEach(urlBuilder::addEncodedQueryParameter); + + return normalize(urlBuilder.build()); } private static HttpUrl.Builder urlHostBuilder(URL host) { - requireNonNull(host); + checkNotNull(host); HttpUrl.Builder builder = new HttpUrl.Builder() .scheme(host.getProtocol()) .host(host.getHost()); @@ -48,16 +49,13 @@ private static HttpUrl.Builder urlHostBuilder(URL host) { } /** - * Removes heading slash from the path. - * Useful because underlying OkHttp applies slashes when constructing paths. + * Normalized the given URL to the canonical form. + * Doesn't modify letters case in the URL. + * Also see {@link URI#normalize()}. */ - private static String normalize(String path) { - requireNonNull(path); - if (path.startsWith("/")) { - return path.substring(1); - } else { - return path; - } + private static HttpUrl normalize(HttpUrl url) { + URI normalized = url.uri().normalize(); + return HttpUrl.get(normalized); } private HttpUrlHelper() { diff --git a/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java index 70601397d8..ba3afeb7ae 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java +++ b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java @@ -19,7 +19,7 @@ import static java.util.Collections.emptyMap; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.params.provider.Arguments.of; +import static org.junit.jupiter.params.provider.Arguments.arguments; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -49,22 +49,23 @@ void getFullUrl(String expectedUrl, * - port is optional * - prefix is optional * - paths can start either with or without heading slash - * - query params is optional. + * - query params are optional. */ private static List source() { Map noQuery = emptyMap(); return ImmutableList.of( - of("http://localhost/path/to/source", + arguments("http://localhost/path/to/source", "http://localhost", "", "/path/to/source", noQuery), - of("http://localhost/prefix/path/to/source", + arguments("http://localhost/prefix/path/to/source", "http://localhost", "prefix", "path/to/source", noQuery), - of("http://localhost:8080/prefix/path/to/source", + arguments("http://localhost/pre%20fix/path/to/source", + "http://localhost", "pre fix", "path/to/source", noQuery), + arguments("http://localhost:8080/prefix/path/to/source", "http://localhost:8080", "/prefix", "/path/to/source", noQuery), - of("http://localhost:8080/pre/fix/path/to/source", + arguments("http://localhost:8080/pre/fix/path/to/source", "http://localhost:8080", "/pre/fix", "/path/to/source", noQuery), - of("http://localhost:8080/pre/fix/path/to/source?key=value", + arguments("http://localhost:8080/pre/fix/path/to/source?key=value", "http://localhost:8080", "/pre/fix", "/path/to/source", ImmutableMap.of("key", "value")) ); } - } From 0f5fe279865e7374b834cb227be3ec780a11b240 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Thu, 11 Jul 2019 16:23:33 +0300 Subject: [PATCH 3/8] remove normalization --- .../main/java/com/exonum/client/HttpUrlHelper.java | 12 +----------- .../java/com/exonum/client/HttpUrlHelperTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java index f1cefee186..e4b250cae7 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java +++ b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java @@ -34,7 +34,7 @@ static HttpUrl getFullUrl(URL host, String prefix, String relativeUrl, .addPathSegments(relativeUrl); encodedQueryParameters.forEach(urlBuilder::addEncodedQueryParameter); - return normalize(urlBuilder.build()); + return urlBuilder.build(); } private static HttpUrl.Builder urlHostBuilder(URL host) { @@ -48,16 +48,6 @@ private static HttpUrl.Builder urlHostBuilder(URL host) { return builder; } - /** - * Normalized the given URL to the canonical form. - * Doesn't modify letters case in the URL. - * Also see {@link URI#normalize()}. - */ - private static HttpUrl normalize(HttpUrl url) { - URI normalized = url.uri().normalize(); - return HttpUrl.get(normalized); - } - private HttpUrlHelper() { } } diff --git a/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java index ba3afeb7ae..8622468a90 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java +++ b/exonum-light-client/src/test/java/com/exonum/client/HttpUrlHelperTest.java @@ -54,17 +54,17 @@ void getFullUrl(String expectedUrl, private static List source() { Map noQuery = emptyMap(); return ImmutableList.of( - arguments("http://localhost/path/to/source", + arguments("http://localhost//path/to/source", "http://localhost", "", "/path/to/source", noQuery), arguments("http://localhost/prefix/path/to/source", "http://localhost", "prefix", "path/to/source", noQuery), arguments("http://localhost/pre%20fix/path/to/source", "http://localhost", "pre fix", "path/to/source", noQuery), - arguments("http://localhost:8080/prefix/path/to/source", + arguments("http://localhost:8080//prefix//path/to/source", "http://localhost:8080", "/prefix", "/path/to/source", noQuery), - arguments("http://localhost:8080/pre/fix/path/to/source", + arguments("http://localhost:8080//pre/fix//path/to/source", "http://localhost:8080", "/pre/fix", "/path/to/source", noQuery), - arguments("http://localhost:8080/pre/fix/path/to/source?key=value", + arguments("http://localhost:8080//pre/fix//path/to/source?key=value", "http://localhost:8080", "/pre/fix", "/path/to/source", ImmutableMap.of("key", "value")) ); } From 1205b58d3a351bd974debf6b65b4abaac19b2513 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Thu, 11 Jul 2019 20:13:07 +0300 Subject: [PATCH 4/8] added changelog fixed build --- exonum-light-client/CHANGELOG.md | 6 ++++++ .../src/main/java/com/exonum/client/HttpUrlHelper.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/exonum-light-client/CHANGELOG.md b/exonum-light-client/CHANGELOG.md index 94f280601e..c98b59fad7 100644 --- a/exonum-light-client/CHANGELOG.md +++ b/exonum-light-client/CHANGELOG.md @@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased +### Added +- Prefix URL can be set for routing all Light Client requests. (#997) + +### Fixed +- Now port is optional in the Exonum host URL. (#997) + ## 0.2.0 - 2019-05-27 Second release of Exonum Java Light Client which brings diff --git a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java index e4b250cae7..1e2d710af4 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java +++ b/exonum-light-client/src/main/java/com/exonum/client/HttpUrlHelper.java @@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkNotNull; -import java.net.URI; import java.net.URL; import java.util.Map; import okhttp3.HttpUrl; From 768e99809730161b7f247f5df1810f638c350212 Mon Sep 17 00:00:00 2001 From: Dmitry Timofeev Date: Thu, 11 Jul 2019 20:23:47 +0300 Subject: [PATCH 5/8] s/Fixed/Changed/ --- exonum-light-client/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exonum-light-client/CHANGELOG.md b/exonum-light-client/CHANGELOG.md index c98b59fad7..c75cb83be4 100644 --- a/exonum-light-client/CHANGELOG.md +++ b/exonum-light-client/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Prefix URL can be set for routing all Light Client requests. (#997) -### Fixed +### Changed - Now port is optional in the Exonum host URL. (#997) ## 0.2.0 - 2019-05-27 From 2084a04488ebee1f97611ba0961047bf6dc2f494 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Fri, 12 Jul 2019 10:09:13 +0300 Subject: [PATCH 6/8] Modified paths to avoid double slashes --- .../java/com/exonum/client/ExonumUrls.java | 4 ++-- ...ExonumHttpClientBlocksIntegrationTest.java | 22 +++++++++---------- .../ExonumHttpClientIntegrationTest.java | 15 +++++++------ .../java/com/exonum/client/TestUtils.java | 12 ++++++++++ 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/exonum-light-client/src/main/java/com/exonum/client/ExonumUrls.java b/exonum-light-client/src/main/java/com/exonum/client/ExonumUrls.java index 2a76e683f1..3f3df57ec7 100644 --- a/exonum-light-client/src/main/java/com/exonum/client/ExonumUrls.java +++ b/exonum-light-client/src/main/java/com/exonum/client/ExonumUrls.java @@ -21,8 +21,8 @@ * Contains Exonum API URLs. */ final class ExonumUrls { - private static final String EXPLORER_PATHS_PREFIX = "/api/explorer/v1"; - private static final String SYS_PATHS_PREFIX = "/api/system/v1"; + private static final String EXPLORER_PATHS_PREFIX = "api/explorer/v1"; + private static final String SYS_PATHS_PREFIX = "api/system/v1"; static final String TRANSACTIONS = EXPLORER_PATHS_PREFIX + "/transactions"; static final String BLOCK = EXPLORER_PATHS_PREFIX + "/block"; static final String BLOCKS = EXPLORER_PATHS_PREFIX + "/blocks"; diff --git a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientBlocksIntegrationTest.java b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientBlocksIntegrationTest.java index 5939c70b8a..ad44148b65 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientBlocksIntegrationTest.java +++ b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientBlocksIntegrationTest.java @@ -33,6 +33,7 @@ import static com.exonum.client.ExonumApi.MAX_BLOCKS_PER_REQUEST; import static com.exonum.client.ExonumUrls.BLOCK; import static com.exonum.client.ExonumUrls.BLOCKS; +import static com.exonum.client.TestUtils.assertPath; import static com.exonum.client.request.BlockFilteringOption.INCLUDE_EMPTY; import static com.exonum.client.request.BlockFilteringOption.SKIP_EMPTY; import static com.exonum.client.request.BlockTimeOption.INCLUDE_COMMIT_TIME; @@ -50,7 +51,6 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -123,7 +123,7 @@ void getBlockByHeight() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCK)); + assertPath(recordedRequest, BLOCK); assertThat(recordedRequest.getRequestUrl().queryParameter("height"), is(String.valueOf(height))); } @@ -160,7 +160,7 @@ void getBlocksSinglePageSkippingEmpty() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); int expectedNumBlocks = Math.toIntExact(toHeight - fromHeight + 1); assertBlockRequestParams(recordedRequest, expectedNumBlocks, blockFilter, toHeight, timeOption); } @@ -197,7 +197,7 @@ void getBlocksSinglePageSkippingEmptyFiltersOutOfRangeBlocks() throws Interrupte // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); int expectedNumBlocks = Math.toIntExact(toHeight - fromHeight + 1); assertBlockRequestParams(recordedRequest, expectedNumBlocks, blockFilter, toHeight, timeOption); } @@ -228,7 +228,7 @@ void getBlocksSinglePageNoTime() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); int expectedNumBlocks = Math.toIntExact(toHeight - fromHeight + 1); assertBlockRequestParams(recordedRequest, expectedNumBlocks, blockFilter, toHeight, timeOption); } @@ -400,7 +400,7 @@ void getLastBlocksSkippingEmptySinglePage() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); assertBlockRequestParams(recordedRequest, numBlocks, blockFilter, null, timeOption); } @@ -437,7 +437,7 @@ void getLastBlocksSkippingEmptyMoreThanCommitted(int overflow) // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); int expectedFirstRequestSize = min(blocksCount, MAX_BLOCKS_PER_REQUEST); assertBlockRequestParams(recordedRequest, expectedFirstRequestSize, blockFilter, null, timeOption); @@ -659,7 +659,7 @@ void getLastBlock() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); assertBlockRequestParams(recordedRequest, 1, INCLUDE_EMPTY, null, INCLUDE_COMMIT_TIME); } @@ -685,7 +685,7 @@ void getLastNotEmptyBlock() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); assertBlockRequestParams(recordedRequest, 1, SKIP_EMPTY, null, INCLUDE_COMMIT_TIME); } @@ -710,7 +710,7 @@ void getLastNotEmptyBlockNoBlock() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); assertBlockRequestParams(recordedRequest, 1, SKIP_EMPTY, null, INCLUDE_COMMIT_TIME); } @@ -738,7 +738,7 @@ void getBlockchainHeight() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(BLOCKS)); + assertPath(recordedRequest, BLOCKS); assertBlockRequestParams(recordedRequest, 0, INCLUDE_EMPTY, null, NO_COMMIT_TIME); } diff --git a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientIntegrationTest.java b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientIntegrationTest.java index 134f827325..c9d2e57a94 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientIntegrationTest.java +++ b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientIntegrationTest.java @@ -23,12 +23,13 @@ import static com.exonum.client.ExonumUrls.MEMORY_POOL; import static com.exonum.client.ExonumUrls.TRANSACTIONS; import static com.exonum.client.ExonumUrls.USER_AGENT; +import static com.exonum.client.TestUtils.assertExactPath; +import static com.exonum.client.TestUtils.assertPath; import static com.exonum.client.TestUtils.createTransactionMessage; import static com.exonum.client.TestUtils.toHex; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -91,7 +92,7 @@ void submitTransactionTest() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("POST")); - assertThat(recordedRequest.getPath(), is(TRANSACTIONS)); + assertExactPath(recordedRequest, TRANSACTIONS); // Assert request encoding String json = recordedRequest.getBody().readUtf8(); @@ -117,7 +118,7 @@ void getUnconfirmedTransactions() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), is(MEMORY_POOL)); + assertExactPath(recordedRequest, MEMORY_POOL); } @Test @@ -136,7 +137,7 @@ void healthCheck() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), is(HEALTH_CHECK)); + assertExactPath(recordedRequest, HEALTH_CHECK); } @Test @@ -154,7 +155,7 @@ void getUserAgentInfo() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), is(USER_AGENT)); + assertExactPath(recordedRequest, USER_AGENT); } @Test @@ -189,7 +190,7 @@ void getTransaction() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(TRANSACTIONS)); + assertPath(recordedRequest, TRANSACTIONS); assertThat(recordedRequest.getRequestUrl().queryParameter("hash"), is(id.toString())); } @@ -208,7 +209,7 @@ void getTransactionNotFound() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); assertThat(recordedRequest.getMethod(), is("GET")); - assertThat(recordedRequest.getPath(), startsWith(TRANSACTIONS)); + assertPath(recordedRequest, TRANSACTIONS); assertThat(recordedRequest.getRequestUrl().queryParameter("hash"), is(id.toString())); } diff --git a/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java b/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java index 431802d7f3..dd819c6099 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java +++ b/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java @@ -17,9 +17,13 @@ package com.exonum.client; import static com.exonum.binding.common.crypto.CryptoFunctions.ed25519; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; import com.exonum.binding.common.message.TransactionMessage; import com.google.common.io.BaseEncoding; +import okhttp3.mockwebserver.RecordedRequest; final class TestUtils { private static final BaseEncoding HEX_ENCODER = BaseEncoding.base16().lowerCase(); @@ -36,4 +40,12 @@ static String toHex(TransactionMessage message) { return HEX_ENCODER.encode(message.toBytes()); } + static void assertExactPath(RecordedRequest request, String url) { + assertThat(request.getPath(), is("/" + url)); + } + + static void assertPath(RecordedRequest request, String url) { + assertThat(request.getPath(), startsWith("/" + url)); + } + } From bdadd5d93643506d7cc2cdf893e4c03173d5e438 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Fri, 12 Jul 2019 10:31:41 +0300 Subject: [PATCH 7/8] Added integration test for prefix feature coverage --- ...umHttpClientWithPrefixIntegrationTest.java | 66 +++++++++++++++++++ .../java/com/exonum/client/TestUtils.java | 1 - 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java diff --git a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java new file mode 100644 index 0000000000..8d89324ee7 --- /dev/null +++ b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019 The Exonum Team + * + * 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.exonum.client; + +import static com.exonum.client.ExonumUrls.USER_AGENT; +import static com.exonum.client.TestUtils.assertExactPath; + +import java.io.IOException; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ExonumHttpClientWithPrefixIntegrationTest { + private MockWebServer server; + private ExonumClient exonumClient; + private String prefixUrl = "pre/fix/"; + + @BeforeEach + void start() throws IOException { + server = new MockWebServer(); + server.start(); + + exonumClient = ExonumClient.newBuilder() + .setExonumHost(server.url("/").url()) + .setPrefix(prefixUrl) + .build(); + } + + @AfterEach + void shutdown() throws IOException { + server.shutdown(); + } + + @Test + @DisplayName("LC applies the given prefix to the underlying requests") + void requestWithPrefix() throws InterruptedException { + // Mock response + server.enqueue(new MockResponse().setBody("ok")); + + // Call + exonumClient.getUserAgentInfo(); + + // Assert request params + RecordedRequest recordedRequest = server.takeRequest(); + assertExactPath(recordedRequest, prefixUrl + USER_AGENT); + } + +} diff --git a/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java b/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java index dd819c6099..4b280b09f7 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java +++ b/exonum-light-client/src/test/java/com/exonum/client/TestUtils.java @@ -47,5 +47,4 @@ static void assertExactPath(RecordedRequest request, String url) { static void assertPath(RecordedRequest request, String url) { assertThat(request.getPath(), startsWith("/" + url)); } - } From 363ee6b3418c0fd7f81e8c65942d8a69a5eb17a2 Mon Sep 17 00:00:00 2001 From: Oleg Bondar Date: Fri, 12 Jul 2019 10:33:28 +0300 Subject: [PATCH 8/8] minor --- .../client/ExonumHttpClientWithPrefixIntegrationTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java index 8d89324ee7..97aa715049 100644 --- a/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java +++ b/exonum-light-client/src/test/java/com/exonum/client/ExonumHttpClientWithPrefixIntegrationTest.java @@ -16,8 +16,7 @@ package com.exonum.client; -import static com.exonum.client.ExonumUrls.USER_AGENT; -import static com.exonum.client.TestUtils.assertExactPath; +import static com.exonum.client.TestUtils.assertPath; import java.io.IOException; import okhttp3.mockwebserver.MockResponse; @@ -31,7 +30,7 @@ class ExonumHttpClientWithPrefixIntegrationTest { private MockWebServer server; private ExonumClient exonumClient; - private String prefixUrl = "pre/fix/"; + private String prefixUrl = "pre/fix"; @BeforeEach void start() throws IOException { @@ -60,7 +59,7 @@ void requestWithPrefix() throws InterruptedException { // Assert request params RecordedRequest recordedRequest = server.takeRequest(); - assertExactPath(recordedRequest, prefixUrl + USER_AGENT); + assertPath(recordedRequest, prefixUrl); } }