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

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

commit 47f173822d6730300e28d60117d513c89f78fa2b
Author: Christoph Deppisch <cdeppi...@redhat.com>
AuthorDate: Thu Jun 6 10:26:45 2019 +0200

    CAMEL-13617: Improve testability of google-sheets component and incorporate 
latest enhancements to 3.x
---
 components/camel-google-sheets/pom.xml             |  85 +++++
 .../main/docs/google-sheets-stream-component.adoc  |   5 +-
 .../sheets/BatchGoogleSheetsClientFactory.java     |  63 +++-
 .../google/sheets/GoogleSheetsClientFactory.java   |   6 +-
 .../google/sheets/GoogleSheetsEndpoint.java        |  40 +-
 .../google/sheets/GoogleSheetsProducer.java        |   2 +-
 .../sheets/GoogleSheetsVerifierExtension.java      |   9 +-
 .../sheets/internal/GoogleSheetsConstants.java     |   4 +-
 .../sheets/stream/GoogleSheetsStreamComponent.java |   8 +-
 .../stream/GoogleSheetsStreamConfiguration.java    |  22 +-
 .../sheets/stream/GoogleSheetsStreamConstants.java |   2 +
 .../sheets/stream/GoogleSheetsStreamConsumer.java  |  42 ++-
 .../sheets/stream/GoogleSheetsStreamEndpoint.java  |  18 +-
 .../sheets/AbstractGoogleSheetsTestSupport.java    |  46 ++-
 .../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       | 113 +++++-
 .../src/test/resources/googleapis.jks              | Bin 0 -> 2695 bytes
 .../src/test/resources/test-options.properties     |   8 +-
 parent/pom.xml                                     |   1 +
 .../GoogleSheetsStreamComponentConfiguration.java  |  17 +-
 25 files changed, 1400 insertions(+), 103 deletions(-)

diff --git a/components/camel-google-sheets/pom.xml 
b/components/camel-google-sheets/pom.xml
index 4a36c10..7c3ac61 100644
--- a/components/camel-google-sheets/pom.xml
+++ b/components/camel-google-sheets/pom.xml
@@ -39,14 +39,58 @@
         
<componentPackage>org.apache.camel.component.google.sheets</componentPackage>
         
<outPackage>org.apache.camel.component.google.sheets.internal</outPackage>
         
<camel.osgi.private.pkg>org.apache.camel.component.google.sheets.internal</camel.osgi.private.pkg>
+        
<spring-security-oauth2-version>2.3.6.RELEASE</spring-security-oauth2-version>
     </properties>
 
+    <dependencyManagement>
+        <dependencies>
+            <!-- Test dependencies -->
+            <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>
             <artifactId>camel-support</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-util</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.google.api-client</groupId>
             <artifactId>google-api-client</artifactId>
             <version>${google-api-client-version}</version>
@@ -107,6 +151,47 @@
             <artifactId>camel-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-mock</artifactId>
+            <version>${project.version}</version>
+            <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 c2caf17..08c93f7 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
@@ -79,7 +79,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (32 parameters):
+==== Query Parameters (33 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -92,11 +92,12 @@ 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
 | *sendEmptyMessageWhenIdle* (consumer) | If the polling consumer did not poll 
any files, you can enable this option to send an empty message (no body) 
instead. | false | boolean
+| *splitResults* (consumer) | True if value range result should be split into 
rows or columns to process each of them individually. When true each row or 
column is represented with a separate exchange in batch processing. Otherwise 
value range object is used as exchange junk size. | false | boolean
 | *spreadsheetId* (consumer) | Specifies the spreadsheet identifier that is 
used to identify the target to obtain. |  | String
 | *valueRenderOption* (consumer) | Determines how values should be rendered in 
the output. | FORMATTED_VALUE | String
 | *exceptionHandler* (consumer) | To let the consumer use a custom 
ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this 
option is not in use. By default the consumer will deal with exceptions, that 
will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
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 327912b..a06716d 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 8cf2cc1..b602e49 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 5a07006..5e7c46d 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,31 @@ import 
org.apache.camel.support.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", consumerPrefix = 
"consumer", label = "api,cloud,sheets")
+@UriEndpoint(firstVersion = "2.23.0",
+        scheme = "google-sheets",
+        title = "Google Sheets",
+        syntax = "google-sheets:apiName/methodName",
+        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 +87,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 c147c39..dad7a21 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 fd6bfcd..96b1ece 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 2c03d35..11cd297 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/GoogleSheetsStreamComponent.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.java
index 32f7236..1b9f8d9 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamComponent.java
@@ -54,9 +54,11 @@ public class GoogleSheetsStreamComponent extends 
DefaultComponent {
 
     public Sheets getClient(GoogleSheetsStreamConfiguration 
endpointConfiguration) {
         if (client == null) {
-            client = 
getClientFactory().makeClient(endpointConfiguration.getClientId(), 
endpointConfiguration.getClientSecret(),
-                                                    
endpointConfiguration.getApplicationName(), 
endpointConfiguration.getRefreshToken(),
-                                                    
endpointConfiguration.getAccessToken());
+            client = 
getClientFactory().makeClient(endpointConfiguration.getClientId(),
+                                                
endpointConfiguration.getClientSecret(),
+                                                
endpointConfiguration.getApplicationName(),
+                                                
endpointConfiguration.getRefreshToken(),
+                                                
endpointConfiguration.getAccessToken());
         }
         return client;
     }
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 ac94812..50b8eab 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;
@@ -66,6 +66,9 @@ public class GoogleSheetsStreamConfiguration implements 
Cloneable {
     @UriParam
     private boolean includeGridData;
 
+    @UriParam
+    private boolean splitResults;
+
     @UriParam(enums = "ROWS,COLUMNS,DIMENSION_UNSPECIFIED", defaultValue = 
"ROWS")
     private String majorDimension = "ROWS";
 
@@ -240,6 +243,21 @@ public class GoogleSheetsStreamConfiguration implements 
Cloneable {
         this.includeGridData = includeGridData;
     }
 
+    public boolean isSplitResults() {
+        return splitResults;
+    }
+
+    /**
+     * True if value range result should be split into rows or columns to 
process each of them individually. When true
+     * each row or column is represented with a separate exchange in batch 
processing. Otherwise value range object is used
+     * as exchange junk size.
+     *
+     * @param splitResults
+     */
+    public void setSplitResults(boolean splitResults) {
+        this.splitResults = splitResults;
+    }
+
     // *************************************************
     //
     // *************************************************
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
index 60f80c0..6e803c9 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConstants.java
@@ -27,6 +27,8 @@ public final class GoogleSheetsStreamConstants {
     public static final String SPREADSHEET_URL =  PROPERTY_PREFIX + 
"SpreadsheetUrl";
     public static final String MAJOR_DIMENSION = PROPERTY_PREFIX + 
"MajorDimension";
     public static final String RANGE = PROPERTY_PREFIX + "Range";
+    public static final String RANGE_INDEX = PROPERTY_PREFIX + "RangeIndex";
+    public static final String VALUE_INDEX = PROPERTY_PREFIX + "ValueIndex";
 
     /**
      * Prevent instantiation.
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 1b20594..c4bf414 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
@@ -20,11 +20,13 @@ import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Queue;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 import com.google.api.services.sheets.v4.Sheets;
 import com.google.api.services.sheets.v4.model.BatchGetValuesResponse;
 import com.google.api.services.sheets.v4.model.Spreadsheet;
+import com.google.api.services.sheets.v4.model.ValueRange;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
@@ -70,8 +72,8 @@ public class GoogleSheetsStreamConsumer extends 
ScheduledBatchPollingConsumer {
 
             if (getConfiguration().getRange().contains(",")) {
                 
request.setRanges(Arrays.stream(getConfiguration().getRange().split(","))
-                                        .map(String::trim)
-                                        .collect(Collectors.toList()));
+                        .map(String::trim)
+                        .collect(Collectors.toList()));
             } else {
                 
request.setRanges(Collections.singletonList(getConfiguration().getRange()));
             }
@@ -79,11 +81,37 @@ public class GoogleSheetsStreamConsumer extends 
ScheduledBatchPollingConsumer {
             BatchGetValuesResponse response = request.execute();
 
             if (response.getValueRanges() != null) {
-                response.getValueRanges()
-                        .stream()
-                        .limit(getConfiguration().getMaxResults())
-                        .map(valueRange -> 
getEndpoint().createExchange(valueRange))
-                        .forEach(answer::add);
+                if (getConfiguration().isSplitResults()) {
+                    for (ValueRange valueRange : response.getValueRanges()) {
+                        AtomicInteger rangeIndex = new AtomicInteger(1);
+                        AtomicInteger valueIndex = new AtomicInteger();
+                        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()
+                            .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);
+                }
             }
         } else {
             Sheets.Spreadsheets.Get request = 
getClient().spreadsheets().get(getConfiguration().getSpreadsheetId());
diff --git 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
index f13f141..3dff538 100644
--- 
a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
+++ 
b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
@@ -16,10 +16,11 @@
  */
 package org.apache.camel.component.google.sheets.stream;
 
+import java.util.List;
+
 import com.google.api.services.sheets.v4.Sheets;
 import com.google.api.services.sheets.v4.model.Spreadsheet;
 import com.google.api.services.sheets.v4.model.ValueRange;
-
 import org.apache.camel.Consumer;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
@@ -77,16 +78,29 @@ public class GoogleSheetsStreamEndpoint extends 
ScheduledPollEndpoint {
         return configuration;
     }
 
-    public Exchange createExchange(ValueRange valueRange) {
+    public Exchange createExchange(int rangeIndex, ValueRange valueRange) {
         Exchange exchange = super.createExchange(getExchangePattern());
         Message message = exchange.getIn();
         exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, 
configuration.getSpreadsheetId());
         exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, 
valueRange.getRange());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, 
rangeIndex);
         
exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, 
valueRange.getMajorDimension());
         message.setBody(valueRange);
         return exchange;
     }
 
+    public Exchange createExchange(int rangeIndex, int valueIndex, String 
range, String majorDimension, List<Object> values) {
+        Exchange exchange = super.createExchange(getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, 
configuration.getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, 
rangeIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.VALUE_INDEX, 
valueIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, range);
+        
exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, 
majorDimension);
+        message.setBody(values);
+        return exchange;
+    }
+
     public Exchange createExchange(Spreadsheet spreadsheet) {
         Exchange exchange = super.createExchange(getExchangePattern());
         Message message = exchange.getIn();
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 1ca893c..4df7eb3 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,9 +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.support.PropertyBindingSupport;
+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.support.PropertyBindingSupport;
+import org.junit.ClassRule;
 
 /**
  * Abstract base class for GoogleSheets Integration tests generated by Camel
@@ -46,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);
 
@@ -79,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);
     }
@@ -97,8 +106,20 @@ public class AbstractGoogleSheetsTestSupport extends 
CamelTestSupport {
         final GoogleSheetsConfiguration configuration = new 
GoogleSheetsConfiguration();
         PropertyBindingSupport.bindProperties(context, 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);
 
@@ -149,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 4efbcfc..4be016b 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 d1589b2..ceffd5b 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 1e9bf35..fe32ae6 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.support.PropertyBindingSupport;
 
 /**
@@ -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 113d077..3e9c5a8 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,6 +16,10 @@
  */
 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;
 import org.apache.camel.Exchange;
@@ -24,20 +28,44 @@ 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;
 import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.SPREADSHEET_ID;
+import static 
org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamConstants.VALUE_INDEX;
 
 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();
+
+        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();
 
-        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId()));
-        context().start();
+        applyTestData(testSheet);
+
+        assertThatGoogleApi(getGoogleApiTestServer())
+                .batchGetValuesRequest(testSheet.getSpreadsheetId(), range)
+                .andReturnValues(data);
+
+        
context().addRoutes(createGoogleStreamRouteBuilder(testSheet.getSpreadsheetId(),
 false));
 
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMinimumMessageCount(1);
@@ -46,9 +74,11 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
         Exchange exchange = mock.getReceivedExchanges().get(0);
         
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
         Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        
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));
 
         ValueRange values = (ValueRange) exchange.getIn().getBody();
@@ -59,12 +89,79 @@ public class SheetsStreamConsumerIntegrationTest extends 
AbstractGoogleSheetsStr
         Assert.assertEquals("b2", values.getValues().get(1).get(1));
     }
 
-    private RouteBuilder createGoogleStreamRouteBuilder(String spreadsheetId) 
throws Exception {
+    @Test
+    public void testConsumeValueRangeSplitResults() throws Exception {
+        String spreadsheetId = UUID.randomUUID().toString();
+
+        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(),
 true));
+        context().getRouteController().startRoute("google-stream-test");
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(2);
+        assertMockEndpointsSatisfied();
+
+        Exchange exchange = mock.getReceivedExchanges().get(0);
+        
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
+        
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(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));
+
+        List<?> values = (List) exchange.getIn().getBody();
+        Assert.assertEquals(2L, values.size());
+        Assert.assertEquals("a1", values.get(0));
+        Assert.assertEquals("b1", values.get(1));
+
+        exchange = mock.getReceivedExchanges().get(1);
+        
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(SPREADSHEET_ID));
+        Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE));
+        
Assert.assertTrue(exchange.getIn().getHeaders().containsKey(RANGE_INDEX));
+        
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(1, exchange.getIn().getHeaders().get(RANGE_INDEX));
+        Assert.assertEquals(2, exchange.getIn().getHeaders().get(VALUE_INDEX));
+
+        values = (List) exchange.getIn().getBody();
+        Assert.assertEquals(2L, values.size());
+        Assert.assertEquals("a2", values.get(0));
+        Assert.assertEquals("b2", values.get(1));
+    }
+
+    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&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 5814302..c12e094 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -124,6 +124,7 @@
         <cglib-version>3.2.12</cglib-version>
         <chunk-templates-version>3.5.0</chunk-templates-version>
         
<chunk-templates-bundle-version>3.5.0_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 bfb787a..89fd12f 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
@@ -140,7 +140,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.
          */
@@ -157,6 +157,13 @@ public class GoogleSheetsStreamComponentConfiguration
          * True if grid data should be returned.
          */
         private Boolean includeGridData = false;
+        /**
+         * True if value range result should be split into rows or columns to
+         * process each of them individually. When true each row or column is
+         * represented with a separate exchange in batch processing. Otherwise
+         * value range object is used as exchange junk size.
+         */
+        private Boolean splitResults = false;
 
         public String getClientId() {
             return clientId;
@@ -261,5 +268,13 @@ public class GoogleSheetsStreamComponentConfiguration
         public void setIncludeGridData(Boolean includeGridData) {
             this.includeGridData = includeGridData;
         }
+
+        public Boolean getSplitResults() {
+            return splitResults;
+        }
+
+        public void setSplitResults(Boolean splitResults) {
+            this.splitResults = splitResults;
+        }
     }
 }
\ No newline at end of file

Reply via email to