You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/05/23 20:18:14 UTC

[camel-quarkus] branch main updated: Use WireMock for xchange tests

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new d465a84e9f Use WireMock for xchange tests
d465a84e9f is described below

commit d465a84e9f9faf0bd74becb74bf542906543e1b1
Author: James Netherton <ja...@gmail.com>
AuthorDate: Mon May 23 11:18:28 2022 +0100

    Use WireMock for xchange tests
    
    Fixes #3724
---
 integration-tests/xchange/README.adoc              | 18 ++++++++
 integration-tests/xchange/pom.xml                  |  4 ++
 .../component/xchange/it/XchangeResource.java      | 49 +++++++++++++++++++---
 .../xchange/it/XchangeBinanceTestResource.java     | 45 ++++++++++++++++++++
 .../xchange/it/XchangeKrakenTestResource.java      | 45 ++++++++++++++++++++
 .../quarkus/component/xchange/it/XchangeTest.java  |  6 ++-
 ...pairs-3a81de1f-2691-412e-8896-3bac2239f07d.json |  1 +
 ...ssets-23a47848-dae8-4bdb-9ac7-851012c5b102.json |  1 +
 ...einfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json |  1 +
 ...pairs-3a81de1f-2691-412e-8896-3bac2239f07d.json | 29 +++++++++++++
 ...ssets-23a47848-dae8-4bdb-9ac7-851012c5b102.json | 29 +++++++++++++
 ...icker-9b4fb7b4-081c-4965-beae-7a5d5c9869e9.json | 29 +++++++++++++
 ...einfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json | 38 +++++++++++++++++
 ..._24hr-32b9aee3-92c1-45ac-af48-7fd4b7f67da9.json | 38 +++++++++++++++++
 14 files changed, 326 insertions(+), 7 deletions(-)

diff --git a/integration-tests/xchange/README.adoc b/integration-tests/xchange/README.adoc
new file mode 100644
index 0000000000..ef18b63bcf
--- /dev/null
+++ b/integration-tests/xchange/README.adoc
@@ -0,0 +1,18 @@
+== Camel Quarkus XChange Integration Tests
+
+By default the XChange integration tests use WireMock to stub the API interactions.
+
+To run the `camel-quarkus-xchange` integration tests against the real APIs, you can set the following environment variable:
+
+[source,shell]
+----
+export CAMEL_QUARKUS_START_MOCK_BACKEND=false
+----
+
+If the WireMock stub recordings need updating, then remove the existing files from `src/test/resources/mappings` and run tests with either:
+
+System property `-Dwiremock.record=true`
+
+Or
+
+Set environment variable `WIREMOCK_RECORD=true`
diff --git a/integration-tests/xchange/pom.xml b/integration-tests/xchange/pom.xml
index 48b26000aa..52a7b64f0f 100644
--- a/integration-tests/xchange/pom.xml
+++ b/integration-tests/xchange/pom.xml
@@ -61,6 +61,10 @@
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-wiremock-support</artifactId>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/integration-tests/xchange/src/main/java/org/apache/camel/quarkus/component/xchange/it/XchangeResource.java b/integration-tests/xchange/src/main/java/org/apache/camel/quarkus/component/xchange/it/XchangeResource.java
index e79642b6d8..4203de4185 100644
--- a/integration-tests/xchange/src/main/java/org/apache/camel/quarkus/component/xchange/it/XchangeResource.java
+++ b/integration-tests/xchange/src/main/java/org/apache/camel/quarkus/component/xchange/it/XchangeResource.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.quarkus.component.xchange.it;
 
+import java.net.URI;
 import java.util.List;
+import java.util.Optional;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -33,17 +35,26 @@ import javax.ws.rs.core.MediaType;
 
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.xchange.XChangeComponent;
+import org.apache.camel.spi.annotations.Component;
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.knowm.xchange.Exchange;
+import org.knowm.xchange.ExchangeFactory;
+import org.knowm.xchange.ExchangeSpecification;
+import org.knowm.xchange.binance.BinanceExchange;
 import org.knowm.xchange.currency.Currency;
 import org.knowm.xchange.currency.CurrencyPair;
 import org.knowm.xchange.dto.marketdata.Ticker;
 import org.knowm.xchange.dto.meta.CurrencyMetaData;
 import org.knowm.xchange.dto.meta.CurrencyPairMetaData;
+import org.knowm.xchange.kraken.KrakenExchange;
 
 @Path("/xchange")
 @ApplicationScoped
 public class XchangeResource {
 
     public static final String DEFAULT_CRYPTO_EXCHANGE = "binance";
+    public static final String ALTERNATIVE_CRYPTO_EXCHANGE = "kraken";
 
     @Inject
     ProducerTemplate producerTemplate;
@@ -55,10 +66,8 @@ public class XchangeResource {
             @PathParam("exchange") String cryptoExchange,
             @QueryParam("currencyPair") String currencyPair) {
 
-        String component = cryptoExchange.equals(DEFAULT_CRYPTO_EXCHANGE) ? "xchange" : "xchange-" + cryptoExchange;
-
         Ticker ticker = producerTemplate.requestBody(
-                component + ":" + cryptoExchange + "?service=marketdata&method=ticker&currencyPair=" + currencyPair, null,
+                "xchange:" + cryptoExchange + "?service=marketdata&method=ticker&currencyPair=" + currencyPair, null,
                 Ticker.class);
         return Json.createObjectBuilder()
                 .add("last", ticker.getLast().longValue())
@@ -114,10 +123,38 @@ public class XchangeResource {
         return metaData.getTradingFee().toPlainString();
     }
 
-    @Named("xchange-kraken")
+    @Named("xchange")
     public XChangeComponent xChangeComponent() {
-        // We are forced to create a dedicated component instance to work with multiple crypto exchanges
-        // https://issues.apache.org/jira/browse/CAMEL-16978
+        Config config = ConfigProvider.getConfig();
+        Optional<String> wireMockUrl = config.getOptionalValue("wiremock.url", String.class);
+        if (wireMockUrl.isPresent()) {
+            return new WireMockedXChangeComponent();
+        }
         return new XChangeComponent();
     }
+
+    @Component("xchange")
+    static final class WireMockedXChangeComponent extends XChangeComponent {
+        @Override
+        protected Exchange createExchange(Class<? extends Exchange> exchangeClass) {
+            String wireMockUrlProperty;
+            if (exchangeClass.equals(BinanceExchange.class)) {
+                wireMockUrlProperty = "wiremock.binance.url";
+            } else if (exchangeClass.equals(KrakenExchange.class)) {
+                wireMockUrlProperty = "wiremock.kraken.url";
+            } else {
+                throw new IllegalStateException("Unsupported WireMocked exchange " + exchangeClass.getSimpleName());
+            }
+
+            Config config = ConfigProvider.getConfig();
+            String wireMockUrl = config.getValue(wireMockUrlProperty, String.class);
+            URI uri = URI.create(wireMockUrl);
+
+            ExchangeSpecification specification = new ExchangeSpecification(exchangeClass);
+            specification.setHost("localhost");
+            specification.setPort(uri.getPort());
+            specification.setSslUri(wireMockUrl);
+            return ExchangeFactory.INSTANCE.createExchange(specification);
+        }
+    }
 }
diff --git a/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeBinanceTestResource.java b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeBinanceTestResource.java
new file mode 100644
index 0000000000..04ad911fac
--- /dev/null
+++ b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeBinanceTestResource.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.quarkus.component.xchange.it;
+
+import java.util.Map;
+
+import org.apache.camel.quarkus.test.mock.backend.MockBackendUtils;
+import org.apache.camel.quarkus.test.wiremock.WireMockTestResourceLifecycleManager;
+
+public class XchangeBinanceTestResource extends WireMockTestResourceLifecycleManager {
+
+    @Override
+    public Map<String, String> start() {
+        Map<String, String> options = super.start();
+        String wireMockUrl = options.get("wiremock.url");
+        if (wireMockUrl != null) {
+            options.put("wiremock.binance.url", wireMockUrl);
+        }
+        return options;
+    }
+
+    @Override
+    protected String getRecordTargetBaseUrl() {
+        return "https://api.binance.com/";
+    }
+
+    @Override
+    protected boolean isMockingEnabled() {
+        return MockBackendUtils.startMockBackend(false);
+    }
+}
diff --git a/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeKrakenTestResource.java b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeKrakenTestResource.java
new file mode 100644
index 0000000000..7fd83202c3
--- /dev/null
+++ b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeKrakenTestResource.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.quarkus.component.xchange.it;
+
+import java.util.Map;
+
+import org.apache.camel.quarkus.test.mock.backend.MockBackendUtils;
+import org.apache.camel.quarkus.test.wiremock.WireMockTestResourceLifecycleManager;
+
+public class XchangeKrakenTestResource extends WireMockTestResourceLifecycleManager {
+
+    @Override
+    public Map<String, String> start() {
+        Map<String, String> options = super.start();
+        String wireMockUrl = options.get("wiremock.url");
+        if (wireMockUrl != null) {
+            options.put("wiremock.kraken.url", wireMockUrl);
+        }
+        return options;
+    }
+
+    @Override
+    protected String getRecordTargetBaseUrl() {
+        return "https://api.kraken.com/";
+    }
+
+    @Override
+    protected boolean isMockingEnabled() {
+        return MockBackendUtils.startMockBackend(false);
+    }
+}
diff --git a/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeTest.java b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeTest.java
index cc3522daae..ba310e9d35 100644
--- a/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeTest.java
+++ b/integration-tests/xchange/src/test/java/org/apache/camel/quarkus/component/xchange/it/XchangeTest.java
@@ -16,12 +16,14 @@
  */
 package org.apache.camel.quarkus.component.xchange.it;
 
+import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
+import static org.apache.camel.quarkus.component.xchange.it.XchangeResource.ALTERNATIVE_CRYPTO_EXCHANGE;
 import static org.apache.camel.quarkus.component.xchange.it.XchangeResource.DEFAULT_CRYPTO_EXCHANGE;
 import static org.hamcrest.Matchers.emptyOrNullString;
 import static org.hamcrest.Matchers.greaterThan;
@@ -29,10 +31,12 @@ import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.not;
 
 @QuarkusTest
+@QuarkusTestResource(XchangeBinanceTestResource.class)
+@QuarkusTestResource(XchangeKrakenTestResource.class)
 class XchangeTest {
 
     @ParameterizedTest
-    @ValueSource(strings = { DEFAULT_CRYPTO_EXCHANGE, "kraken" })
+    @ValueSource(strings = { DEFAULT_CRYPTO_EXCHANGE, ALTERNATIVE_CRYPTO_EXCHANGE })
     public void currencyTicker(String cryptoExchange) {
         RestAssured.given()
                 .queryParam("currencyPair", "BTC/USDT")
diff --git a/integration-tests/xchange/src/test/resources/__files/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json b/integration-tests/xchange/src/test/resources/__files/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json
new file mode 100644
index 0000000000..6c010dd818
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/__files/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json
@@ -0,0 +1 @@
+{"error":[],"result":{"1INCHEUR":{"altname":"1INCHEUR","wsname":"1INCH/EUR","aclass_base":"currency","base":"1INCH","aclass_quote":"currency","quote":"ZEUR","lot":"unit","pair_decimals":3,"lot_decimals":8,"lot_multiplier":1,"leverage_buy":[],"leverage_sell":[],"fees":[[0,0.26],[50000,0.24],[100000,0.22],[250000,0.2],[500000,0.18],[1000000,0.16],[2500000,0.14],[5000000,0.12],[10000000,0.1]],"fees_maker":[[0,0.16],[50000,0.14],[100000,0.12],[250000,0.1],[500000,0.08],[1000000,0.06],[250000 [...]
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/__files/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json b/integration-tests/xchange/src/test/resources/__files/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json
new file mode 100644
index 0000000000..e26ee5e838
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/__files/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json
@@ -0,0 +1 @@
+{"error":[],"result":{"1INCH":{"aclass":"currency","altname":"1INCH","decimals":10,"display_decimals":5},"AAVE":{"aclass":"currency","altname":"AAVE","decimals":10,"display_decimals":5},"ACA":{"aclass":"currency","altname":"ACA","decimals":10,"display_decimals":5},"ADA":{"aclass":"currency","altname":"ADA","decimals":8,"display_decimals":6},"ADA.S":{"aclass":"currency","altname":"ADA.S","decimals":8,"display_decimals":6},"AGLD":{"aclass":"currency","altname":"AGLD","decimals":10,"display [...]
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/__files/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json b/integration-tests/xchange/src/test/resources/__files/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json
new file mode 100644
index 0000000000..9d1f31dc7e
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/__files/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json
@@ -0,0 +1 @@
+{"timezone":"UTC","serverTime":1653300040347,"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":1200},{"rateLimitType":"ORDERS","interval":"SECOND","intervalNum":10,"limit":50},{"rateLimitType":"ORDERS","interval":"DAY","intervalNum":1,"limit":160000},{"rateLimitType":"RAW_REQUESTS","interval":"MINUTE","intervalNum":5,"limit":6100}],"exchangeFilters":[],"symbols":[{"symbol":"ETHBTC","status":"TRADING","baseAsset":"ETH","baseAssetPrecision":8,"quot [...]
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/mappings/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json b/integration-tests/xchange/src/test/resources/mappings/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json
new file mode 100644
index 0000000000..efc9e74ea2
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/mappings/0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json
@@ -0,0 +1,29 @@
+{
+  "id" : "3a81de1f-2691-412e-8896-3bac2239f07d",
+  "name" : "0_public_assetpairs",
+  "request" : {
+    "url" : "/0/public/AssetPairs",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "bodyFileName" : "0_public_assetpairs-3a81de1f-2691-412e-8896-3bac2239f07d.json",
+    "headers" : {
+      "Date" : "Mon, 23 May 2022 10:00:43 GMT",
+      "Content-Type" : "application/json",
+      "strict-transport-security" : "max-age=15768000",
+      "cache-control" : "public, max-age=1, s-maxage=1",
+      "referrer-policy" : "strict-origin-when-cross-origin",
+      "Last-Modified" : "Mon, 23 May 2022 10:00:43 GMT",
+      "CF-Cache-Status" : "HIT",
+      "Age" : "0",
+      "Expect-CT" : "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"",
+      "Set-Cookie" : "__cf_bm=uVwO8iZAmsSOoFZJFL.adKZIhsgJyaeCzuDdnYLbSRA-1653300043-0-AWCUFlfFL/e3ROoR/yQ9vzEjMnQ8K07asrciF8fCNbyo50hLK9qLmkFDznBTJv44kAeyVby9C/qL2EKiih+BqQM=; path=/; expires=Mon, 23-May-22 10:30:43 GMT; domain=.kraken.com; HttpOnly; Secure; SameSite=None",
+      "Server" : "cloudflare",
+      "CF-RAY" : "70fcf237e8e274a1-LHR"
+    }
+  },
+  "uuid" : "3a81de1f-2691-412e-8896-3bac2239f07d",
+  "persistent" : true,
+  "insertionIndex" : 1
+}
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/mappings/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json b/integration-tests/xchange/src/test/resources/mappings/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json
new file mode 100644
index 0000000000..e9ea23eeb9
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/mappings/0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json
@@ -0,0 +1,29 @@
+{
+  "id" : "23a47848-dae8-4bdb-9ac7-851012c5b102",
+  "name" : "0_public_assets",
+  "request" : {
+    "url" : "/0/public/Assets",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "bodyFileName" : "0_public_assets-23a47848-dae8-4bdb-9ac7-851012c5b102.json",
+    "headers" : {
+      "Date" : "Mon, 23 May 2022 10:00:43 GMT",
+      "Content-Type" : "application/json",
+      "cache-control" : "public, max-age=1, s-maxage=1",
+      "strict-transport-security" : "max-age=15768000",
+      "referrer-policy" : "strict-origin-when-cross-origin",
+      "Last-Modified" : "Mon, 23 May 2022 10:00:41 GMT",
+      "CF-Cache-Status" : "HIT",
+      "Age" : "0",
+      "Expect-CT" : "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"",
+      "Set-Cookie" : "__cf_bm=iapj4pvCgI5gecM1t0ur_QSguz813VAzrypZYB4pBag-1653300043-0-AY4IaU2BEtA5otAnha2qtjyHYbyCjFGUegriH+w5U1tkjVkv20xwO/dkWgZBAVf5KPaFbKKiIV3ihPMxAadPaHE=; path=/; expires=Mon, 23-May-22 10:30:43 GMT; domain=.kraken.com; HttpOnly; Secure; SameSite=None",
+      "Server" : "cloudflare",
+      "CF-RAY" : "70fcf2391a9474a1-LHR"
+    }
+  },
+  "uuid" : "23a47848-dae8-4bdb-9ac7-851012c5b102",
+  "persistent" : true,
+  "insertionIndex" : 2
+}
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/mappings/0_public_ticker-9b4fb7b4-081c-4965-beae-7a5d5c9869e9.json b/integration-tests/xchange/src/test/resources/mappings/0_public_ticker-9b4fb7b4-081c-4965-beae-7a5d5c9869e9.json
new file mode 100644
index 0000000000..699133df24
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/mappings/0_public_ticker-9b4fb7b4-081c-4965-beae-7a5d5c9869e9.json
@@ -0,0 +1,29 @@
+{
+  "id" : "9b4fb7b4-081c-4965-beae-7a5d5c9869e9",
+  "name" : "0_public_ticker",
+  "request" : {
+    "url" : "/0/public/Ticker?pair=XBTUSDT",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : "{\"error\":[],\"result\":{\"XBTUSDT\":{\"a\":[\"30443.10000\",\"1\",\"1.000\"],\"b\":[\"30436.80000\",\"1\",\"1.000\"],\"c\":[\"30441.60000\",\"0.01527161\"],\"v\":[\"129.93859286\",\"366.00353540\"],\"p\":[\"30294.71427\",\"30159.21029\"],\"t\":[933,2587],\"l\":[\"30086.60000\",\"29666.00000\"],\"h\":[\"30647.30000\",\"30647.30000\"],\"o\":\"30295.80000\"}}}",
+    "headers" : {
+      "Date" : "Mon, 23 May 2022 10:00:43 GMT",
+      "Content-Type" : "application/json; charset=utf-8",
+      "cache-control" : "public,max-age=1,smaxage=1",
+      "strict-transport-security" : "max-age=15768000",
+      "vary" : "Accept-Encoding",
+      "referrer-policy" : "strict-origin-when-cross-origin",
+      "Last-Modified" : "Mon, 23 May 2022 10:00:43 GMT",
+      "CF-Cache-Status" : "HIT",
+      "Expect-CT" : "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"",
+      "Set-Cookie" : "__cf_bm=gLPf8Sa5HYkWhYf2CfUzvT_3e6mvdich03g9uw5OfKU-1653300043-0-AX8lXDNJ1hqkGEC8pKIAZURGxJJEtc12pP+QNJ7yO4WIaZNAgXZ3zax7K4M9jdnIkIWBOwIIKJlB/Unne5Yvbqo=; path=/; expires=Mon, 23-May-22 10:30:43 GMT; domain=.kraken.com; HttpOnly; Secure; SameSite=None",
+      "Server" : "cloudflare",
+      "CF-RAY" : "70fcf2398b1274a1-LHR"
+    }
+  },
+  "uuid" : "9b4fb7b4-081c-4965-beae-7a5d5c9869e9",
+  "persistent" : true,
+  "insertionIndex" : 3
+}
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/mappings/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json b/integration-tests/xchange/src/test/resources/mappings/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json
new file mode 100644
index 0000000000..1ce189b7ca
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/mappings/api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json
@@ -0,0 +1,38 @@
+{
+  "id" : "41fc7d67-259d-4bf2-944d-8a00f9c2370a",
+  "name" : "api_v3_exchangeinfo",
+  "request" : {
+    "url" : "/api/v3/exchangeInfo",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "bodyFileName" : "api_v3_exchangeinfo-41fc7d67-259d-4bf2-944d-8a00f9c2370a.json",
+    "headers" : {
+      "Content-Type" : "application/json;charset=UTF-8",
+      "Date" : "Mon, 23 May 2022 10:00:40 GMT",
+      "Server" : "nginx",
+      "Vary" : "Accept-Encoding",
+      "x-mbx-uuid" : "820c2377-8d1c-4f8b-aa84-4d952fb43379",
+      "x-mbx-used-weight" : "10",
+      "x-mbx-used-weight-1m" : "10",
+      "Strict-Transport-Security" : "max-age=31536000; includeSubdomains",
+      "X-Frame-Options" : "SAMEORIGIN",
+      "X-Xss-Protection" : "1; mode=block",
+      "X-Content-Type-Options" : "nosniff",
+      "Content-Security-Policy" : "default-src 'self'",
+      "X-Content-Security-Policy" : "default-src 'self'",
+      "X-WebKit-CSP" : "default-src 'self'",
+      "Cache-Control" : "no-cache, no-store, must-revalidate",
+      "Pragma" : "no-cache",
+      "Expires" : "0",
+      "X-Cache" : "Miss from cloudfront",
+      "Via" : "1.1 dcf307cd37f9d94bc0225628c89153d8.cloudfront.net (CloudFront)",
+      "X-Amz-Cf-Pop" : "LHR61-P4",
+      "X-Amz-Cf-Id" : "1jMJrXKrUkmHDYVgnmxAvRnAgZeE9ChlUE71MD5j19znjm9ahuwHBw=="
+    }
+  },
+  "uuid" : "41fc7d67-259d-4bf2-944d-8a00f9c2370a",
+  "persistent" : true,
+  "insertionIndex" : 1
+}
\ No newline at end of file
diff --git a/integration-tests/xchange/src/test/resources/mappings/api_v3_ticker_24hr-32b9aee3-92c1-45ac-af48-7fd4b7f67da9.json b/integration-tests/xchange/src/test/resources/mappings/api_v3_ticker_24hr-32b9aee3-92c1-45ac-af48-7fd4b7f67da9.json
new file mode 100644
index 0000000000..3c601a5444
--- /dev/null
+++ b/integration-tests/xchange/src/test/resources/mappings/api_v3_ticker_24hr-32b9aee3-92c1-45ac-af48-7fd4b7f67da9.json
@@ -0,0 +1,38 @@
+{
+  "id" : "32b9aee3-92c1-45ac-af48-7fd4b7f67da9",
+  "name" : "api_v3_ticker_24hr",
+  "request" : {
+    "url" : "/api/v3/ticker/24hr?symbol=BTCUSDT",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : "{\"symbol\":\"BTCUSDT\",\"priceChange\":\"263.37000000\",\"priceChangePercent\":\"0.873\",\"weightedAvgPrice\":\"30178.56459959\",\"prevClosePrice\":\"30177.32000000\",\"lastPrice\":\"30440.70000000\",\"lastQty\":\"0.00536000\",\"bidPrice\":\"30440.69000000\",\"bidQty\":\"6.00464000\",\"askPrice\":\"30440.70000000\",\"askQty\":\"0.00004000\",\"openPrice\":\"30177.33000000\",\"highPrice\":\"30670.51000000\",\"lowPrice\":\"29668.51000000\",\"volume\":\"41775.05738000\",\"quot [...]
+    "headers" : {
+      "Content-Type" : "application/json;charset=UTF-8",
+      "Date" : "Mon, 23 May 2022 10:00:43 GMT",
+      "Server" : "nginx",
+      "Vary" : "Accept-Encoding",
+      "x-mbx-uuid" : "cd2079da-d451-4253-bebb-d549b3ae623e",
+      "x-mbx-used-weight" : "11",
+      "x-mbx-used-weight-1m" : "11",
+      "Strict-Transport-Security" : "max-age=31536000; includeSubdomains",
+      "X-Frame-Options" : "SAMEORIGIN",
+      "X-Xss-Protection" : "1; mode=block",
+      "X-Content-Type-Options" : "nosniff",
+      "Content-Security-Policy" : "default-src 'self'",
+      "X-Content-Security-Policy" : "default-src 'self'",
+      "X-WebKit-CSP" : "default-src 'self'",
+      "Cache-Control" : "no-cache, no-store, must-revalidate",
+      "Pragma" : "no-cache",
+      "Expires" : "0",
+      "X-Cache" : "Miss from cloudfront",
+      "Via" : "1.1 dcf307cd37f9d94bc0225628c89153d8.cloudfront.net (CloudFront)",
+      "X-Amz-Cf-Pop" : "LHR61-P4",
+      "X-Amz-Cf-Id" : "rkdJI-EMurvz1Duuki0lRXs0n3QIFw_C9U0cK-BC-4AHgOEw67T2Kw=="
+    }
+  },
+  "uuid" : "32b9aee3-92c1-45ac-af48-7fd4b7f67da9",
+  "persistent" : true,
+  "insertionIndex" : 2
+}
\ No newline at end of file