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

acosentino pushed a commit to branch camel-2.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 12ca5a537e3dfc0eb9b2b02782016f5e15e80991
Author: Christoph Deppisch <cdeppi...@redhat.com>
AuthorDate: Thu Jun 6 12:47:51 2019 +0200

    CAMEL-13617: Improve testability of google-sheets component
---
 components/camel-google-sheets/pom.xml             |  90 ++++-
 .../main/docs/google-sheets-stream-component.adoc  |   2 +-
 .../sheets/BatchGoogleSheetsClientFactory.java     |  63 +++-
 .../google/sheets/GoogleSheetsClientFactory.java   |   6 +-
 .../google/sheets/GoogleSheetsEndpoint.java        |  41 ++-
 .../google/sheets/GoogleSheetsProducer.java        |   2 +-
 .../sheets/GoogleSheetsVerifierExtension.java      |   9 +-
 .../sheets/internal/GoogleSheetsConstants.java     |   4 +-
 .../stream/GoogleSheetsStreamConfiguration.java    |   4 +-
 .../sheets/stream/GoogleSheetsStreamConsumer.java  |  23 +-
 .../sheets/AbstractGoogleSheetsTestSupport.java    |  43 ++-
 .../sheets/SheetsSpreadsheetsIntegrationTest.java  |  37 +-
 .../SheetsSpreadsheetsValuesIntegrationTest.java   |  83 ++++-
 .../sheets/server/GoogleSheetsApiTestServer.java   | 354 ++++++++++++++++++
 .../server/GoogleSheetsApiTestServerAssert.java    | 405 +++++++++++++++++++++
 .../server/GoogleSheetsApiTestServerRule.java      | 116 ++++++
 .../AbstractGoogleSheetsStreamTestSupport.java     |  17 +
 .../SheetsStreamConsumerIntegrationTest.java       |  77 +++-
 .../src/test/resources/googleapis.jks              | Bin 0 -> 2695 bytes
 .../src/test/resources/test-options.properties     |   8 +-
 parent/pom.xml                                     |   1 +
 .../GoogleSheetsStreamComponentConfiguration.java  |   2 +-
 22 files changed, 1281 insertions(+), 106 deletions(-)

diff --git a/components/camel-google-sheets/pom.xml 
b/components/camel-google-sheets/pom.xml
index d13d94f..0be3151 100644
--- a/components/camel-google-sheets/pom.xml
+++ b/components/camel-google-sheets/pom.xml
@@ -29,8 +29,8 @@
 
   <artifactId>camel-google-sheets</artifactId>
   <packaging>jar</packaging>
-  <name>Camel :: GoogleSheets</name>
-  <description>Camel Component for GoogleSheets</description>
+  <name>Camel :: Google Sheets</name>
+  <description>Camel Component for Google Sheets</description>
 
   <properties>
     <schemeName>google-sheets</schemeName>
@@ -40,8 +40,53 @@
     
<camel.osgi.private.pkg>org.apache.camel.component.google.sheets.internal</camel.osgi.private.pkg>
     
<camel.osgi.export.pkg>org.apache.camel.component.google.sheets</camel.osgi.export.pkg>
     
<camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=google-sheets</camel.osgi.export.service>
+    
<spring-security-oauth2-version>2.3.6.RELEASE</spring-security-oauth2-version>
   </properties>
 
+  <dependencyManagement>
+    <dependencies>
+        <!-- Test dependencies -->
+        <dependency>
+          <groupId>org.assertj</groupId>
+          <artifactId>assertj-core</artifactId>
+          <version>${assertj-version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.springframework</groupId>
+          <artifactId>spring-webmvc</artifactId>
+          <version>${spring-version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.springframework.security</groupId>
+          <artifactId>spring-security-web</artifactId>
+          <version>${spring-security-version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.springframework.security.oauth</groupId>
+          <artifactId>spring-security-oauth2</artifactId>
+          <version>${spring-security-oauth2-version}</version>
+        </dependency>
+        <dependency>
+          <groupId>com.consol.citrus</groupId>
+          <artifactId>citrus-core</artifactId>
+          <version>${citrus.version}</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>com.consol.citrus</groupId>
+          <artifactId>citrus-java-dsl</artifactId>
+          <version>${citrus.version}</version>
+          <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>com.consol.citrus</groupId>
+          <artifactId>citrus-http</artifactId>
+          <version>${citrus.version}</version>
+          <scope>test</scope>
+        </dependency>
+    </dependencies>
+  </dependencyManagement>
+
   <dependencies>
     <dependency>
       <groupId>org.apache.camel</groupId>
@@ -78,9 +123,9 @@
 
     <!-- Component API javadoc in provided scope to read API signatures -->
     <dependency>
-        <groupId>com.google.apis</groupId>
-        <artifactId>google-api-services-sheets</artifactId>
-        <version>${google-api-services-sheets-version}</version>
+      <groupId>com.google.apis</groupId>
+      <artifactId>google-api-services-sheets</artifactId>
+      <version>${google-api-services-sheets-version}</version>
       <type>javadoc</type>
       <scope>provided</scope>
     </dependency>
@@ -108,6 +153,41 @@
       <artifactId>camel-test</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security.oauth</groupId>
+      <artifactId>spring-security-oauth2</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.consol.citrus</groupId>
+      <artifactId>citrus-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.consol.citrus</groupId>
+      <artifactId>citrus-java-dsl</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.consol.citrus</groupId>
+      <artifactId>citrus-http</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
diff --git 
a/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
 
b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
index ac98fdc..9112d6d 100644
--- 
a/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
+++ 
b/components/camel-google-sheets/src/main/docs/google-sheets-stream-component.adoc
@@ -91,7 +91,7 @@ with the following path and query parameters:
 | *clientSecret* (consumer) | Client secret of the sheets application |  | 
String
 | *includeGridData* (consumer) | True if grid data should be returned. | false 
| boolean
 | *majorDimension* (consumer) | Specifies the major dimension that results 
should use.. | ROWS | String
-| *maxResults* (consumer) | Specify the maximum number of returned results. 
This will limit the number of rows in a returned value range data set or the 
number of returned value ranges in a batch request. | 10 | int
+| *maxResults* (consumer) | Specify the maximum number of returned results. 
This will limit the number of rows in a returned value range data set or the 
number of returned value ranges in a batch request. | 0 | int
 | *range* (consumer) | Specifies the range of rows and columns in a sheet to 
get data from. |  | String
 | *refreshToken* (consumer) | OAuth 2 refresh token. Using this, the Google 
Calendar component can obtain a new accessToken whenever the current one 
expires - a necessity if the application is long-lived. |  | String
 | *scopes* (consumer) | Specifies the level of permissions you want a sheets 
application to have to a user account. See 
https://developers.google.com/identity/protocols/googlescopes for more info. |  
| List
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
index 1c5a91a..4125083 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/BatchGoogleSheetsClientFactory.java
@@ -18,49 +18,78 @@ package org.apache.camel.component.google.sheets;
 
 import com.google.api.client.auth.oauth2.Credential;
 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.http.HttpTransport;
 import com.google.api.client.http.javanet.NetHttpTransport;
 import com.google.api.client.json.jackson2.JacksonFactory;
 import com.google.api.services.sheets.v4.Sheets;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.util.ObjectHelper;
 
 public class BatchGoogleSheetsClientFactory implements 
GoogleSheetsClientFactory {
 
-    private final NetHttpTransport transport;
+    private final HttpTransport transport;
     private final JacksonFactory jsonFactory;
 
     public BatchGoogleSheetsClientFactory() {
-        this.transport = new NetHttpTransport();
-        this.jsonFactory = new JacksonFactory();
+        this(new NetHttpTransport(), new JacksonFactory());
+    }
+
+    public BatchGoogleSheetsClientFactory(HttpTransport httpTransport) {
+        this(httpTransport, new JacksonFactory());
+    }
+
+    public BatchGoogleSheetsClientFactory(HttpTransport httpTransport, 
JacksonFactory jacksonFactory) {
+        this.transport = httpTransport;
+        this.jsonFactory = jacksonFactory;
     }
 
     @Override
-    public Sheets makeClient(String clientId, String clientSecret, String 
applicationName, String refreshToken, String accessToken) {
+    public Sheets makeClient(String clientId,
+                             String clientSecret,
+                             String applicationName,
+                             String refreshToken,
+                             String accessToken) {
         if (clientId == null || clientSecret == null) {
             throw new IllegalArgumentException("clientId and clientSecret are 
required to create Google Sheets client.");
         }
+
         try {
-            Credential credential = authorize(clientId, clientSecret);
+            Credential credential = authorize(clientId, clientSecret, 
refreshToken, accessToken);
 
-            if (refreshToken != null && !"".equals(refreshToken)) {
-                credential.setRefreshToken(refreshToken);
-            }
-            if (accessToken != null && !"".equals(accessToken)) {
-                credential.setAccessToken(accessToken);
-            }
-            return new Sheets.Builder(transport, jsonFactory, credential)
-                                .setApplicationName(applicationName)
-                                .build();
+            Sheets.Builder clientBuilder = new Sheets.Builder(transport, 
jsonFactory, credential)
+                                                     
.setApplicationName(applicationName);
+            configure(clientBuilder);
+            return clientBuilder.build();
         } catch (Exception e) {
             throw new RuntimeCamelException("Could not create Google Sheets 
client.", e);
         }
     }
 
+    /**
+     * Subclasses may add customized configuration to client builder.
+     * @param clientBuilder
+     */
+    protected void configure(Sheets.Builder clientBuilder) {
+        clientBuilder.setRootUrl(Sheets.DEFAULT_ROOT_URL);
+    }
+
     // Authorizes the installed application to access user's protected data.
-    private Credential authorize(String clientId, String clientSecret) {
+    private Credential authorize(String clientId, String clientSecret, String 
refreshToken, String accessToken) {
         // authorize
-        return new GoogleCredential.Builder()
+        Credential credential = new GoogleCredential.Builder()
                         .setJsonFactory(jsonFactory)
                         .setTransport(transport)
-                        .setClientSecrets(clientId, clientSecret).build();
+                        .setClientSecrets(clientId, clientSecret)
+                        .build();
+
+        if (ObjectHelper.isNotEmpty(refreshToken)) {
+            credential.setRefreshToken(refreshToken);
+        }
+
+        if (ObjectHelper.isNotEmpty(accessToken)) {
+            credential.setAccessToken(accessToken);
+        }
+
+        return credential;
     }
 }
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
index 78b4e97..8186790 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsClientFactory.java
@@ -20,6 +20,10 @@ import com.google.api.services.sheets.v4.Sheets;
 
 public interface GoogleSheetsClientFactory {
 
-    Sheets makeClient(String clientId, String clientSecret, String 
applicationName, String refreshToken, String accessToken);
+    Sheets makeClient(String clientId,
+                      String clientSecret,
+                      String applicationName,
+                      String refreshToken,
+                      String accessToken);
 
 }
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
index a6d1768..f1e2e08 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsEndpoint.java
@@ -35,23 +35,32 @@ import 
org.apache.camel.util.component.ApiMethodPropertiesHelper;
 /**
  * The google-sheets component provides access to Google Sheets.
  */
-@UriEndpoint(firstVersion = "2.23.0", scheme = "google-sheets", title = 
"Google Sheets", 
-             syntax = "google-sheets:apiName/methodName", consumerClass = 
GoogleSheetsConsumer.class, consumerPrefix = "consumer", label = 
"api,cloud,sheets")
+@UriEndpoint(firstVersion = "2.23.0",
+        scheme = "google-sheets",
+        title = "Google Sheets",
+        syntax = "google-sheets:apiName/methodName",
+        consumerClass = GoogleSheetsConsumer.class,
+        consumerPrefix = "consumer",
+        label = "api,cloud,sheets")
 public class GoogleSheetsEndpoint extends 
AbstractApiEndpoint<GoogleSheetsApiName, GoogleSheetsConfiguration> {
 
-    @UriParam
-    private GoogleSheetsConfiguration configuration;
+    @UriParam(name = "configuration")
+    private GoogleSheetsConfiguration endpointConfiguration;
 
     private Object apiProxy;
 
-    public GoogleSheetsEndpoint(String uri, GoogleSheetsComponent component, 
GoogleSheetsApiName apiName, String methodName, GoogleSheetsConfiguration 
endpointConfiguration) {
+    public GoogleSheetsEndpoint(String uri,
+                                GoogleSheetsComponent component,
+                                GoogleSheetsApiName apiName,
+                                String methodName,
+                                GoogleSheetsConfiguration 
endpointConfiguration) {
         super(uri, component, apiName, methodName, 
GoogleSheetsApiCollection.getCollection().getHelper(apiName), 
endpointConfiguration);
-        this.configuration = endpointConfiguration;
+        this.endpointConfiguration = endpointConfiguration;
     }
 
     @Override
     public Producer createProducer() throws Exception {
-        return new 
org.apache.camel.component.google.sheets.GoogleSheetsProducer(this);
+        return new GoogleSheetsProducer(this);
     }
 
     @Override
@@ -79,19 +88,19 @@ public class GoogleSheetsEndpoint extends 
AbstractApiEndpoint<GoogleSheetsApiNam
     @Override
     protected void afterConfigureProperties() {
         switch (apiName) {
-        case SPREADSHEETS:
-            apiProxy = getClient().spreadsheets();
-            break;
-        case DATA:
-            apiProxy = getClient().spreadsheets().values();
-            break;
-        default:
-            throw new IllegalArgumentException("Invalid API name " + apiName);
+            case SPREADSHEETS:
+                apiProxy = getClient().spreadsheets();
+                break;
+            case DATA:
+                apiProxy = getClient().spreadsheets().values();
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid API name " + 
apiName);
         }
     }
 
     public Sheets getClient() {
-        return 
((GoogleSheetsComponent)getComponent()).getClient(configuration);
+        return 
((GoogleSheetsComponent)getComponent()).getClient(endpointConfiguration);
     }
 
     @Override
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java
index abc4060..e9419fc 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsProducer.java
@@ -39,7 +39,7 @@ public class GoogleSheetsProducer extends 
AbstractApiProducer<GoogleSheetsApiNam
 
     @Override
     protected Object doInvokeMethod(ApiMethod method, Map<String, Object> 
properties) throws RuntimeCamelException {
-        AbstractGoogleClientRequest<?> request = 
(AbstractGoogleClientRequest)super.doInvokeMethod(method, properties);
+        AbstractGoogleClientRequest<?> request = (AbstractGoogleClientRequest) 
super.doInvokeMethod(method, properties);
         try {
             TypeConverter typeConverter = 
getEndpoint().getCamelContext().getTypeConverter();
             for (Entry<String, Object> p : properties.entrySet()) {
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
index 26100cf..4ab0cd3 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/GoogleSheetsVerifierExtension.java
@@ -61,9 +61,12 @@ public class GoogleSheetsVerifierExtension extends 
DefaultComponentVerifierExten
         try {
             GoogleSheetsConfiguration configuration = setProperties(new 
GoogleSheetsConfiguration(), parameters);
             GoogleSheetsClientFactory clientFactory = new 
BatchGoogleSheetsClientFactory();
-            Sheets client = 
clientFactory.makeClient(configuration.getClientId(), 
configuration.getClientSecret(), configuration.getApplicationName(),
-                                                     
configuration.getRefreshToken(), configuration.getAccessToken());
-            
client.spreadsheets().get(Optional.ofNullable(parameters.get("spreadsheetId")).map(Object::toString).orElse(UUID.randomUUID().toString())).execute();
+            Sheets client = 
clientFactory.makeClient(configuration.getClientId(), 
configuration.getClientSecret(),
+                    configuration.getApplicationName(),
+                    configuration.getRefreshToken(), 
configuration.getAccessToken());
+            
client.spreadsheets().get(Optional.ofNullable(parameters.get("spreadsheetId"))
+                                              .map(Object::toString)
+                                              
.orElse(UUID.randomUUID().toString())).execute();
         } catch (Exception e) {
             ResultErrorBuilder errorBuilder = 
ResultErrorBuilder.withCodeAndDescription(VerificationError.StandardCode.AUTHENTICATION,
 e.getMessage())
                 .detail("google_sheets_exception_message", 
e.getMessage()).detail(VerificationError.ExceptionAttribute.EXCEPTION_CLASS, 
e.getClass().getName())
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
index feb9141..0727e33 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/internal/GoogleSheetsConstants.java
@@ -29,5 +29,7 @@ public final class GoogleSheetsConstants {
     /**
      * Prevent instantiation.
      */
-    private GoogleSheetsConstants() { }
+    private GoogleSheetsConstants() {
+        super();
+    }
 }
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
index 4de5222..7f949ed 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConfiguration.java
@@ -57,8 +57,8 @@ public class GoogleSheetsStreamConfiguration implements 
Cloneable {
     @UriParam
     private String spreadsheetId;
 
-    @UriParam(defaultValue = "10")
-    private int maxResults = 10;
+    @UriParam(defaultValue = "0")
+    private int maxResults;
 
     @UriParam
     private String range;
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
index 35b8815..7142953 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
@@ -85,17 +85,30 @@ public class GoogleSheetsStreamConsumer extends 
ScheduledBatchPollingConsumer {
                     for (ValueRange valueRange : response.getValueRanges()) {
                         AtomicInteger rangeIndex = new AtomicInteger(1);
                         AtomicInteger valueIndex = new AtomicInteger();
-                        valueRange.getValues().stream()
-                            .limit(getConfiguration().getMaxResults())
-                            .map(values -> 
getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(), 
valueRange.getRange(), valueRange.getMajorDimension(), values))
-                            .forEach(answer::add);
+                        if (getConfiguration().getMaxResults() > 0) {
+                            valueRange.getValues().stream()
+                                    .limit(getConfiguration().getMaxResults())
+                                    .map(values -> 
getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(), 
valueRange.getRange(), valueRange.getMajorDimension(), values))
+                                    .forEach(answer::add);
+                        } else {
+                            valueRange.getValues().stream()
+                                    .map(values -> 
getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(), 
valueRange.getRange(), valueRange.getMajorDimension(), values))
+                                    .forEach(answer::add);
+                        }
                         rangeIndex.incrementAndGet();
                     }
                 } else {
                     AtomicInteger rangeIndex = new AtomicInteger();
                     response.getValueRanges()
                             .stream()
-                            .limit(getConfiguration().getMaxResults())
+                            .peek(valueRange -> {
+                                if (getConfiguration().getMaxResults() > 0) {
+                                    valueRange.setValues(valueRange.getValues()
+                                            .stream()
+                                            
.limit(getConfiguration().getMaxResults())
+                                            .collect(Collectors.toList()));
+                                }
+                            })
                             .map(valueRange -> 
getEndpoint().createExchange(rangeIndex.incrementAndGet(), valueRange))
                             .forEach(answer::add);
                 }
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
index d52905c..f1e5eb7 100644
--- 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/AbstractGoogleSheetsTestSupport.java
@@ -24,6 +24,9 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Random;
 
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.sheets.v4.Sheets;
 import com.google.api.services.sheets.v4.model.Sheet;
 import com.google.api.services.sheets.v4.model.SheetProperties;
 import com.google.api.services.sheets.v4.model.Spreadsheet;
@@ -31,8 +34,12 @@ import 
com.google.api.services.sheets.v4.model.SpreadsheetProperties;
 import com.google.api.services.sheets.v4.model.ValueRange;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelExecutionException;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsConstants;
+import 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServer;
+import 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerRule;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.apache.camel.util.IntrospectionSupport;
+import org.junit.ClassRule;
 
 /**
  * Abstract base class for GoogleSheets Integration tests generated by Camel
@@ -45,13 +52,16 @@ public class AbstractGoogleSheetsTestSupport extends 
CamelTestSupport {
 
     private Spreadsheet spreadsheet;
 
+    @ClassRule
+    public static GoogleSheetsApiTestServerRule googleSheetsApiTestServerRule 
= new GoogleSheetsApiTestServerRule(TEST_OPTIONS_PROPERTIES);
+
     /**
      * Create test spreadsheet that is used throughout all tests.
      */
     private void createTestSpreadsheet() {
         Spreadsheet spreadsheet = new Spreadsheet();
         SpreadsheetProperties spreadsheetProperties = new 
SpreadsheetProperties();
-        spreadsheetProperties.setTitle("camel-sheets-" + Math.abs(new 
Random().nextInt()));
+        spreadsheetProperties.setTitle("camel-sheets-" + new 
Random().nextInt(Integer.MAX_VALUE));
 
         spreadsheet.setProperties(spreadsheetProperties);
 
@@ -78,12 +88,12 @@ public class AbstractGoogleSheetsTestSupport extends 
CamelTestSupport {
 
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
spreadsheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
spreadsheet.getSpreadsheetId());
         // parameter type is String
-        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "range", 
TEST_SHEET + "!A1:B2");
 
         // parameter type is String
-        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + 
"valueInputOption", "USER_ENTERED");
 
         requestBodyAndHeaders("google-sheets://data/update?inBody=values", 
valueRange, headers);
     }
@@ -96,8 +106,20 @@ public class AbstractGoogleSheetsTestSupport extends 
CamelTestSupport {
         final GoogleSheetsConfiguration configuration = new 
GoogleSheetsConfiguration();
         IntrospectionSupport.setProperties(configuration, getTestOptions());
 
-        // add GoogleSheetsComponent to Camel context
+        // add GoogleSheetsComponent to Camel context and use localhost url
         final GoogleSheetsComponent component = new 
GoogleSheetsComponent(context);
+        component.setClientFactory(new BatchGoogleSheetsClientFactory(
+                                            new NetHttpTransport.Builder()
+                                                    
.trustCertificatesFromJavaKeyStore(
+                                                            
getClass().getResourceAsStream("/" + 
GoogleSheetsApiTestServerRule.SERVER_KEYSTORE),
+                                                            
GoogleSheetsApiTestServerRule.SERVER_KEYSTORE_PASSWORD)
+                                                    .build(),
+                                            new JacksonFactory()) {
+            @Override
+            protected void configure(Sheets.Builder clientBuilder) {
+                
clientBuilder.setRootUrl(String.format("https://localhost:%s/";, 
googleSheetsApiTestServerRule.getServerPort()));
+            }
+        });
         component.setConfiguration(configuration);
         context.addComponent("google-sheets", component);
 
@@ -148,17 +170,16 @@ public class AbstractGoogleSheetsTestSupport extends 
CamelTestSupport {
         return spreadsheet;
     }
 
-    public Spreadsheet getSpreadsheetWithTestData() {
-        if (spreadsheet == null) {
-            createTestSpreadsheet();
-        }
-
+    public Spreadsheet applyTestData(Spreadsheet spreadsheet) {
         createTestData();
-
         return spreadsheet;
     }
 
     public void setSpreadsheet(Spreadsheet sheet) {
         this.spreadsheet = sheet;
     }
+
+    public GoogleSheetsApiTestServer getGoogleApiTestServer() {
+        return googleSheetsApiTestServerRule.getGoogleApiTestServer();
+    }
 }
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
index 800d023..b42fbaa 100644
--- 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsIntegrationTest.java
@@ -27,14 +27,16 @@ import com.google.api.services.sheets.v4.model.Request;
 import com.google.api.services.sheets.v4.model.Spreadsheet;
 import com.google.api.services.sheets.v4.model.SpreadsheetProperties;
 import 
com.google.api.services.sheets.v4.model.UpdateSpreadsheetPropertiesRequest;
-
 import org.apache.camel.builder.RouteBuilder;
 import 
org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsConstants;
 import 
org.apache.camel.component.google.sheets.internal.SheetsSpreadsheetsApiMethod;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerAssert.assertThatGoogleApi;
+
 /**
  * Test class for {@link 
com.google.api.services.sheets.v4.Sheets.Spreadsheets} APIs.
  */
@@ -45,14 +47,18 @@ public class SheetsSpreadsheetsIntegrationTest extends 
AbstractGoogleSheetsTestS
 
     @Test
     public void testCreate() throws Exception {
-        String title = "camel-sheets-" + Math.abs(new Random().nextInt());
+        String title = "camel-sheets-" + new 
Random().nextInt(Integer.MAX_VALUE);
         Spreadsheet sheetToCreate = new Spreadsheet();
         SpreadsheetProperties sheetProperties = new SpreadsheetProperties();
         sheetProperties.setTitle(title);
 
         sheetToCreate.setProperties(sheetProperties);
 
-        // using com.google.api.services.sheets.v4.model.Spreadsheet message 
body for single parameter "content"
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasTitle(title)
+                .andReturnRandomSpreadsheet();
+
         final Spreadsheet result = requestBody("direct://CREATE", 
sheetToCreate);
 
         assertNotNull("create result is null", result);
@@ -63,8 +69,17 @@ public class SheetsSpreadsheetsIntegrationTest extends 
AbstractGoogleSheetsTestS
 
     @Test
     public void testGet() throws Exception {
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnRandomSpreadsheet();
+
         Spreadsheet testSheet = getSpreadsheet();
 
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .getSpreadsheetRequest(testSheet.getSpreadsheetId())
+                .andReturnSpreadsheet(testSheet);
+
         // using String message body for single parameter "spreadsheetId"
         final Spreadsheet result = requestBody("direct://GET", 
testSheet.getSpreadsheetId());
 
@@ -76,14 +91,24 @@ public class SheetsSpreadsheetsIntegrationTest extends 
AbstractGoogleSheetsTestS
 
     @Test
     public void testBatchUpdate() throws Exception {
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnRandomSpreadsheet();
+
         Spreadsheet testSheet = getSpreadsheet();
         String updateTitle = "updated-" + testSheet.getProperties().getTitle();
 
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .batchUpdateSpreadsheetRequest(testSheet.getSpreadsheetId())
+                .updateTitle(updateTitle)
+                .andReturnUpdated();
+
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
testSheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
testSheet.getSpreadsheetId());
         // parameter type is 
com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest
-        headers.put("CamelGoogleSheets.batchUpdateSpreadsheetRequest", new 
BatchUpdateSpreadsheetRequest()
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + 
"batchUpdateSpreadsheetRequest", new BatchUpdateSpreadsheetRequest()
                                                                             
.setIncludeSpreadsheetInResponse(true)
                                                                             
.setRequests(Collections.singletonList(new 
Request().setUpdateSpreadsheetProperties(new 
UpdateSpreadsheetPropertiesRequest()
                                                                                
     .setProperties(new SpreadsheetProperties().setTitle(updateTitle))
@@ -91,7 +116,7 @@ public class SheetsSpreadsheetsIntegrationTest extends 
AbstractGoogleSheetsTestS
 
         final BatchUpdateSpreadsheetResponse result = 
requestBodyAndHeaders("direct://BATCHUPDATE", null, headers);
 
-        assertNotNull("batchUpdate result in null", result);
+        assertNotNull("batchUpdate result is null", result);
         assertEquals(updateTitle, 
result.getUpdatedSpreadsheet().getProperties().getTitle());
 
         LOG.debug("batchUpdate: " + result);
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
index 0075f7a..405ae7a 100644
--- 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/SheetsSpreadsheetsValuesIntegrationTest.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import com.google.api.services.sheets.v4.model.AppendValuesResponse;
 import com.google.api.services.sheets.v4.model.ClearValuesRequest;
@@ -28,14 +29,17 @@ import 
com.google.api.services.sheets.v4.model.ClearValuesResponse;
 import com.google.api.services.sheets.v4.model.Spreadsheet;
 import com.google.api.services.sheets.v4.model.UpdateValuesResponse;
 import com.google.api.services.sheets.v4.model.ValueRange;
-
 import org.apache.camel.builder.RouteBuilder;
 import 
org.apache.camel.component.google.sheets.internal.GoogleSheetsApiCollection;
+import org.apache.camel.component.google.sheets.internal.GoogleSheetsConstants;
 import 
org.apache.camel.component.google.sheets.internal.SheetsSpreadsheetsValuesApiMethod;
+import org.apache.camel.util.ObjectHelper;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerAssert.assertThatGoogleApi;
+
 /**
  * Test class for {@link 
com.google.api.services.sheets.v4.Sheets.Spreadsheets.Values} APIs.
  */
@@ -46,44 +50,63 @@ public class SheetsSpreadsheetsValuesIntegrationTest 
extends AbstractGoogleSheet
 
     @Test
     public void testGet() throws Exception {
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnRandomSpreadsheet();
+
         Spreadsheet testSheet = getSpreadsheet();
 
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .getValuesRequest(testSheet.getSpreadsheetId(), TEST_SHEET + 
"!A1:B2")
+                .andReturnValues(Collections.emptyList());
+
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
testSheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
testSheet.getSpreadsheetId());
         // parameter type is String
-        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "range", 
TEST_SHEET + "!A1:B2");
 
         final ValueRange result = requestBodyAndHeaders("direct://GET", null, 
headers);
 
         assertNotNull("get result is null", result);
         assertEquals(TEST_SHEET + "!A1:B2", result.getRange());
-        assertNull("expected empty value range but found entries", 
result.getValues());
+        assertTrue("expected empty value range but found entries", 
ObjectHelper.isEmpty(result.getValues()));
 
         LOG.debug("get: " + result);
     }
 
     @Test
     public void testUpdate() throws Exception {
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnRandomSpreadsheet();
+
         Spreadsheet testSheet = getSpreadsheet();
 
         List<List<Object>> data = Arrays.asList(
                 Arrays.asList("A1", "B1"),
                 Arrays.asList("A2", "B2")
         );
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .updateValuesRequest(testSheet.getSpreadsheetId(), TEST_SHEET 
+ "!A1:B2", data)
+                .andReturnUpdateResponse();
+
         ValueRange values = new ValueRange();
         values.setValues(data);
 
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
testSheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
testSheet.getSpreadsheetId());
         // parameter type is String
-        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "range", 
TEST_SHEET + "!A1:B2");
         // parameter type is com.google.api.services.sheets.v4.model.ValueRange
-        headers.put("CamelGoogleSheets.values", values);
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "values", values);
 
         // parameter type is String
-        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + 
"valueInputOption", "USER_ENTERED");
 
         final UpdateValuesResponse result = 
requestBodyAndHeaders("direct://UPDATE", null, headers);
 
@@ -98,18 +121,29 @@ public class SheetsSpreadsheetsValuesIntegrationTest 
extends AbstractGoogleSheet
 
     @Test
     public void testAppend() throws Exception {
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnRandomSpreadsheet();
+
         Spreadsheet testSheet = getSpreadsheet();
 
+        List<List<Object>> data = 
Collections.singletonList(Arrays.asList("A10", "B10", "C10"));
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .appendValuesRequest(testSheet.getSpreadsheetId(), TEST_SHEET 
+ "!A10", data)
+                .andReturnAppendResponse(TEST_SHEET + "!A10:C10");
+
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
testSheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
testSheet.getSpreadsheetId());
         // parameter type is String
-        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A10");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "range", 
TEST_SHEET + "!A10");
         // parameter type is com.google.api.services.sheets.v4.model.ValueRange
-        headers.put("CamelGoogleSheets.values", new 
ValueRange().setValues(Collections.singletonList(Arrays.asList("A10", "B10", 
"C10"))));
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "values", new 
ValueRange().setValues(data));
 
         // parameter type is String
-        headers.put("CamelGoogleSheets.valueInputOption", "USER_ENTERED");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + 
"valueInputOption", "USER_ENTERED");
 
         final AppendValuesResponse result = 
requestBodyAndHeaders("direct://APPEND", null, headers);
 
@@ -124,15 +158,32 @@ public class SheetsSpreadsheetsValuesIntegrationTest 
extends AbstractGoogleSheet
 
     @Test
     public void testClear() throws Exception {
-        Spreadsheet testSheet = getSpreadsheetWithTestData();
+        String spreadsheetId = UUID.randomUUID().toString();
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnSpreadsheet(spreadsheetId);
+
+        Spreadsheet testSheet = getSpreadsheet();
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .updateValuesRequest(spreadsheetId, TEST_SHEET + "!A1:B2", 
Arrays.asList(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2")))
+                .andReturnUpdateResponse();
+
+        applyTestData(testSheet);
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .clearValuesRequest(testSheet.getSpreadsheetId(), TEST_SHEET + 
"!A1:B2")
+                .andReturnClearResponse(TEST_SHEET + "!A1:B2");
 
         final Map<String, Object> headers = new HashMap<>();
         // parameter type is String
-        headers.put("CamelGoogleSheets.spreadsheetId", 
testSheet.getSpreadsheetId());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "spreadsheetId", 
testSheet.getSpreadsheetId());
         // parameter type is String
-        headers.put("CamelGoogleSheets.range", TEST_SHEET + "!A1:B2");
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + "range", 
TEST_SHEET + "!A1:B2");
         // parameter type is 
com.google.api.services.sheets.v4.model.ClearValuesRequest
-        headers.put("CamelGoogleSheets.clearValuesRequest", new 
ClearValuesRequest());
+        headers.put(GoogleSheetsConstants.PROPERTY_PREFIX + 
"clearValuesRequest", new ClearValuesRequest());
 
         final ClearValuesResponse result = 
requestBodyAndHeaders("direct://CLEAR", null, headers);
 
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServer.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServer.java
new file mode 100644
index 0000000..00bb91c
--- /dev/null
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServer.java
@@ -0,0 +1,354 @@
+/*
+ * 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.component.google.sheets.server;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.zip.GZIPInputStream;
+
+import com.consol.citrus.Citrus;
+import com.consol.citrus.dsl.runner.DefaultTestRunner;
+import com.consol.citrus.dsl.runner.TestRunner;
+import com.consol.citrus.exceptions.CitrusRuntimeException;
+import com.consol.citrus.http.server.HttpServer;
+import com.consol.citrus.http.server.HttpServerBuilder;
+import com.consol.citrus.http.servlet.GzipHttpServletResponseWrapper;
+import com.consol.citrus.http.servlet.RequestCachingServletFilter;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
+import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
+import org.springframework.security.oauth2.provider.AuthorizationRequest;
+import org.springframework.security.oauth2.provider.ClientDetails;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import 
org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
+import 
org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
+import org.springframework.security.oauth2.provider.client.BaseClientDetails;
+import 
org.springframework.security.oauth2.provider.client.InMemoryClientDetailsService;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+import 
org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class GoogleSheetsApiTestServer {
+
+    private static Citrus citrus = Citrus.newInstance();
+
+    private final HttpServer httpServer;
+    private TestRunner runner;
+
+    /**
+     * Prevent direct instantiation.
+     */
+    private GoogleSheetsApiTestServer(HttpServer httpServer) {
+        super();
+        this.httpServer = httpServer;
+    }
+
+    /**
+     * Initialize new test run.
+     */
+    public void init() {
+        runner = new DefaultTestRunner(citrus.getApplicationContext(), 
citrus.createTestContext());
+    }
+
+    /**
+     * Stop and reset current test run if any.
+     */
+    public void reset() {
+        if (runner != null) {
+            runner.purgeEndpoints(action -> action.endpoint(httpServer));
+            runner.stop();
+        }
+    }
+
+    /**
+     * Obtains the httpServer.
+     * @return
+     */
+    public HttpServer getHttpServer() {
+        return httpServer;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        httpServer.afterPropertiesSet();
+    }
+
+    public TestRunner getRunner() {
+        return runner;
+    }
+
+    /**
+     * Builder builds server instance from given http server builder adding 
more setting options in fluent
+     * builder pattern style.
+     */
+    public static class Builder {
+        private final HttpServerBuilder serverBuilder;
+
+        private Path keyStorePath;
+        private String keyStorePassword;
+        private int securePort = 8443;
+
+        private String basePath = "";
+
+        private String clientId;
+        private String clientSecret;
+
+        private String accessToken;
+        private String refreshToken;
+
+        public Builder(HttpServerBuilder serverBuilder) {
+            this.serverBuilder = serverBuilder;
+        }
+
+        public Builder securePort(int securePort) {
+            this.securePort = securePort;
+            return this;
+        }
+
+        public Builder keyStorePath(Path keyStorePath) {
+            this.keyStorePath = keyStorePath;
+            return this;
+        }
+
+        public Builder keyStorePassword(String keyStorePass) {
+            this.keyStorePassword = keyStorePass;
+            return this;
+        }
+
+        public Builder basePath(String basePath) {
+            this.basePath = basePath;
+            return this;
+        }
+
+        public Builder clientId(String clientId) {
+            this.clientId = clientId;
+            return this;
+        }
+
+        public Builder clientSecret(String clientSecret) {
+            this.clientSecret = clientSecret;
+            return this;
+        }
+
+        public Builder accessToken(String accessToken) {
+            this.accessToken = accessToken;
+            return this;
+        }
+
+        public Builder refreshToken(String refreshToken) {
+            this.refreshToken = refreshToken;
+            return this;
+        }
+
+        public GoogleSheetsApiTestServer build() throws Exception {
+            SslContextFactory sslContextFactory = new SslContextFactory(true);
+            
sslContextFactory.setKeyStorePath(keyStorePath.toAbsolutePath().toString());
+            sslContextFactory.setKeyStorePassword(keyStorePassword);
+
+            HttpConfiguration parent = new HttpConfiguration();
+            parent.setSecureScheme("https");
+            parent.setSecurePort(securePort);
+            HttpConfiguration httpConfiguration = new 
HttpConfiguration(parent);
+            httpConfiguration.setCustomizers(Collections.singletonList(new 
SecureRequestCustomizer()));
+
+            ServerConnector sslConnector = new ServerConnector(new 
org.eclipse.jetty.server.Server(),
+                    new SslConnectionFactory(sslContextFactory, "http/1.1"),
+                    new HttpConnectionFactory(httpConfiguration));
+            sslConnector.setPort(securePort);
+
+            serverBuilder.connector(sslConnector);
+
+            Map<String, Filter> filterMap = new LinkedHashMap<>();
+            filterMap.put("request-caching-filter", new 
RequestCachingServletFilter());
+            filterMap.put("gzip-filter", new GzipServletFilter());
+            filterMap.put("oauth2-filter", oauth2Filter());
+
+            Map<String, String> filterMapings = new LinkedHashMap<>();
+            filterMapings.put("oauth2-filter", "/" + 
Optional.ofNullable(basePath).map(path -> path + "/*").orElse("*"));
+            serverBuilder.filterMappings(filterMapings);
+
+            serverBuilder.filters(filterMap);
+
+            serverBuilder.applicationContext(citrus.getApplicationContext());
+
+            GoogleSheetsApiTestServer server = new 
GoogleSheetsApiTestServer(serverBuilder.build());
+            server.afterPropertiesSet();
+            return server;
+        }
+
+        private Filter oauth2Filter() {
+            BaseClientDetails clientDetails = new BaseClientDetails();
+            clientDetails.setClientId(clientId);
+            clientDetails.setClientSecret(clientSecret);
+            clientDetails.setAccessTokenValiditySeconds(3000);
+            clientDetails.setAutoApproveScopes(Arrays.asList("read", "write"));
+            clientDetails.setScope(Arrays.asList("read", "write"));
+            clientDetails.setAuthorities(Arrays.asList(new 
SimpleGrantedAuthority("client_credentials"),
+                                                        new 
SimpleGrantedAuthority("authorization_code"),
+                                                        new 
SimpleGrantedAuthority("password"),
+                                                        new 
SimpleGrantedAuthority("refresh_token")));
+
+            OAuth2AuthenticationProcessingFilter filter = new 
OAuth2AuthenticationProcessingFilter();
+            OAuth2AuthenticationManager oauth2AuthenticationManager = new 
OAuth2AuthenticationManager();
+
+            InMemoryClientDetailsService clientDetailsService = new 
InMemoryClientDetailsService();
+            Map<String, ClientDetails> clientDetailsStore = new HashMap<>();
+            clientDetailsStore.put(clientId, clientDetails);
+            clientDetailsService.setClientDetailsStore(clientDetailsStore);
+            
oauth2AuthenticationManager.setClientDetailsService(clientDetailsService);
+
+            InMemoryTokenStore tokenStore = new InMemoryTokenStore();
+            AuthorizationRequest authorizationRequest = new 
AuthorizationRequest();
+            authorizationRequest.setClientId(clientDetails.getClientId());
+            
authorizationRequest.setAuthorities(clientDetails.getAuthorities());
+            authorizationRequest.setApproved(true);
+
+            OAuth2Authentication authentication = new 
OAuth2Authentication(authorizationRequest.createOAuth2Request(), null);
+
+            tokenStore.storeAccessToken(new 
DefaultOAuth2AccessToken(accessToken), authentication);
+            tokenStore.storeRefreshToken(new 
DefaultOAuth2RefreshToken(refreshToken), authentication);
+
+            DefaultTokenServices tokenServices = new DefaultTokenServices();
+            tokenServices.setTokenStore(tokenStore);
+            tokenServices.setClientDetailsService(clientDetailsService);
+            tokenServices.setSupportRefreshToken(true);
+            oauth2AuthenticationManager.setTokenServices(tokenServices);
+
+            filter.setAuthenticationManager(oauth2AuthenticationManager);
+            return filter;
+        }
+    }
+
+    private static class GzipServletFilter extends OncePerRequestFilter {
+        @Override
+        protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse response,
+                                        FilterChain filterChain) throws 
ServletException, IOException {
+            HttpServletRequest filteredRequest = request;
+            HttpServletResponse filteredResponse = response;
+
+            String contentEncoding = 
request.getHeader(HttpHeaders.CONTENT_ENCODING);
+            if (contentEncoding != null && contentEncoding.contains("gzip")) {
+                filteredRequest = new GzipHttpServletRequestWrapper(request);
+            }
+
+            String acceptEncoding = 
request.getHeader(HttpHeaders.ACCEPT_ENCODING);
+            if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
+                filteredResponse = new 
GzipHttpServletResponseWrapper(response);
+            }
+
+            filterChain.doFilter(filteredRequest, filteredResponse);
+
+            if (filteredResponse instanceof GzipHttpServletResponseWrapper) {
+                ((GzipHttpServletResponseWrapper) filteredResponse).finish();
+            }
+        }
+    }
+
+    private static class GzipHttpServletRequestWrapper extends 
HttpServletRequestWrapper {
+        /**
+         * Constructs a request adaptor wrapping the given request.
+         *
+         * @param request
+         * @throws IllegalArgumentException if the request is null
+         */
+        public GzipHttpServletRequestWrapper(HttpServletRequest request) {
+            super(request);
+        }
+
+        @Override
+        public ServletInputStream getInputStream() throws IOException {
+            return new GzipServletInputStream(getRequest());
+        }
+
+        /**
+         * Gzip enabled servlet input stream.
+         */
+        private static class GzipServletInputStream extends ServletInputStream 
{
+            private final GZIPInputStream gzipStream;
+
+            /**
+             * Default constructor using wrapped input stream.
+             *
+             * @param request
+             * @throws IOException
+             */
+            public GzipServletInputStream(ServletRequest request) throws 
IOException {
+                super();
+                gzipStream = new GZIPInputStream(request.getInputStream());
+            }
+
+            @Override
+            public boolean isFinished() {
+                try {
+                    return gzipStream.available() == 0;
+                } catch (IOException e) {
+                    throw new CitrusRuntimeException("Failed to check gzip 
intput stream availability", e);
+                }
+            }
+
+            @Override
+            public boolean isReady() {
+                return true;
+            }
+
+            @Override
+            public void setReadListener(final ReadListener readListener) {
+                throw new UnsupportedOperationException("Unsupported 
operation");
+            }
+
+            @Override
+            public int read() {
+                try {
+                    return gzipStream.read();
+                } catch (IOException e) {
+                    throw new CitrusRuntimeException("Failed to read gzip 
input stream", e);
+                }
+            }
+
+            @Override
+            public int read(byte[] b) throws IOException {
+                return gzipStream.read(b);
+            }
+
+            @Override
+            public int read(byte[] b, int off, int len) throws IOException {
+                return gzipStream.read(b, off, len);
+            }
+        }
+    }
+}
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerAssert.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerAssert.java
new file mode 100644
index 0000000..a89edae
--- /dev/null
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerAssert.java
@@ -0,0 +1,405 @@
+/*
+ * 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.component.google.sheets.server;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+import com.consol.citrus.message.MessageType;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.ValueRange;
+import org.apache.camel.util.ObjectHelper;
+import org.assertj.core.api.AbstractAssert;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+public class GoogleSheetsApiTestServerAssert extends 
AbstractAssert<GoogleSheetsApiTestServerAssert, GoogleSheetsApiTestServer> {
+
+    private ObjectMapper mapper = new ObjectMapper()
+                
.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY,
 JsonInclude.Include.NON_EMPTY))
+                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+                .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
+                .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
+                .disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
+
+    private GoogleSheetsApiTestServerAssert(GoogleSheetsApiTestServer server) {
+        super(server, GoogleSheetsApiTestServerAssert.class);
+    }
+
+    /**
+     * A fluent entry point to the assertion class.
+     * @param server the target server to perform assertions to.
+     * @return
+     */
+    public static GoogleSheetsApiTestServerAssert 
assertThatGoogleApi(GoogleSheetsApiTestServer server) {
+        return new GoogleSheetsApiTestServerAssert(server);
+    }
+
+    public GetSpreadsheetAssert getSpreadsheetRequest(String spreadsheetId) {
+        return new GetSpreadsheetAssert(spreadsheetId);
+    }
+
+    public void isRunning() {
+        isRunning(5000, TimeUnit.MILLISECONDS);
+    }
+
+    public void isRunning(long timeout, TimeUnit timeUnit) {
+        ScheduledFuture<?> schedule = null;
+        try {
+            CompletableFuture<Boolean> runningProbe = new 
CompletableFuture<>();
+            schedule = 
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
+                if (actual.getHttpServer().isRunning()) {
+                    runningProbe.complete(true);
+                }
+            }, 0, timeout / 10, timeUnit);
+
+            runningProbe.get(timeout, timeUnit);
+        } catch (InterruptedException | ExecutionException | TimeoutException 
e) {
+            throw new IllegalStateException(e);
+        } finally {
+            Optional.ofNullable(schedule)
+                .ifPresent(future -> future.cancel(true));
+        }
+    }
+
+    public class GetSpreadsheetAssert {
+        GetSpreadsheetAssert(String spreadsheetId) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+        }
+
+        public void andReturnSpreadsheet(Spreadsheet spreadsheet) throws 
IOException {
+            String spreadsheetJson = spreadsheet.toPrettyString();
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .get("/v4/spreadsheets/${spreadsheetId}")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload(spreadsheetJson))
+            );
+        }
+    }
+
+    public ClearValuesAssert clearValuesRequest(String spreadsheetId, String 
range) {
+        return new ClearValuesAssert(spreadsheetId, range);
+    }
+
+    public class ClearValuesAssert {
+        ClearValuesAssert(String spreadsheetId, String range) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("range", range);
+        }
+
+        public void andReturnClearResponse(String clearedRange) throws 
IOException {
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    
.post("/v4/spreadsheets/${spreadsheetId}/values/${range}:clear")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload("{" +
+                            "\"spreadsheetId\": \"${spreadsheetId}\"," +
+                            "\"clearedRange\": \"" + clearedRange + "\"" +
+                        "}"))
+            );
+        }
+    }
+
+    public UpdateValuesAssert updateValuesRequest(String spreadsheetId, String 
range, List<List<Object>> data) {
+        return new UpdateValuesAssert(spreadsheetId, range, data);
+    }
+
+    public class UpdateValuesAssert {
+        private final List<List<Object>> data;
+
+        UpdateValuesAssert(String spreadsheetId, String range, 
List<List<Object>> data) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("range", range);
+            this.data = data;
+        }
+
+        public void andReturnUpdateResponse() throws IOException {
+            String valuesJson = mapper.writer().writeValueAsString(data);
+
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .put("/v4/spreadsheets/${spreadsheetId}/values/${range}")
+                    .validate("$.values.toString()", valuesJson)),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload("{" +
+                            "\"spreadsheetId\": \"${spreadsheetId}\"," +
+                            "\"updatedRange\": \"${range}\"," +
+                            "\"updatedRows\": " + data.size() + "," +
+                            "\"updatedColumns\": " + 
Optional.ofNullable(data.get(0)).map(Collection::size).orElse(0) + "," +
+                            "\"updatedCells\": " + data.size() * 
Optional.ofNullable(data.get(0)).map(Collection::size).orElse(0) +
+                        "}"))
+            );
+        }
+    }
+
+    public AppendValuesAssert appendValuesRequest(String spreadsheetId, String 
range, List<List<Object>> data) {
+        return new AppendValuesAssert(spreadsheetId, range, data);
+    }
+
+    public class AppendValuesAssert {
+        private final List<List<Object>> data;
+
+        AppendValuesAssert(String spreadsheetId, String range, 
List<List<Object>> data) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("range", range);
+            this.data = data;
+        }
+
+        public void andReturnAppendResponse(String updatedRange) throws 
IOException {
+            String valuesJson = mapper.writer().writeValueAsString(data);
+
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    
.post("/v4/spreadsheets/${spreadsheetId}/values/${range}:append")
+                    .validate("$.values.toString()", valuesJson)),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload("{" +
+                        "\"spreadsheetId\": \"${spreadsheetId}\"," +
+                        "\"updates\":" +
+                            "{" +
+                                "\"spreadsheetId\": \"${spreadsheetId}\"," +
+                                "\"updatedRange\": \"" + updatedRange + "\"," +
+                                "\"updatedRows\": " + data.size() + "," +
+                                "\"updatedColumns\": " + 
Optional.ofNullable(data.get(0)).map(Collection::size).orElse(0) + "," +
+                                "\"updatedCells\": " + data.size() * 
Optional.ofNullable(data.get(0)).map(Collection::size).orElse(0) +
+                            "}" +
+                        "}"))
+            );
+        }
+    }
+
+    public GetValuesAssert getValuesRequest(String spreadsheetId, String 
range) {
+        return new GetValuesAssert(spreadsheetId, range);
+    }
+
+    public class GetValuesAssert {
+        GetValuesAssert(String spreadsheetId, String range) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("range", range);
+        }
+
+        public void andReturnValueRange(ValueRange valueRange) throws 
IOException {
+            String valueJson = valueRange.toPrettyString();
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .get("/v4/spreadsheets/${spreadsheetId}/values/${range}")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload(valueJson))
+            );
+        }
+
+        public void andReturnValues(List<List<Object>> data) throws 
JsonProcessingException {
+            String valueRangeJson;
+            if (ObjectHelper.isEmpty(data)) {
+                valueRangeJson = "{" +
+                        "\"range\": \"${range}\"," +
+                        "\"majorDimension\": \"ROWS\"" +
+                    "}";
+            } else {
+                valueRangeJson = "{" +
+                        "\"range\": \"${range}\"," +
+                        "\"majorDimension\": \"ROWS\"," +
+                        "\"values\":" + 
mapper.writer().writeValueAsString(data) +
+                    "}";
+            }
+
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .get("/v4/spreadsheets/${spreadsheetId}/values/${range}")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload(valueRangeJson))
+            );
+        }
+    }
+
+    public BatchGetValuesAssert batchGetValuesRequest(String spreadsheetId, 
String range) {
+        return new BatchGetValuesAssert(spreadsheetId, range);
+    }
+
+    public class BatchGetValuesAssert {
+        BatchGetValuesAssert(String spreadsheetId, String range) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("range", range);
+        }
+
+        public void andReturnValues(List<List<Object>> data) throws 
JsonProcessingException {
+            String valueRangeJson;
+            if (ObjectHelper.isEmpty(data)) {
+                valueRangeJson = "{\"spreadsheetId\": \"${spreadsheetId}\"," +
+                    "\"valueRanges\": [" +
+                        "{" +
+                            "\"range\": \"${range}\"," +
+                            "\"majorDimension\": \"ROWS\"" +
+                        "}" +
+                    "]}";
+            } else {
+                valueRangeJson = "{\"spreadsheetId\": \"${spreadsheetId}\"," +
+                    "\"valueRanges\": [" +
+                        "{" +
+                            "\"range\": \"${range}\"," +
+                            "\"majorDimension\": \"ROWS\"," +
+                            "\"values\":" + 
mapper.writer().writeValueAsString(data) +
+                        "}" +
+                    "]}";
+            }
+
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .get("/v4/spreadsheets/${spreadsheetId}/values:batchGet")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    .payload(valueRangeJson))
+            );
+        }
+    }
+
+    public CreateSpreadsheetAssert createSpreadsheetRequest() {
+        return new CreateSpreadsheetAssert();
+    }
+
+    public class CreateSpreadsheetAssert {
+        private String title = "@ignore@";
+        private String sheetTitle;
+
+        public CreateSpreadsheetAssert hasTitle(String title) {
+            this.title = title;
+            return this;
+        }
+
+        public CreateSpreadsheetAssert hasSheetTitle(String sheetTitle) {
+            this.sheetTitle = sheetTitle;
+            return this;
+        }
+
+        public void andReturnRandomSpreadsheet() {
+            andReturnSpreadsheet("citrus:randomString(44)");
+        }
+
+        public void andReturnSpreadsheet(String spreadsheetId) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+            actual.getRunner().createVariable("title", title);
+
+            String spreadsheetJson;
+            if (ObjectHelper.isNotEmpty(sheetTitle)) {
+                actual.getRunner().createVariable("sheetTitle", sheetTitle);
+                spreadsheetJson = 
"{\"properties\":{\"title\":\"${title}\"},\"sheets\":[{\"properties\":{\"title\":\"${sheetTitle}\"}}]}";
+            } else {
+                spreadsheetJson = "{\"properties\":{\"title\":\"${title}\"}}";
+            }
+
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .post("/v4/spreadsheets")
+                    .name("create.request")
+                    .messageType(MessageType.JSON)
+                    .payload(spreadsheetJson)),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    
.payload("{\"spreadsheetId\":\"${spreadsheetId}\",\"properties\":{\"title\":\"citrus:jsonPath(citrus:message(create.request.payload()),
 '$.properties.title')\"}}"))
+            );
+        }
+    }
+
+    public BatchUpdateSpreadsheetAssert batchUpdateSpreadsheetRequest(String 
spreadsheetId) {
+        return new BatchUpdateSpreadsheetAssert(spreadsheetId);
+    }
+
+    public class BatchUpdateSpreadsheetAssert {
+        private List<String> fields = new ArrayList<>();
+
+        BatchUpdateSpreadsheetAssert(String spreadsheetId) {
+            actual.getRunner().createVariable("spreadsheetId", spreadsheetId);
+        }
+
+        public BatchUpdateSpreadsheetAssert updateTitle(String title) {
+            actual.getRunner().createVariable("title", title);
+            fields.add("title");
+            return this;
+        }
+
+        public void andReturnUpdated() {
+            actual.getRunner().async().actions(
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .receive()
+                    .post("/v4/spreadsheets/${spreadsheetId}:batchUpdate")
+                    .messageType(MessageType.JSON)
+                    .payload("{" +
+                        "\"includeSpreadsheetInResponse\":true," +
+                        "\"requests\":[" +
+                                "{" +
+                                    "\"updateSpreadsheetProperties\": {" +
+                                    "\"fields\":\"" + String.join(",", fields) 
+ "\"," +
+                                    "\"properties\":{" + 
fields.stream().map(field -> String.format("\"%s\":\"${%s}\"", field, 
field)).collect(Collectors.joining(",")) + "}" +
+                                "}" +
+                            "}" +
+                        "]}")),
+                actual.getRunner().http(action -> 
action.server(actual.getHttpServer())
+                    .send()
+                    .response(HttpStatus.OK)
+                    .contentType(MediaType.APPLICATION_JSON_VALUE)
+                    
.payload("{\"spreadsheetId\":\"${spreadsheetId}\",\"updatedSpreadsheet\":{\"properties\":{\"title\":\"${title}\"},\"spreadsheetId\":\"${spreadsheetId}\"}}"))
+            );
+        }
+    }
+}
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerRule.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerRule.java
new file mode 100644
index 0000000..7ecdc53
--- /dev/null
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/server/GoogleSheetsApiTestServerRule.java
@@ -0,0 +1,116 @@
+/*
+ * 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.component.google.sheets.server;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.consol.citrus.dsl.endpoint.CitrusEndpoints;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.SocketUtils;
+
+import static 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerAssert.assertThatGoogleApi;
+
+public class GoogleSheetsApiTestServerRule implements TestRule {
+
+    public static final String SERVER_KEYSTORE = "googleapis.jks";
+    public static final String SERVER_KEYSTORE_PASSWORD = "secret";
+
+    private GoogleSheetsApiTestServer googleApiTestServer;
+    private int serverPort = SocketUtils.findAvailableTcpPort();
+
+    public GoogleSheetsApiTestServerRule(String optionFile) {
+        try {
+            Map<String, Object> testOptions = getTestOptions(optionFile);
+
+            googleApiTestServer = new 
GoogleSheetsApiTestServer.Builder(CitrusEndpoints.http()
+                    .server()
+                    .port(serverPort)
+                    .timeout(15000)
+                    .defaultStatus(HttpStatus.REQUEST_TIMEOUT)
+                    .autoStart(true))
+                    .keyStorePath(new 
ClassPathResource(SERVER_KEYSTORE).getFile().toPath())
+                    .keyStorePassword(SERVER_KEYSTORE_PASSWORD)
+                    .securePort(serverPort)
+                    .clientId(testOptions.get("clientId").toString())
+                    .clientSecret(testOptions.get("clientSecret").toString())
+                    .accessToken(testOptions.get("accessToken").toString())
+                    .refreshToken(testOptions.get("refreshToken").toString())
+                    .build();
+
+            assertThatGoogleApi(googleApiTestServer).isRunning();
+        } catch (Exception e) {
+            throw new IllegalStateException("Error while reading server 
keystore file", e);
+        }
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new GoogleSheetsApiTestServerStatement(base);
+    }
+
+    /**
+     * Read component configuration from TEST_OPTIONS_PROPERTIES.
+     * @return Map of component options.
+     */
+    private Map<String, Object> getTestOptions(String optionFile) throws 
IOException {
+        final Properties properties = new Properties();
+        properties.load(getClass().getResourceAsStream(optionFile));
+
+        Map<String, Object> options = new HashMap<>();
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            options.put(entry.getKey().toString(), entry.getValue());
+        }
+
+        return options;
+    }
+
+    /**
+     * Rule statement initializes and resets test server after each method.
+     */
+    private class GoogleSheetsApiTestServerStatement extends Statement {
+        private final Statement base;
+
+        GoogleSheetsApiTestServerStatement( Statement base ) {
+            this.base = base;
+        }
+
+        @Override
+        public void evaluate() throws Throwable {
+            googleApiTestServer.init();
+            try {
+                base.evaluate();
+            } finally {
+                googleApiTestServer.reset();
+            }
+        }
+    }
+
+    public GoogleSheetsApiTestServer getGoogleApiTestServer() {
+        return googleApiTestServer;
+    }
+
+    public int getServerPort() {
+        return serverPort;
+    }
+}
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
index 4767a0c..1ca4f5e 100644
--- 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/AbstractGoogleSheetsStreamTestSupport.java
@@ -16,8 +16,13 @@
  */
 package org.apache.camel.component.google.sheets.stream;
 
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.sheets.v4.Sheets;
 import org.apache.camel.CamelContext;
 import 
org.apache.camel.component.google.sheets.AbstractGoogleSheetsTestSupport;
+import org.apache.camel.component.google.sheets.BatchGoogleSheetsClientFactory;
+import 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerRule;
 import org.apache.camel.util.IntrospectionSupport;
 
 /**
@@ -36,6 +41,18 @@ public class AbstractGoogleSheetsStreamTestSupport extends 
AbstractGoogleSheetsT
 
         // add GoogleSheetsComponent to Camel context
         final GoogleSheetsStreamComponent component = new 
GoogleSheetsStreamComponent(context);
+        component.setClientFactory(new BatchGoogleSheetsClientFactory(
+                new NetHttpTransport.Builder()
+                        .trustCertificatesFromJavaKeyStore(
+                                getClass().getResourceAsStream("/" + 
GoogleSheetsApiTestServerRule.SERVER_KEYSTORE),
+                                
GoogleSheetsApiTestServerRule.SERVER_KEYSTORE_PASSWORD)
+                        .build(),
+                new JacksonFactory()) {
+            @Override
+            protected void configure(Sheets.Builder clientBuilder) {
+                
clientBuilder.setRootUrl(String.format("https://localhost:%s/";, 
googleSheetsApiTestServerRule.getServerPort()));
+            }
+        });
         component.setConfiguration(configuration);
         context.addComponent("google-sheets-stream", component);
 
diff --git 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
index 2aa7c5d..ea79f17 100644
--- 
a/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
+++ 
b/components/camel-google-sheets/src/test/java/org/apache/camel/component/google/sheets/stream/SheetsStreamConsumerIntegrationTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.google.sheets.stream;
 
+import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
 
 import com.google.api.services.sheets.v4.model.Spreadsheet;
 import com.google.api.services.sheets.v4.model.ValueRange;
@@ -26,6 +28,7 @@ import org.apache.camel.component.mock.MockEndpoint;
 import org.junit.Assert;
 import org.junit.Test;
 
+import static 
org.apache.camel.component.google.sheets.server.GoogleSheetsApiTestServerAssert.assertThatGoogleApi;
 import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.MAJOR_DIMENSION;
 import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.RANGE;
 import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.RANGE_INDEX;
@@ -34,14 +37,35 @@ import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStream
 
 public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStreamTestSupport {
 
-    private String range = "A1:B2";
+    private String range = TEST_SHEET + "!A1:B2";
 
     @Test
     public void testConsumeValueRange() throws Exception {
-        Spreadsheet testSheet = getSpreadsheetWithTestData();
+        String spreadsheetId = UUID.randomUUID().toString();
 
-        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId()));
-        context().startRoute("google-stream-test");
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnSpreadsheet(spreadsheetId);
+
+        Spreadsheet testSheet = getSpreadsheet();
+
+        List<List<Object>> data = Arrays.asList(
+                Arrays.asList("a1", "b1"),
+                Arrays.asList("a2", "b2")
+        );
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .updateValuesRequest(spreadsheetId, range, data)
+                .andReturnUpdateResponse();
+
+        applyTestData(testSheet);
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .batchGetValuesRequest(testSheet.getSpreadsheetId(), range)
+                .andReturnValues(data);
+
+        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId(),
 false));
 
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
@@ -53,7 +77,7 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
         
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
         
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(MAJOR_DIMENSION));
         Assert.assertEquals(testSheet.getSpreadsheetId(), 
exchange.getIn().getHeaders().get(SPREADSHEET_ID));
-        Assert.assertEquals(TEST_SHEET + "!" + range, 
exchange.getIn().getHeaders().get(RANGE));
+        Assert.assertEquals(range, exchange.getIn().getHeaders().get(RANGE));
         Assert.assertEquals(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
         Assert.assertEquals("ROWS", 
exchange.getIn().getHeaders().get(MAJOR_DIMENSION));
 
@@ -66,13 +90,35 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
     }
 
     @Test
-    public void testConsumeRowValues() throws Exception {
-        Spreadsheet testSheet = getSpreadsheetWithTestData();
+    public void testConsumeValueRangeSplitResults() throws Exception {
+        String spreadsheetId = UUID.randomUUID().toString();
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .createSpreadsheetRequest()
+                .hasSheetTitle("TestData")
+                .andReturnSpreadsheet(spreadsheetId);
 
-        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId()));
-        context().startRoute("google-stream-values-test");
+        Spreadsheet testSheet = getSpreadsheet();
 
-        MockEndpoint mock = getMockEndpoint("mock:rows");
+        List<List<Object>> data = Arrays.asList(
+                Arrays.asList("a1", "b1"),
+                Arrays.asList("a2", "b2")
+        );
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .updateValuesRequest(spreadsheetId, range, data)
+                .andReturnUpdateResponse();
+
+        applyTestData(testSheet);
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .batchGetValuesRequest(testSheet.getSpreadsheetId(), range)
+                .andReturnValues(data);
+
+        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId(),
 true));
+        context().startRoute("google-stream-test");
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(2);
         assertMockEndpointsSatisfied();
 
@@ -83,7 +129,7 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
         
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(VALUE_INDEX));
         
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(MAJOR_DIMENSION));
         Assert.assertEquals(testSheet.getSpreadsheetId(), 
exchange.getIn().getHeaders().get(SPREADSHEET_ID));
-        Assert.assertEquals(TEST_SHEET + "!" + range, 
exchange.getIn().getHeaders().get(RANGE));
+        Assert.assertEquals(range, exchange.getIn().getHeaders().get(RANGE));
         Assert.assertEquals(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
         Assert.assertEquals(1, exchange.getIn().getHeaders().get(VALUE_INDEX));
         Assert.assertEquals("ROWS", 
exchange.getIn().getHeaders().get(MAJOR_DIMENSION));
@@ -109,14 +155,13 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
         Assert.assertEquals("b2", values.get(1));
     }
 
-    private RouteBuilder createGoogleStreamRouteBuilder(String spreadsheetId) 
throws Exception {
+    private RouteBuilder createGoogleStreamRouteBuilder(String spreadsheetId, 
boolean splitResults) throws Exception {
         return new RouteBuilder() {
             @Override
             public void configure() {
-                from("google-sheets-stream://data?spreadsheetId=" + 
spreadsheetId + "&range=" + range + 
"&delay=2000&maxResults=5").routeId("google-stream-test").to("mock:result");
-
-                from("google-sheets-stream://data?spreadsheetId=" + 
spreadsheetId 
-                    + "&range=" + range + 
"&delay=2000&maxResults=5&splitResults=true").routeId("google-stream-values-test").to("mock:rows");
+                
from(String.format("google-sheets-stream://data?spreadsheetId=%s&range=%s&delay=20000&maxResults=5&splitResults=%s",
 spreadsheetId, range, splitResults))
+                        .routeId("google-stream-test")
+                        .to("mock:result");
             }
         };
     }
diff --git a/components/camel-google-sheets/src/test/resources/googleapis.jks 
b/components/camel-google-sheets/src/test/resources/googleapis.jks
new file mode 100644
index 0000000..0d6097c
Binary files /dev/null and 
b/components/camel-google-sheets/src/test/resources/googleapis.jks differ
diff --git 
a/components/camel-google-sheets/src/test/resources/test-options.properties 
b/components/camel-google-sheets/src/test/resources/test-options.properties
index b21908c..f2e4a6f 100644
--- a/components/camel-google-sheets/src/test/resources/test-options.properties
+++ b/components/camel-google-sheets/src/test/resources/test-options.properties
@@ -19,8 +19,8 @@
 ## Login properties for Google Sheets Component
 #####################################
 ## Application client id and secret
-clientId=
-clientSecret=
+clientId=syndesis-client
+clientSecret=syndesis
 applicationName=camel-google-sheets/1.0
-accessToken=
-refreshToken=
+accessToken=cd887efc-7c7d-4e8e-9580-f7502123badf
+refreshToken=bdbbe5ec-6081-4c6c-8974-9c4abfc0fdcc
diff --git a/parent/pom.xml b/parent/pom.xml
index 9d001b4..bd2138c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -128,6 +128,7 @@
     <chronicle-wire-version>1.16.21</chronicle-wire-version>
     <chunk-templates-version>3.3.1</chunk-templates-version>
     <chunk-templates-bundle-version>3.3.1_1</chunk-templates-bundle-version>
+    <citrus.version>2.8.0</citrus.version>
     <cmis-version>1.1.0</cmis-version>
     <cometd-bayeux-version>6.1.11</cometd-bayeux-version>
     <cometd-java-client-version>3.1.2</cometd-java-client-version>
diff --git 
a/platforms/spring-boot/components-starter/camel-google-sheets-starter/src/main/java/org/apache/camel/component/google/sheets/stream/springboot/GoogleSheetsStreamComponentConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-google-sheets-starter/src/main/java/org/apache/camel/component/google/sheets/stream/springboot/GoogleSheetsStreamComponentConfiguration.java
index 8df3880..b02e6bb 100644
--- 
a/platforms/spring-boot/components-starter/camel-google-sheets-starter/src/main/java/org/apache/camel/component/google/sheets/stream/springboot/GoogleSheetsStreamComponentConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-google-sheets-starter/src/main/java/org/apache/camel/component/google/sheets/stream/springboot/GoogleSheetsStreamComponentConfiguration.java
@@ -127,7 +127,7 @@ public class GoogleSheetsStreamComponentConfiguration
          * number of rows in a returned value range data set or the number of
          * returned value ranges in a batch request.
          */
-        private Integer maxResults = 10;
+        private Integer maxResults = 0;
         /**
          * Specifies the range of rows and columns in a sheet to get data from.
          */

Reply via email to