Skip to content

Commit fe54288

Browse files
authored
adds Spanner integration tests (spring-attic#459)
Adds integration tests to spanner. * `mvn clean install` by default skips integration tests. The tests can be turned on by passing `-Dit.spanner=true`to maven * in order to run Integration Tests you have to provide credentials to a GCP project that has a Spanner instance called `integration-instance`. The database and the schema are automatically created. * for Travis CI, this commit introduces the following: * use `-Dit.spanner=true` so that the build fails when dependencies are not met * adds the latest version of google-cloud-sdk only if it doesn't exist * caches `~/.m2` and `~/google-cloud-sdk` so that subsequent builds can use it on the same branch * setup the travis encrypted credentials for our integration test project and a service account with limited permissions
1 parent 734a430 commit fe54288

File tree

18 files changed

+733
-25
lines changed

18 files changed

+733
-25
lines changed

.travis.yml

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
language: java
22
jdk:
33
- oraclejdk8
4+
env:
5+
- GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/travis/admin.json
46
branches:
57
only:
68
- master
9+
cache:
10+
directories:
11+
- $HOME/google-cloud-sdk
12+
- $HOME/.m2
13+
script:
14+
- ./mvnw test -B -Dit.spanner=true
715
install:
8-
# Install Cloud SDK
9-
- wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-189.0.0-linux-x86_64.tar.gz
10-
- tar -xvzf google-cloud-sdk-189.0.0-linux-x86_64.tar.gz
11-
- export PATH=$PWD/google-cloud-sdk/bin:$PATH
12-
- gcloud components update --quiet
13-
- gcloud components install beta pubsub-emulator --quiet
1416
- ./mvnw install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
1517
before_script:
1618
- gcloud beta emulators pubsub start &
1719
- while [ ! -f ~/.config/gcloud/emulators/pubsub/env.yaml ]; do sleep 1; done
1820
- $(gcloud beta emulators pubsub env-init)
21+
before_install:
22+
- openssl aes-256-cbc -K $encrypted_1ef8dfbdb114_key -iv $encrypted_1ef8dfbdb114_iv -in travis.tar.gz.enc -out travis.tar.gz -d
23+
- if [ ! -d "$HOME/google-cloud-sdk/bin" ]; then rm -rf $HOME/google-cloud-sdk; export CLOUDSDK_CORE_DISABLE_PROMPTS=1; curl https://sdk.cloud.google.com | bash; fi
24+
- source $HOME/google-cloud-sdk/path.bash.inc
25+
- gcloud components install beta pubsub-emulator --quiet
26+
- tar -xzf travis.tar.gz
27+
- gcloud config set project spring-cloud-gcp-ci

spring-cloud-gcp-autoconfigure/src/main/java/org/springframework/cloud/gcp/autoconfigure/spanner/GcpSpannerAutoConfiguration.java

+14-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2929
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3031
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3132
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3233
import org.springframework.cloud.gcp.autoconfigure.core.GcpContextAutoConfiguration;
@@ -77,32 +78,38 @@ public GcpSpannerAutoConfiguration(GcpSpannerProperties gcpSpannerProperties,
7778
}
7879

7980
@Bean
80-
public DatabaseId databaseId() {
81-
return DatabaseId.of(this.projectId, this.instanceId, this.databaseName);
82-
}
83-
84-
@Bean
81+
@ConditionalOnMissingBean
8582
public SpannerOptions spannerOptions() {
8683
return SpannerOptions.newBuilder().setProjectId(this.projectId)
8784
.setCredentials(this.credentials).build();
8885
}
8986

9087
@Bean
88+
@ConditionalOnMissingBean
89+
public DatabaseId databaseId() {
90+
return DatabaseId.of(this.projectId, this.instanceId, this.databaseName);
91+
}
92+
93+
@Bean
94+
@ConditionalOnMissingBean
9195
public Spanner spanner(SpannerOptions spannerOptions) {
9296
return spannerOptions.getService();
9397
}
9498

9599
@Bean
100+
@ConditionalOnMissingBean
96101
public DatabaseClient spannerDatabaseClient(Spanner spanner, DatabaseId databaseId) {
97102
return spanner.getDatabaseClient(databaseId);
98103
}
99104

100105
@Bean
106+
@ConditionalOnMissingBean
101107
public SpannerMappingContext spannerMappingContext() {
102108
return new SpannerMappingContext();
103109
}
104110

105111
@Bean
112+
@ConditionalOnMissingBean
106113
public SpannerOperations spannerOperations(DatabaseClient databaseClient,
107114
SpannerMappingContext mappingContext, SpannerConverter spannerConverter,
108115
SpannerMutationFactory spannerMutationFactory) {
@@ -111,11 +118,13 @@ public SpannerOperations spannerOperations(DatabaseClient databaseClient,
111118
}
112119

113120
@Bean
121+
@ConditionalOnMissingBean
114122
public SpannerConverter spannerConverter(SpannerMappingContext mappingContext) {
115123
return new MappingSpannerConverter(mappingContext);
116124
}
117125

118126
@Bean
127+
@ConditionalOnMissingBean
119128
public SpannerMutationFactory spannerMutationFactory(
120129
SpannerConverter spannerConverter,
121130
SpannerMappingContext spannerMappingContext) {

spring-cloud-gcp-data-spanner/pom.xml

+24-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
<description>Spring Cloud GCP Spanner Module</description>
1616
<properties>
1717
<main.basedir>${basedir}/../..</main.basedir>
18+
<it.spanner>false</it.spanner>
1819
</properties>
19-
2020
<dependencies>
2121
<dependency>
2222
<groupId>com.google.cloud</groupId>
@@ -34,5 +34,28 @@
3434
<groupId>org.springframework</groupId>
3535
<artifactId>spring-core</artifactId>
3636
</dependency>
37+
<dependency>
38+
<groupId>org.springframework.cloud</groupId>
39+
<artifactId>spring-cloud-gcp-core</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.springframework</groupId>
44+
<artifactId>spring-tx</artifactId>
45+
<scope>test</scope>
46+
</dependency>
3747
</dependencies>
48+
<build>
49+
<plugins>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-surefire-plugin</artifactId>
53+
<configuration>
54+
<environmentVariables>
55+
<forceIntegrationTests>${it.spanner}</forceIntegrationTests>
56+
</environmentVariables>
57+
</configuration>
58+
</plugin>
59+
</plugins>
60+
</build>
3861
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2018 original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.gcp.data.spanner.core.it;
18+
19+
import com.google.cloud.spanner.Key;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.cloud.gcp.data.spanner.core.SpannerOperations;
25+
import org.springframework.cloud.gcp.data.spanner.test.AbstractSpannerIntegrationTest;
26+
import org.springframework.cloud.gcp.data.spanner.test.domain.Trade;
27+
import org.springframework.test.context.junit4.SpringRunner;
28+
29+
import static org.hamcrest.Matchers.is;
30+
import static org.junit.Assert.assertThat;
31+
32+
/**
33+
* @author Balint Pato
34+
*/
35+
36+
@RunWith(SpringRunner.class)
37+
public class SpannerTemplateIntegrationTests extends AbstractSpannerIntegrationTest {
38+
39+
@Autowired
40+
protected SpannerOperations spannerOperations;
41+
42+
@Test
43+
public void insertAndDeleteSequence() {
44+
assertThat(this.spannerOperations.count(Trade.class), is(0L));
45+
46+
Trade trade = Trade.aTrade();
47+
this.spannerOperations.insert(trade);
48+
assertThat(this.spannerOperations.count(Trade.class), is(1L));
49+
50+
Trade retrievedTrade = this.spannerOperations.find(Trade.class, Key.of(trade.getId()));
51+
assertThat(retrievedTrade, is(trade));
52+
53+
this.spannerOperations.delete(trade);
54+
assertThat(this.spannerOperations.count(Trade.class), is(0L));
55+
}
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2018 original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.gcp.data.spanner.repository.it;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.cloud.gcp.data.spanner.core.SpannerOperations;
27+
import org.springframework.cloud.gcp.data.spanner.test.AbstractSpannerIntegrationTest;
28+
import org.springframework.cloud.gcp.data.spanner.test.domain.Trade;
29+
import org.springframework.cloud.gcp.data.spanner.test.domain.TradeRepository;
30+
import org.springframework.test.context.junit4.SpringRunner;
31+
32+
import static org.hamcrest.Matchers.containsInAnyOrder;
33+
import static org.hamcrest.Matchers.is;
34+
import static org.junit.Assert.assertThat;
35+
36+
/**
37+
* @author Balint Pato
38+
*/
39+
@RunWith(SpringRunner.class)
40+
public class SpannerRepositoryIntegrationTests extends AbstractSpannerIntegrationTest {
41+
42+
@Autowired
43+
SpannerOperations spannerOperations;
44+
45+
@Autowired
46+
TradeRepository tradeRepository;
47+
48+
@Test
49+
public void declarativeQueryMethodTest() {
50+
List<Trade> trader1BuyTrades = insertTrades("trader1", "BUY", 3);
51+
List<Trade> trader1SellTrades = insertTrades("trader1", "SELL", 2);
52+
List<Trade> trader2Trades = insertTrades("trader2", "SELL", 3);
53+
54+
List<Trade> allTrades = new ArrayList<>();
55+
allTrades.addAll(trader1BuyTrades);
56+
allTrades.addAll(trader1SellTrades);
57+
allTrades.addAll(trader2Trades);
58+
59+
assertThat(this.tradeRepository.count(), is(8L));
60+
61+
List<Trade> allTradesRetrieved = this.spannerOperations.findAll(Trade.class);
62+
assertThat("size is not " + allTrades.size() + " in received records: \n"
63+
+ allTradesRetrieved, allTradesRetrieved.size(), is(allTrades.size()));
64+
assertThat(allTradesRetrieved, containsInAnyOrder(allTrades.toArray()));
65+
66+
assertThat(this.tradeRepository.countByAction("BUY"), is(3));
67+
68+
List<Trade> trader2TradesRetrieved = this.tradeRepository.findByTraderId("trader2");
69+
assertThat("size is not " + allTrades.size() + " in received records: \n"
70+
+ trader2TradesRetrieved, trader2TradesRetrieved.size(), is(trader2Trades.size()));
71+
assertThat(trader2TradesRetrieved, containsInAnyOrder(trader2Trades.toArray()));
72+
}
73+
74+
protected List<Trade> insertTrades(String traderId1, String action, int numTrades) {
75+
List<Trade> trades = new ArrayList<>();
76+
for (int i = 0; i < numTrades; i++) {
77+
Trade t = Trade.aTrade();
78+
t.setAction(action);
79+
t.setTraderId(traderId1);
80+
trades.add(t);
81+
this.spannerOperations.insert(t);
82+
}
83+
return trades;
84+
}
85+
}

0 commit comments

Comments
 (0)