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