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 2020/11/04 16:43:31 UTC

[camel-quarkus] 05/07: Stub Geocoder tests with WireMock

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

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

commit b774567e890688340dd1d569acac3c657fc81f1e
Author: James Netherton <ja...@gmail.com>
AuthorDate: Tue Nov 3 09:50:58 2020 +0000

    Stub Geocoder tests with WireMock
---
 integration-tests/geocoder/README.adoc             |  10 +
 integration-tests/geocoder/pom.xml                 |   2 +-
 .../geocoder/it/GeocoderGoogleResource.java        |   6 +-
 .../component/geocoder/it/GeocoderProducers.java   |  55 ++
 .../quarkus/component/geocoder/it/Routes.java      | 129 ----
 .../src/main/resources/application.properties      |   8 +-
 .../component/geocoder/it/GeocoderGoogleTest.java  |  25 +-
 .../geocoder/it/GeocoderNominationTest.java        |   2 +
 .../geocoder/it/GeocoderTestResource.java          |  35 +
 .../test/resources/__files/mapsApiAddresses.json   | 771 +++++++++++++++++++++
 .../resources/mappings/geocodeGetFromAddress.json  |  28 +
 .../resources/mappings/geocodeGetFromFile.json     |  29 +
 .../resources/mappings/geocodeGetFromLatLng.json   |  28 +
 13 files changed, 987 insertions(+), 141 deletions(-)

diff --git a/integration-tests/geocoder/README.adoc b/integration-tests/geocoder/README.adoc
index a47b4b2..aa048bc 100644
--- a/integration-tests/geocoder/README.adoc
+++ b/integration-tests/geocoder/README.adoc
@@ -1,5 +1,7 @@
 == Camel Quarkus Geocoder Integration Tests
 
+By default the Geocoder integration tests use WireMock to stub the API interactions.
+
 To run `camel-quarkus-geocoder` integration tests using google maps service, you will need a google cloud https://developers.google.com/maps/documentation/javascript/get-api-key[API key].
 
 Then set the following environment variable:
@@ -8,3 +10,11 @@ Then set the following environment variable:
 ----
 GOOGLE_API_KEY=your-api-id
 ----
+
+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/geocoder/pom.xml b/integration-tests/geocoder/pom.xml
index 05e2c98..e882ad3 100644
--- a/integration-tests/geocoder/pom.xml
+++ b/integration-tests/geocoder/pom.xml
@@ -62,7 +62,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
-            <artifactId>camel-quarkus-integration-test-support-mock-backend</artifactId>
+            <artifactId>camel-quarkus-integration-wiremock-support</artifactId>
         </dependency>
 
 
diff --git a/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleResource.java b/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleResource.java
index 36c0a47..6db2186 100644
--- a/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleResource.java
+++ b/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleResource.java
@@ -46,7 +46,7 @@ public class GeocoderGoogleResource {
         LOG.infof("Retrieve info from current location");
         final GeocodingResult[] response = producerTemplate.requestBody(
                 String.format("geocoder:address:current?apiKey=%s", googleApiKey),
-                "Hello World", GeocodingResult[].class);
+                null, GeocodingResult[].class);
         LOG.infof("Response : %s", response);
         return response;
     }
@@ -57,7 +57,7 @@ public class GeocoderGoogleResource {
         LOG.infof("Retrieve info from address : %s", address);
         final GeocodingResult[] response = producerTemplate.requestBody(
                 String.format("geocoder:address:%s?apiKey=%s", address, googleApiKey),
-                "Hello World", GeocodingResult[].class);
+                null, GeocodingResult[].class);
         LOG.infof("Response: %s", response);
         return response;
     }
@@ -68,7 +68,7 @@ public class GeocoderGoogleResource {
         LOG.infof("Retrieve  info from georgraphic coordinates latitude : %s, longitude %s", latitude, longitude);
         final GeocodingResult[] response = producerTemplate.requestBody(
                 String.format("geocoder:latlng:%s,%s?apiKey=%s", latitude, longitude, googleApiKey),
-                "Hello World", GeocodingResult[].class);
+                null, GeocodingResult[].class);
         LOG.infof("Response : %s", response);
         return response;
     }
diff --git a/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderProducers.java b/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderProducers.java
new file mode 100644
index 0000000..b6f24a3
--- /dev/null
+++ b/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderProducers.java
@@ -0,0 +1,55 @@
+/*
+ * 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.geocoder.it;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Named;
+
+import io.quarkus.arc.Unremovable;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.geocoder.GeoCoderComponent;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+@ApplicationScoped
+public class GeocoderProducers {
+
+    @ConfigProperty(name = "google.api.key")
+    String googleApiKey;
+
+    /**
+     * We need to implement some conditional configuration of the {@link GeoCoderComponent} thus we create it
+     * programmatically and publish via CDI.
+     *
+     * @return a configured {@link GeoCoderComponent}
+     */
+    @Produces
+    @ApplicationScoped
+    @Unremovable
+    @Named("geocoder")
+    GeoCoderComponent geocoderComponent(CamelContext camelContext, MockApiService mockApiService)
+            throws IllegalAccessException, NoSuchFieldException, InstantiationException {
+        final String wireMockUrl = System.getProperty("wiremock.url");
+        final GeoCoderComponent result = new GeoCoderComponent();
+        result.setCamelContext(camelContext);
+
+        if (wireMockUrl != null) {
+            result.setGeoApiContext(mockApiService.createGeoApiContext(wireMockUrl, googleApiKey));
+        }
+        return result;
+    }
+}
diff --git a/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/Routes.java b/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/Routes.java
deleted file mode 100644
index 3d96cde..0000000
--- a/integration-tests/geocoder/src/main/java/org/apache/camel/quarkus/component/geocoder/it/Routes.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.geocoder.it;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Produces;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import io.quarkus.arc.Unremovable;
-import org.apache.camel.Exchange;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.geocoder.GeoCoderComponent;
-import org.apache.camel.quarkus.test.mock.backend.MockBackendUtils;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-
-@ApplicationScoped
-public class Routes extends RouteBuilder {
-
-    @ConfigProperty(name = "google.api.key")
-    String googleApiKey;
-    @ConfigProperty(name = "quarkus.http.test-port")
-    int httpTestPort;
-    @ConfigProperty(name = "quarkus.http.port")
-    int httpPort;
-    @Inject
-    MockApiService mockApiService;
-
-    private String getBaseUri() {
-        final boolean isNativeMode = "executable".equals(System.getProperty("org.graalvm.nativeimage.kind"));
-        return "AIzaFakeKey".equals(googleApiKey)
-                ? "http://localhost:" + (isNativeMode ? httpPort : httpTestPort)
-                : "https://maps.googleapis.com";
-    }
-
-    /**
-     * We need to implement some conditional configuration of the {@link GeoCoderComponent} thus we create it
-     * programmatically and publish via CDI.
-     *
-     * @return a configured {@link GeoCoderComponent}
-     */
-    @Produces
-    @ApplicationScoped
-    @Unremovable
-    @Named("geocoder")
-    GeoCoderComponent geocoderComponent() throws IllegalAccessException, NoSuchFieldException, InstantiationException {
-        final GeoCoderComponent result = new GeoCoderComponent();
-        result.setCamelContext(getContext());
-        result.setGeoApiContext(mockApiService.createGeoApiContext(getBaseUri(), googleApiKey));
-        return result;
-    }
-
-    @Override
-    public void configure() throws Exception {
-        if (MockBackendUtils.startMockBackend(true)) {
-            from("platform-http:///maps/api/geocode/json?httpMethodRestrict=GET")
-                    .process(e -> load(createMockGeocodeResponse(), e));
-            from("platform-http:///geolocation/v1/geolocate?httpMethodRestrict=POST")
-                    .process(e -> load(createMockGeolocateResponse(), e));
-        }
-    }
-
-    private String createMockGeolocateResponse() {
-        return "{\n" +
-                "  \"location\": {\n" +
-                "    \"lat\": 71.5388001,\n" +
-                "    \"lng\": -66.885417\n" +
-                "  },\n" +
-                "  \"accuracy\": 578963\n" +
-                "} ";
-    }
-
-    private String createMockGeocodeResponse() {
-        return "{\n"
-                + "   \"results\" : [\n"
-                + "      {\n"
-                + "         \"address_components\" : [\n"
-                + "            {\n"
-                + "               \"long_name\" : \"1600\",\n"
-                + "               \"short_name\" : \"1600\",\n"
-                + "               \"types\" : [ \"street_number\" ]\n"
-                + "            }\n"
-                + "         ],\n"
-                + "         \"formatted_address\" : \"1600 Amphitheatre Parkway, Mountain View, "
-                + "CA 94043, USA\",\n"
-                + "         \"geometry\" : {\n"
-                + "            \"location\" : {\n"
-                + "               \"lat\" : 37.4220033,\n"
-                + "               \"lng\" : -122.0839778\n"
-                + "            },\n"
-                + "            \"location_type\" : \"ROOFTOP\",\n"
-                + "            \"viewport\" : {\n"
-                + "               \"northeast\" : {\n"
-                + "                  \"lat\" : 37.4233522802915,\n"
-                + "                  \"lng\" : -122.0826288197085\n"
-                + "               },\n"
-                + "               \"southwest\" : {\n"
-                + "                  \"lat\" : 37.4206543197085,\n"
-                + "                  \"lng\" : -122.0853267802915\n"
-                + "               }\n"
-                + "            }\n"
-                + "         },\n"
-                + "         \"types\" : [ \"street_address\" ]\n"
-                + "      }\n"
-                + "   ],\n"
-                + "   \"status\" : \"OK\"\n"
-                + "}";
-
-    }
-
-    private void load(String response, Exchange exchange) {
-        exchange.getMessage().setBody(response);
-    }
-
-}
diff --git a/integration-tests/geocoder/src/main/resources/application.properties b/integration-tests/geocoder/src/main/resources/application.properties
index 8668957..d3bb1dc 100644
--- a/integration-tests/geocoder/src/main/resources/application.properties
+++ b/integration-tests/geocoder/src/main/resources/application.properties
@@ -21,13 +21,7 @@
 # add your API KEY to run the examples
 google.api.key=${GOOGLE_API_KEY:AIzaFakeKey}
 
-# You may want to export CAMEL_QUARKUS_START_MOCK_BACKEND=false to avoid starting he the mock Google Maps API
-# to make sure that you test against the real remote Google Maps API
-camel.quarkus.start-mock-backend=true
-
 # this configuration is needed only to mock Google Maps API
 quarkus.index-dependency.gmaps.group-id=com.google.maps
 quarkus.index-dependency.gmaps.artifact-id=google-maps-services
-quarkus.camel.native.reflection.include-patterns=com.google.maps.GeoApiContext$Builder
-
-
+quarkus.camel.native.reflection.include-patterns=com.google.maps.GeoApiContext$Builder
\ No newline at end of file
diff --git a/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleTest.java b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleTest.java
index 673002b..3387faf 100644
--- a/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleTest.java
+++ b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderGoogleTest.java
@@ -16,20 +16,43 @@
  */
 package org.apache.camel.quarkus.component.geocoder.it;
 
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.common.http.TestHTTPEndpoint;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
+import org.apache.camel.quarkus.test.wiremock.MockServer;
 import org.junit.jupiter.api.Test;
 
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.matching;
+import static com.github.tomakehurst.wiremock.client.WireMock.request;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
 import static org.hamcrest.Matchers.hasKey;
 
 @QuarkusTest
 @TestHTTPEndpoint(GeocoderGoogleResource.class)
+@QuarkusTestResource(GeocoderTestResource.class)
 class GeocoderGoogleTest {
 
+    @MockServer
+    WireMockServer server;
+
     @Test
     public void loadCurrentLocation() {
-        // disable test if no API KEY
+        // We need to manually stub this API call because it invokes multiple API targets:
+        // - googleapis.com
+        // - maps.googleapis.com
+        if (server != null) {
+            server.stubFor(request("POST", urlPathEqualTo("/geolocation/v1/geolocate"))
+                    .withQueryParam("key", matching(".*"))
+                    .withRequestBody(equalToJson("{\"considerIp\": true}"))
+                    .willReturn(aResponse()
+                            .withHeader("Content-Type", "application/json")
+                            .withBody("{\"location\":{\"lat\":24.7768404,\"lng\":-76.2849047},\"accuracy\":8252}")));
+        }
+
         RestAssured.get()
                 .then()
                 .statusCode(200)
diff --git a/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderNominationTest.java b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderNominationTest.java
index f3cd27c..b01962a 100644
--- a/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderNominationTest.java
+++ b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderNominationTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.quarkus.component.geocoder.it;
 
+import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.common.http.TestHTTPEndpoint;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
@@ -25,6 +26,7 @@ import static org.hamcrest.Matchers.equalTo;
 
 @QuarkusTest
 @TestHTTPEndpoint(GeocoderNominationResource.class)
+@QuarkusTestResource(GeocoderTestResource.class)
 public class GeocoderNominationTest {
 
     @Test
diff --git a/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderTestResource.java b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderTestResource.java
new file mode 100644
index 0000000..260e9c4
--- /dev/null
+++ b/integration-tests/geocoder/src/test/java/org/apache/camel/quarkus/component/geocoder/it/GeocoderTestResource.java
@@ -0,0 +1,35 @@
+/*
+ * 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.geocoder.it;
+
+import org.apache.camel.quarkus.test.wiremock.WireMockTestResourceLifecycleManager;
+
+public class GeocoderTestResource extends WireMockTestResourceLifecycleManager {
+
+    private static final String GOOGLE_API_BASE_URL = "https://maps.googleapis.com/";
+    private static final String GOOGLE_API_ENV_KEY = "GOOGLE_API_KEY";
+
+    @Override
+    protected String getRecordTargetBaseUrl() {
+        return GOOGLE_API_BASE_URL;
+    }
+
+    @Override
+    protected boolean isMockingEnabled() {
+        return !envVarsPresent(GOOGLE_API_ENV_KEY);
+    }
+}
diff --git a/integration-tests/geocoder/src/test/resources/__files/mapsApiAddresses.json b/integration-tests/geocoder/src/test/resources/__files/mapsApiAddresses.json
new file mode 100644
index 0000000..8a3c552
--- /dev/null
+++ b/integration-tests/geocoder/src/test/resources/__files/mapsApiAddresses.json
@@ -0,0 +1,771 @@
+{
+   "plus_code" : {
+      "compound_code" : "P27Q+MC New York, NY, USA",
+      "global_code" : "87G8P27Q+MC"
+   },
+   "results" : [
+      {
+         "address_components" : [
+            {
+               "long_name" : "277",
+               "short_name" : "277",
+               "types" : [ "street_number" ]
+            },
+            {
+               "long_name" : "Bedford Avenue",
+               "short_name" : "Bedford Ave",
+               "types" : [ "route" ]
+            },
+            {
+               "long_name" : "Williamsburg",
+               "short_name" : "Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            },
+            {
+               "long_name" : "11211",
+               "short_name" : "11211",
+               "types" : [ "postal_code" ]
+            }
+         ],
+         "formatted_address" : "277 Bedford Ave, Brooklyn, NY 11211, USA",
+         "geometry" : {
+            "location" : {
+               "lat" : 40.7142205,
+               "lng" : -73.9612903
+            },
+            "location_type" : "ROOFTOP",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.71556948029149,
+                  "lng" : -73.95994131970849
+               },
+               "southwest" : {
+                  "lat" : 40.7128715197085,
+                  "lng" : -73.9626392802915
+               }
+            }
+         },
+         "place_id" : "ChIJd8BlQ2BZwokRAFUEcm_qrcA",
+         "plus_code" : {
+            "compound_code" : "P27Q+MF New York, NY, USA",
+            "global_code" : "87G8P27Q+MF"
+         },
+         "types" : [ "street_address" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "279",
+               "short_name" : "279",
+               "types" : [ "street_number" ]
+            },
+            {
+               "long_name" : "Bedford Avenue",
+               "short_name" : "Bedford Ave",
+               "types" : [ "route" ]
+            },
+            {
+               "long_name" : "Williamsburg",
+               "short_name" : "Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            },
+            {
+               "long_name" : "11211",
+               "short_name" : "11211",
+               "types" : [ "postal_code" ]
+            },
+            {
+               "long_name" : "4203",
+               "short_name" : "4203",
+               "types" : [ "postal_code_suffix" ]
+            }
+         ],
+         "formatted_address" : "279 Bedford Ave, Brooklyn, NY 11211, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.7142628,
+                  "lng" : -73.96121309999999
+               },
+               "southwest" : {
+                  "lat" : 40.7141534,
+                  "lng" : -73.9613792
+               }
+            },
+            "location" : {
+               "lat" : 40.7142015,
+               "lng" : -73.96130769999999
+            },
+            "location_type" : "ROOFTOP",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7155570802915,
+                  "lng" : -73.95994716970849
+               },
+               "southwest" : {
+                  "lat" : 40.7128591197085,
+                  "lng" : -73.96264513029149
+               }
+            }
+         },
+         "place_id" : "ChIJRYYERGBZwokRAM4n1GlcYX4",
+         "types" : [ "premise" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "279",
+               "short_name" : "279",
+               "types" : [ "street_number" ]
+            },
+            {
+               "long_name" : "Bedford Avenue",
+               "short_name" : "Bedford Ave",
+               "types" : [ "route" ]
+            },
+            {
+               "long_name" : "Williamsburg",
+               "short_name" : "Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            },
+            {
+               "long_name" : "11211",
+               "short_name" : "11211",
+               "types" : [ "postal_code" ]
+            }
+         ],
+         "formatted_address" : "279 Bedford Ave, Brooklyn, NY 11211, USA",
+         "geometry" : {
+            "location" : {
+               "lat" : 40.7142077,
+               "lng" : -73.96131149999999
+            },
+            "location_type" : "ROOFTOP",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7155566802915,
+                  "lng" : -73.9599625197085
+               },
+               "southwest" : {
+                  "lat" : 40.7128587197085,
+                  "lng" : -73.9626604802915
+               }
+            }
+         },
+         "place_id" : "ChIJT2x8Q2BZwokRpBu2jUzX3dE",
+         "plus_code" : {
+            "compound_code" : "P27Q+MF New York, NY, USA",
+            "global_code" : "87G8P27Q+MF"
+         },
+         "types" : [
+            "bakery",
+            "cafe",
+            "establishment",
+            "food",
+            "point_of_interest",
+            "store"
+         ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "291-275",
+               "short_name" : "291-275",
+               "types" : [ "street_number" ]
+            },
+            {
+               "long_name" : "Bedford Avenue",
+               "short_name" : "Bedford Ave",
+               "types" : [ "route" ]
+            },
+            {
+               "long_name" : "Williamsburg",
+               "short_name" : "Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            },
+            {
+               "long_name" : "11211",
+               "short_name" : "11211",
+               "types" : [ "postal_code" ]
+            }
+         ],
+         "formatted_address" : "291-275 Bedford Ave, Brooklyn, NY 11211, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.7145065,
+                  "lng" : -73.9612923
+               },
+               "southwest" : {
+                  "lat" : 40.7139055,
+                  "lng" : -73.96168349999999
+               }
+            },
+            "location" : {
+               "lat" : 40.7142045,
+               "lng" : -73.9614845
+            },
+            "location_type" : "GEOMETRIC_CENTER",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7155549802915,
+                  "lng" : -73.96013891970848
+               },
+               "southwest" : {
+                  "lat" : 40.7128570197085,
+                  "lng" : -73.96283688029149
+               }
+            }
+         },
+         "place_id" : "ChIJ8ThWRGBZwokR3E1zUisk3LU",
+         "types" : [ "route" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "South Williamsburg",
+               "short_name" : "South Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "South Williamsburg, Brooklyn, NY, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.7167119,
+                  "lng" : -73.9420904
+               },
+               "southwest" : {
+                  "lat" : 40.6984866,
+                  "lng" : -73.9699432
+               }
+            },
+            "location" : {
+               "lat" : 40.7043921,
+               "lng" : -73.9565551
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7167119,
+                  "lng" : -73.9420904
+               },
+               "southwest" : {
+                  "lat" : 40.6984866,
+                  "lng" : -73.9699432
+               }
+            }
+         },
+         "place_id" : "ChIJR3_ODdlbwokRYtN19kNtcuk",
+         "types" : [ "neighborhood", "political" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "11211",
+               "short_name" : "11211",
+               "types" : [ "postal_code" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "New York",
+               "types" : [ "locality", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "Brooklyn, NY 11211, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.7280089,
+                  "lng" : -73.9207299
+               },
+               "southwest" : {
+                  "lat" : 40.7008331,
+                  "lng" : -73.9644697
+               }
+            },
+            "location" : {
+               "lat" : 40.7093358,
+               "lng" : -73.9565551
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7280089,
+                  "lng" : -73.9207299
+               },
+               "southwest" : {
+                  "lat" : 40.7008331,
+                  "lng" : -73.9644697
+               }
+            }
+         },
+         "place_id" : "ChIJvbEjlVdZwokR4KapM3WCFRw",
+         "types" : [ "postal_code" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "Williamsburg",
+               "short_name" : "Williamsburg",
+               "types" : [ "neighborhood", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "Williamsburg, Brooklyn, NY, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.7251773,
+                  "lng" : -73.936498
+               },
+               "southwest" : {
+                  "lat" : 40.6979329,
+                  "lng" : -73.96984499999999
+               }
+            },
+            "location" : {
+               "lat" : 40.7081156,
+               "lng" : -73.9570696
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.7251773,
+                  "lng" : -73.936498
+               },
+               "southwest" : {
+                  "lat" : 40.6979329,
+                  "lng" : -73.96984499999999
+               }
+            }
+         },
+         "place_id" : "ChIJQSrBBv1bwokRbNfFHCnyeYI",
+         "types" : [ "neighborhood", "political" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "Brooklyn, NY, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.739446,
+                  "lng" : -73.83336509999999
+               },
+               "southwest" : {
+                  "lat" : 40.551042,
+                  "lng" : -74.05663
+               }
+            },
+            "location" : {
+               "lat" : 40.6781784,
+               "lng" : -73.94415789999999
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.739446,
+                  "lng" : -73.83336509999999
+               },
+               "southwest" : {
+                  "lat" : 40.551042,
+                  "lng" : -74.05663
+               }
+            }
+         },
+         "place_id" : "ChIJCSF8lBZEwokRhngABHRcdoI",
+         "types" : [ "political", "sublocality", "sublocality_level_1" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "Kings County",
+               "short_name" : "Kings County",
+               "types" : [ "administrative_area_level_2", "political" ]
+            },
+            {
+               "long_name" : "Brooklyn",
+               "short_name" : "Brooklyn",
+               "types" : [ "political", "sublocality", "sublocality_level_1" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "Kings County, Brooklyn, NY, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.739446,
+                  "lng" : -73.83336509999999
+               },
+               "southwest" : {
+                  "lat" : 40.551042,
+                  "lng" : -74.05663
+               }
+            },
+            "location" : {
+               "lat" : 40.6528762,
+               "lng" : -73.95949399999999
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.739446,
+                  "lng" : -73.83336509999999
+               },
+               "southwest" : {
+                  "lat" : 40.551042,
+                  "lng" : -74.05663
+               }
+            }
+         },
+         "place_id" : "ChIJOwE7_GTtwokRs75rhW4_I6M",
+         "types" : [ "administrative_area_level_2", "political" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "New York",
+               "short_name" : "New York",
+               "types" : [ "locality", "political" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "New York, NY, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 40.9175771,
+                  "lng" : -73.70027209999999
+               },
+               "southwest" : {
+                  "lat" : 40.4773991,
+                  "lng" : -74.25908989999999
+               }
+            },
+            "location" : {
+               "lat" : 40.7127753,
+               "lng" : -74.0059728
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 40.9175771,
+                  "lng" : -73.70027209999999
+               },
+               "southwest" : {
+                  "lat" : 40.4773991,
+                  "lng" : -74.25908989999999
+               }
+            }
+         },
+         "place_id" : "ChIJOwg_06VPwokRYv534QaPC8g",
+         "types" : [ "locality", "political" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "Long Island",
+               "short_name" : "Long Island",
+               "types" : [ "establishment", "natural_feature" ]
+            },
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "Long Island, New York, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 41.1612401,
+                  "lng" : -71.85620109999999
+               },
+               "southwest" : {
+                  "lat" : 40.5429789,
+                  "lng" : -74.0419497
+               }
+            },
+            "location" : {
+               "lat" : 40.789142,
+               "lng" : -73.13496099999999
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 41.1612401,
+                  "lng" : -71.85620109999999
+               },
+               "southwest" : {
+                  "lat" : 40.5429789,
+                  "lng" : -74.0419497
+               }
+            }
+         },
+         "place_id" : "ChIJy6Xu4VRE6IkRGA2UhmH59x0",
+         "types" : [ "establishment", "natural_feature" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "New York",
+               "short_name" : "NY",
+               "types" : [ "administrative_area_level_1", "political" ]
+            },
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "New York, USA",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 45.015861,
+                  "lng" : -71.777491
+               },
+               "southwest" : {
+                  "lat" : 40.4773991,
+                  "lng" : -79.7625901
+               }
+            },
+            "location" : {
+               "lat" : 43.2994285,
+               "lng" : -74.21793260000001
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 45.015861,
+                  "lng" : -71.777491
+               },
+               "southwest" : {
+                  "lat" : 40.4773991,
+                  "lng" : -79.7625901
+               }
+            }
+         },
+         "place_id" : "ChIJqaUj8fBLzEwRZ5UY3sHGz90",
+         "types" : [ "administrative_area_level_1", "political" ]
+      },
+      {
+         "address_components" : [
+            {
+               "long_name" : "United States",
+               "short_name" : "US",
+               "types" : [ "country", "political" ]
+            }
+         ],
+         "formatted_address" : "United States",
+         "geometry" : {
+            "bounds" : {
+               "northeast" : {
+                  "lat" : 71.5388001,
+                  "lng" : -66.885417
+               },
+               "southwest" : {
+                  "lat" : 18.7763,
+                  "lng" : 170.5957
+               }
+            },
+            "location" : {
+               "lat" : 37.09024,
+               "lng" : -95.712891
+            },
+            "location_type" : "APPROXIMATE",
+            "viewport" : {
+               "northeast" : {
+                  "lat" : 71.5388001,
+                  "lng" : -66.885417
+               },
+               "southwest" : {
+                  "lat" : 18.7763,
+                  "lng" : 170.5957
+               }
+            }
+         },
+         "place_id" : "ChIJCzYy5IS16lQRQrfeQ5K5Oxw",
+         "types" : [ "country", "political" ]
+      }
+   ],
+   "status" : "OK"
+}
diff --git a/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromAddress.json b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromAddress.json
new file mode 100644
index 0000000..4881c65
--- /dev/null
+++ b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromAddress.json
@@ -0,0 +1,28 @@
+{
+  "id" : "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "name" : "maps_api_geocode_json",
+  "request" : {
+    "url" : "/maps/api/geocode/json?key=AIzaFakeKey&address=calle+marie+curie%2C+sevilla%2C+sevilla",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : "{\n   \"results\" : [\n      {\n         \"address_components\" : [\n            {\n               \"long_name\" : \"Calle Marie Curie\",\n               \"short_name\" : \"Calle Marie Curie\",\n               \"types\" : [ \"route\" ]\n            },\n            {\n               \"long_name\" : \"Sevilla\",\n               \"short_name\" : \"Sevilla\",\n               \"types\" : [ \"locality\", \"political\" ]\n            },\n            {\n               \"long_name\" [...]
+    "headers" : {
+      "Content-Type" : "application/json; charset=UTF-8",
+      "Date" : "Tue, 03 Nov 2020 09:39:11 GMT",
+      "Pragma" : "no-cache",
+      "Expires" : "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control" : "no-cache, must-revalidate",
+      "Vary" : "Accept-Language",
+      "Server" : "mafe",
+      "X-XSS-Protection" : "0",
+      "X-Frame-Options" : "SAMEORIGIN",
+      "Server-Timing" : "gfet4t7; dur=263",
+      "Alt-Svc" : "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid" : "09aa79df-8a19-41df-8655-e414d390d6eb",
+  "persistent" : true,
+  "insertionIndex" : 2
+}
\ No newline at end of file
diff --git a/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromFile.json b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromFile.json
new file mode 100644
index 0000000..383e19f
--- /dev/null
+++ b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromFile.json
@@ -0,0 +1,29 @@
+{
+  "id" : "01626380-6d65-4cdb-8080-4e7b8c3565e4",
+  "name" : "maps_api_geocode_json",
+  "request" : {
+    "url" : "/maps/api/geocode/json?key=AIzaFakeKey&latlng=40.71422400%2C-73.96145200",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "bodyFileName" : "mapsApiAddresses.json",
+    "headers" : {
+      "Content-Type" : "application/json; charset=UTF-8",
+      "Date" : "Tue, 03 Nov 2020 09:39:12 GMT",
+      "Pragma" : "no-cache",
+      "Expires" : "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control" : "no-cache, must-revalidate",
+      "Vary" : "Accept-Language",
+      "X-Goog-Maps-Metro-Area" : "New York, NY",
+      "Server" : "mafe",
+      "X-XSS-Protection" : "0",
+      "X-Frame-Options" : "SAMEORIGIN",
+      "Server-Timing" : "gfet4t7; dur=44",
+      "Alt-Svc" : "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid" : "01626380-6d65-4cdb-8080-4e7b8c3565e4",
+  "persistent" : true,
+  "insertionIndex" : 3
+}
\ No newline at end of file
diff --git a/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromLatLng.json b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromLatLng.json
new file mode 100644
index 0000000..3f9e959
--- /dev/null
+++ b/integration-tests/geocoder/src/test/resources/mappings/geocodeGetFromLatLng.json
@@ -0,0 +1,28 @@
+{
+  "id" : "93b092b6-d2d4-485c-b9a8-a1e4625e343a",
+  "name" : "maps_api_geocode_json",
+  "request" : {
+    "url" : "/maps/api/geocode/json?key=AIzaFakeKey&latlng=24.77684040%2C-76.28490470",
+    "method" : "GET"
+  },
+  "response" : {
+    "status" : 200,
+    "body" : "{\n   \"plus_code\" : {\n      \"compound_code\" : \"QPG8+P2 Freetown, The Bahamas\",\n      \"global_code\" : \"77P5QPG8+P2\"\n   },\n   \"results\" : [\n      {\n         \"address_components\" : [\n            {\n               \"long_name\" : \"Unnamed Road\",\n               \"short_name\" : \"Unnamed Road\",\n               \"types\" : [ \"route\" ]\n            },\n            {\n               \"long_name\" : \"Freetown\",\n               \"short_name\" : \"Freetown [...]
+    "headers" : {
+      "Content-Type" : "application/json; charset=UTF-8",
+      "Date" : "Tue, 03 Nov 2020 09:39:12 GMT",
+      "Pragma" : "no-cache",
+      "Expires" : "Fri, 01 Jan 1990 00:00:00 GMT",
+      "Cache-Control" : "no-cache, must-revalidate",
+      "Vary" : "Accept-Language",
+      "Server" : "mafe",
+      "X-XSS-Protection" : "0",
+      "X-Frame-Options" : "SAMEORIGIN",
+      "Server-Timing" : "gfet4t7; dur=45",
+      "Alt-Svc" : "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+    }
+  },
+  "uuid" : "93b092b6-d2d4-485c-b9a8-a1e4625e343a",
+  "persistent" : true,
+  "insertionIndex" : 4
+}
\ No newline at end of file