Polishing.

Reformat code. Refine dependencies.

See #650
Original pull request: #663
This commit is contained in:
Mark Paluch
2023-05-15 11:25:40 +02:00
parent 244f971d1a
commit 545d957031
12 changed files with 310 additions and 319 deletions

View File

@@ -1,5 +1,6 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-couchbase-examples</artifactId>
@@ -24,9 +25,9 @@
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
</dependency>
</dependencies>

View File

@@ -13,11 +13,6 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>

View File

@@ -1,80 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-couchbase-transactions</artifactId>
<name>Spring Data Couchbase - Transaction example</name>
<description>Transactions Demo project for Spring Data Couchbase</description>
<artifactId>spring-data-couchbase-transactions</artifactId>
<name>Spring Data Couchbase - Transaction example</name>
<description>Transactions Demo project for Spring Data Couchbase</description>
<parent>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-couchbase-examples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<parent>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-couchbase-examples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
</dependency>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-couchbase-example-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-couchbase-example-utils</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-couchbase-example-utils</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
<repository>
<id>sonatype-snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -16,7 +16,6 @@
package com.example.demo;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.index.QueryIndexed;
import org.springframework.data.couchbase.core.mapping.Document;
@@ -26,37 +25,40 @@ import org.springframework.data.couchbase.core.mapping.Document;
*/
@Document
public class AirlineGates {
@Id String id;
@Version Long version;
@QueryIndexed String name;
String iata;
Long gates;
@Id
String id;
@Version
Long version;
@QueryIndexed
String name;
String iata;
Long gates;
@PersistenceConstructor
public AirlineGates(String id, String name, String iata, Long gates) {
this.id = id;
this.name = name;
this.iata = iata;
this.gates = gates;
}
public AirlineGates(String id, String name, String iata, Long gates) {
this.id = id;
this.name = name;
this.iata = iata;
this.gates = gates;
}
public String getId() {
return id;
}
public Long getGates() {
return gates;
}
public String getId() {
return id;
}
public String toString(){
StringBuffer sb=new StringBuffer();
sb.append("{");
sb.append("\"id\":"+id);
sb.append(", \"name\":"+name);
sb.append(", \"iata\":"+iata);
sb.append(", \"gates\":"+gates);
sb.append("}");
public Long getGates() {
return gates;
}
return sb.toString();
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("{");
sb.append("\"id\":" + id);
sb.append(", \"name\":" + name);
sb.append(", \"iata\":" + iata);
sb.append(", \"gates\":" + gates);
sb.append("}");
return sb.toString();
}
}

View File

@@ -13,18 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.demo;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.DynamicProxyable;
import org.springframework.stereotype.Repository;
/**
* @author Michael Reiche
*/
@Repository
public interface AirlineGatesRepository
extends CouchbaseRepository<AirlineGates, String>, DynamicProxyable<AirlineGatesRepository> {
extends CouchbaseRepository<AirlineGates, String>, DynamicProxyable<AirlineGatesRepository> {
}

View File

@@ -15,89 +15,88 @@
*/
package com.example.demo;
import reactor.core.publisher.Mono;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
import org.springframework.data.couchbase.core.TransactionalSupport;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Mono;
/**
* @author Michael Reiche
*/
@Service
public class AirlineGatesService {
CouchbaseTemplate template;
ReactiveCouchbaseTemplate reactiveTemplate;
AirlineGatesRepository airlineGatesRepository;
CouchbaseTemplate template;
ReactiveCouchbaseTemplate reactiveTemplate;
AirlineGatesRepository airlineGatesRepository;
public AirlineGatesService(CouchbaseTemplate template, AirlineGatesRepository airlineGatesRepository) {
this.template = template;
this.reactiveTemplate = template.reactive();
this.airlineGatesRepository = airlineGatesRepository;
}
public AirlineGatesService(CouchbaseTemplate template, AirlineGatesRepository airlineGatesRepository) {
this.template = template;
this.reactiveTemplate = template.reactive();
this.airlineGatesRepository = airlineGatesRepository;
}
@Transactional
public void transferGates(String fromId, String toId, int gatesToTransfer, RuntimeException exceptionToThrow) {
AirlineGates fromAirlineGates = template.findById(AirlineGates.class).one(fromId);
AirlineGates toAirlineGates = template.findById(AirlineGates.class).one(toId);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
template.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
template.save(toAirlineGates);
}
@Transactional
public void transferGates(String fromId, String toId, int gatesToTransfer, RuntimeException exceptionToThrow) {
AirlineGates fromAirlineGates = template.findById(AirlineGates.class).one(fromId);
AirlineGates toAirlineGates = template.findById(AirlineGates.class).one(toId);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
template.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
template.save(toAirlineGates);
}
@Transactional
public void transferGatesRepo(String fromId, String toId, int gatesToTransfer, RuntimeException exceptionToThrow) {
AirlineGates fromAirlineGates = airlineGatesRepository.findById(fromId).orElse(null);
AirlineGates toAirlineGates = airlineGatesRepository.findById(toId).orElse(null);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
airlineGatesRepository.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
airlineGatesRepository.save(toAirlineGates);
}
@Transactional
public void transferGatesRepo(String fromId, String toId, int gatesToTransfer, RuntimeException exceptionToThrow) {
AirlineGates fromAirlineGates = airlineGatesRepository.findById(fromId).orElse(null);
AirlineGates toAirlineGates = airlineGatesRepository.findById(toId).orElse(null);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
airlineGatesRepository.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
airlineGatesRepository.save(toAirlineGates);
}
// The @Transactional annotation results in the method of the proxy for the service executing this in a transaction
@Transactional
public Mono<Void> transferGatesReactive(String fromId, String toId, int gatesToTransfer,
RuntimeException exceptionToThrow) {
return Mono.deferContextual(ctx -> {
AirlineGates fromAirlineGates = template.findById(AirlineGates.class).one(fromId);
AirlineGates toAirlineGates = template.findById(AirlineGates.class).one(toId);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
template.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
return reactiveTemplate.save(toAirlineGates).then();
});
}
// The @Transactional annotation results in the method of the proxy for the service executing this in a transaction
@Transactional
public Mono<Void> transferGatesReactive(String fromId, String toId, int gatesToTransfer,
RuntimeException exceptionToThrow) {
return Mono.deferContextual(ctx -> {
AirlineGates fromAirlineGates = template.findById(AirlineGates.class).one(fromId);
AirlineGates toAirlineGates = template.findById(AirlineGates.class).one(toId);
toAirlineGates.gates += gatesToTransfer;
fromAirlineGates.gates -= gatesToTransfer;
template.save(fromAirlineGates);
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
return reactiveTemplate.save(toAirlineGates).then();
});
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates save(AirlineGates airlineGates) {
return template.save(airlineGates);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates save(AirlineGates airlineGates) {
return template.save(airlineGates);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates findById(String id) {
return template.findById(AirlineGates.class).one(id);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates findById(String id) {
return template.findById(AirlineGates.class).one(id);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates saveRepo(AirlineGates airlineGates) {
return airlineGatesRepository.save(airlineGates);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates saveRepo(AirlineGates airlineGates) {
return airlineGatesRepository.save(airlineGates);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates findByIdRepo(String id) {
return airlineGatesRepository.findById(id).orElse(null);
}
// This does not have the @Transactional annotation therefore is not executed in a transaction
public AirlineGates findByIdRepo(String id) {
return airlineGatesRepository.findById(id).orElse(null);
}
}

View File

@@ -23,93 +23,98 @@ import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
/**
* Components of the type CommandLineRunner are called right after the application start up. So the method *run* is
* called as soon as the application starts.
*
* Components of the type CommandLineRunner are called right after the application start up. So the method *run* is called as
* soon as the application starts.
*
* @author Michael Reiche
*/
@Component
public class CmdRunner implements CommandLineRunner {
@Autowired CouchbaseTemplate template;
@Autowired AirlineGatesService airlineGatesService;
@Autowired
CouchbaseTemplate template;
@Autowired
AirlineGatesService airlineGatesService;
//@Override
public void run(String... strings) {
// @Override
public void run(String... strings) {
try { // remove leftovers from previous run
template.removeById(AirlineGates.class).one("1");
} catch (Exception e) {}
try {
template.removeById(AirlineGates.class).one("2");
} catch (Exception e) {}
try { // remove leftovers from previous run
template.removeById(AirlineGates.class).one("1");
} catch (Exception e) {
}
try {
template.removeById(AirlineGates.class).one("2");
} catch (Exception e) {
}
AirlineGates airlineGates1 = new AirlineGates("1", "American Airlines", "JFK", Long.valueOf(200)); // 1
AirlineGates airlineGates2 = new AirlineGates("2", "Lufthansa", "JFK", Long.valueOf(200));
AirlineGates saved1 = airlineGatesService.save(airlineGates1);
AirlineGates saved2 = airlineGatesService.save(airlineGates2);
AirlineGates found_a_1 = airlineGatesService.findById(saved1.getId()); // 2
AirlineGates found_a_2 = airlineGatesService.findById(saved2.getId());
System.err.println("initialized airlines");
System.err.println(" found before transferGates: " + found_a_1);
System.err.println(" found before transferGates: " + found_a_2);
// move 50 gates from airline1 to airline2
int gatesToTransfer = 50;
System.err.println("===============================================================");
System.err.println("this transferGates attempt will succeed. transferring " + gatesToTransfer);
AirlineGates airlineGates1 = new AirlineGates("1", "American Airlines", "JFK", Long.valueOf(200)); // 1
AirlineGates airlineGates2 = new AirlineGates("2", "Lufthansa", "JFK", Long.valueOf(200));
AirlineGates saved1 = airlineGatesService.save(airlineGates1);
AirlineGates saved2 = airlineGatesService.save(airlineGates2);
AirlineGates found_a_1 = airlineGatesService.findById(saved1.getId()); // 2
AirlineGates found_a_2 = airlineGatesService.findById(saved2.getId());
System.err.println("initialized airlines");
System.err.println(" found before transferGates: " + found_a_1);
System.err.println(" found before transferGates: " + found_a_2);
// move 50 gates from airline1 to airline2
int gatesToTransfer = 50;
System.err.println("===============================================================");
System.err.println("this transferGates attempt will succeed. transferring " + gatesToTransfer);
airlineGatesService.transferGates(airlineGates1.getId(), airlineGates2.getId(), gatesToTransfer, null); // 3
airlineGatesService.transferGates(airlineGates1.getId(), airlineGates2.getId(), gatesToTransfer, null); // 3
AirlineGates found_b_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_b_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_b_1); // 4
System.err.println(" found after transferGates: " + found_b_2);
Assert.isTrue(found_b_1.getGates().equals(found_a_1.getGates() - gatesToTransfer), "should have transferred");
Assert.isTrue(found_b_2.getGates().equals(found_a_1.getGates() + gatesToTransfer), "should have transferred");
System.err.println("===============================================================");
gatesToTransfer = 44;
System.err.println("this transferGates attempt will fail. transferring " + gatesToTransfer);
// attempt to move 44 gates from airline1 to airline2, but it fails.
try {
AirlineGates found_b_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_b_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_b_1); // 4
System.err.println(" found after transferGates: " + found_b_2);
Assert.isTrue(found_b_1.getGates().equals(found_a_1.getGates() - gatesToTransfer), "should have transferred");
Assert.isTrue(found_b_2.getGates().equals(found_a_1.getGates() + gatesToTransfer), "should have transferred");
System.err.println("===============================================================");
gatesToTransfer = 44;
System.err.println("this transferGates attempt will fail. transferring " + gatesToTransfer);
// attempt to move 44 gates from airline1 to airline2, but it fails.
try {
airlineGatesService.transferGates(airlineGates1.getId(), airlineGates2.getId(), 44, new SimulateErrorException());
airlineGatesService.transferGates(airlineGates1.getId(), airlineGates2.getId(), 44, new SimulateErrorException());
} catch (RuntimeException rte) {
if (!(rte instanceof TransactionSystemUnambiguousException) && rte != null
&& rte.getCause() instanceof SimulateErrorException) {
throw rte;
}
System.err.println(" got exception " + rte);
}
AirlineGates found_c_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_c_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_c_1);
System.err.println(" found after transferGates: " + found_c_2);
Assert.isTrue(found_c_1.getGates().equals(found_b_1.getGates()), "should be same as previous");
Assert.isTrue(found_c_2.getGates().equals(found_b_2.getGates()), "should be same as previous");
System.err.println("===============================================================");
gatesToTransfer = 44;
System.err.println("this transferGates attempt will succeed. transferring " + gatesToTransfer);
try {
} catch (RuntimeException rte) {
if (!(rte instanceof TransactionSystemUnambiguousException) && rte != null
&& rte.getCause() instanceof SimulateErrorException) {
throw rte;
}
System.err.println(" got exception " + rte);
}
AirlineGates found_c_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_c_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_c_1);
System.err.println(" found after transferGates: " + found_c_2);
Assert.isTrue(found_c_1.getGates().equals(found_b_1.getGates()), "should be same as previous");
Assert.isTrue(found_c_2.getGates().equals(found_b_2.getGates()), "should be same as previous");
System.err.println("===============================================================");
gatesToTransfer = 44;
System.err.println("this transferGates attempt will succeed. transferring " + gatesToTransfer);
try {
airlineGatesService.transferGatesReactive(airlineGates1.getId(), airlineGates2.getId(), gatesToTransfer, null)
.block();
airlineGatesService.transferGatesReactive(airlineGates1.getId(), airlineGates2.getId(), gatesToTransfer, null)
.block();
} catch (RuntimeException rte) {
if (!(rte instanceof TransactionSystemUnambiguousException) && rte != null
&& rte.getCause() instanceof SimulateErrorException) {
throw rte;
}
System.err.println(" got exception " + rte);
}
AirlineGates found_d_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_d_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_d_1);
System.err.println(" found after transferGates: " + found_d_2);
Assert.isTrue(found_d_1.getGates().equals(found_c_1.getGates() - gatesToTransfer), "should have transferred");
Assert.isTrue(found_d_2.getGates().equals(found_c_2.getGates() + gatesToTransfer), "should have transferred");
System.err.println("===============================================================");
}
} catch (RuntimeException rte) {
if (!(rte instanceof TransactionSystemUnambiguousException) && rte != null
&& rte.getCause() instanceof SimulateErrorException) {
throw rte;
}
System.err.println(" got exception " + rte);
}
AirlineGates found_d_1 = airlineGatesService.findById(airlineGates1.getId());
AirlineGates found_d_2 = airlineGatesService.findById(airlineGates2.getId());
System.err.println(" found after transferGates: " + found_d_1);
System.err.println(" found after transferGates: " + found_d_2);
Assert.isTrue(found_d_1.getGates().equals(found_c_1.getGates() - gatesToTransfer), "should have transferred");
Assert.isTrue(found_d_2.getGates().equals(found_c_2.getGates() + gatesToTransfer), "should have transferred");
System.err.println("===============================================================");
}
static class SimulateErrorException extends RuntimeException {}
static class SimulateErrorException extends RuntimeException {
}
}

View File

@@ -15,47 +15,45 @@
*/
package com.example.demo;
import com.couchbase.client.core.msg.kv.DurabilityLevel;
import com.couchbase.client.java.env.ClusterEnvironment;
import com.couchbase.client.java.transactions.config.TransactionsConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.couchbase.client.core.msg.kv.DurabilityLevel;
import com.couchbase.client.java.env.ClusterEnvironment;
import com.couchbase.client.java.transactions.config.TransactionsConfig;
/**
* @author Michael Reiche
*/
@Configuration
@EnableCouchbaseRepositories({"com.example.demo"})
@EnableCouchbaseRepositories({ "com.example.demo" })
@EnableTransactionManagement
public class Config extends AbstractCouchbaseConfiguration {
@Override
public String getConnectionString() {
return "127.0.0.1";
}
@Override
public String getConnectionString() {
return "127.0.0.1";
}
@Override
public String getUserName() {
return "Administrator";
}
@Override
public String getUserName() {
return "Administrator";
}
@Override
public String getPassword() {
return "password";
}
@Override
public String getPassword() {
return "password";
}
@Override
public String getBucketName() {
return "travel-sample";
}
@Override
public void configureEnvironment(ClusterEnvironment.Builder builder){
builder.transactionsConfig(TransactionsConfig.durabilityLevel(DurabilityLevel.NONE));
}
@Override
public String getBucketName() {
return "travel-sample";
}
@Override
public void configureEnvironment(ClusterEnvironment.Builder builder) {
builder.transactionsConfig(TransactionsConfig.durabilityLevel(DurabilityLevel.NONE));
}
}

View File

@@ -17,17 +17,28 @@ package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;
import example.springdata.couchbase.util.CouchbaseAvailableRule;
/**
* @author Michael Reiche
*/
@SpringBootApplication
@Conditional(DemoApplication.CouchbaseAvailable.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run( DemoApplication.class, args );
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
static class CouchbaseAvailable implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return CouchbaseAvailableRule.onLocalhost().isAvailable();
}
}
}

View File

@@ -1 +0,0 @@
spring.main.allow-bean-definition-overriding=true

View File

@@ -15,19 +15,26 @@
*/
package com.example.demo;
import example.springdata.couchbase.util.EnabledIfCouchbaseAvailable;
import org.junit.ClassRule;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import example.springdata.couchbase.util.CouchbaseAvailableRule;
/**
* @author Michael Reiche
* @author Christoph Strobl
*/
@EnabledIfCouchbaseAvailable
@SpringBootTest
@ContextConfiguration(classes = DemoApplication.class)
class DemoApplicationTests {
@Test
void contextLoads() {
}
@ClassRule //
public static CouchbaseAvailableRule COUCHBASE = CouchbaseAvailableRule.onLocalhost();
@Test
void contextLoads() {
}
}

View File

@@ -19,13 +19,14 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.time.Duration;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import javax.net.SocketFactory;
import org.junit.AssumptionViolatedException;
import org.junit.rules.ExternalResource;
/**
* Rule to check Couchbase server availability. If Couchbase is not running, tests are skipped.
*
@@ -33,35 +34,49 @@ import org.junit.rules.ExternalResource;
*/
public class CouchbaseAvailableRule extends ExternalResource {
private final String host;
private final int port;
private final Duration timeout = Duration.ofSeconds(1);
private final String host;
private final int port;
private final Duration timeout = Duration.ofSeconds(1);
private CouchbaseAvailableRule(String host, int port) {
this.host = host;
this.port = port;
}
private CouchbaseAvailableRule(String host, int port) {
this.host = host;
this.port = port;
}
/**
* Create a new rule requiring Couchbase running on {@code localhost} on {@code 8091}.
*
* @return the test rule.
*/
public static CouchbaseAvailableRule onLocalhost() {
return new CouchbaseAvailableRule("localhost", 8091);
}
/**
* Create a new rule requiring Couchbase running on {@code localhost} on {@code 8091}.
*
* @return the test rule.
*/
public static CouchbaseAvailableRule onLocalhost() {
return new CouchbaseAvailableRule("localhost", 8091);
}
@Override
protected void before() throws Throwable {
@Override
protected void before() throws Throwable {
Socket socket = SocketFactory.getDefault().createSocket();
try {
socket.connect(new InetSocketAddress(host, port), Math.toIntExact(timeout.toMillis()));
} catch (IOException e) {
throw new AssumptionViolatedException(
String.format("Couchbase not available on on %s:%d. Skipping tests.", host, port), e);
} finally {
socket.close();
}
}
check((b, throwable) -> {
if (throwable != null) {
throw new AssumptionViolatedException(
String.format("Couchbase not available on on %s:%d. Skipping tests.", host, port), throwable);
}
});
}
public boolean isAvailable() {
AtomicBoolean b = new AtomicBoolean();
check((avail, t) -> b.set(avail));
return b.get();
}
private void check(BiConsumer<Boolean, Throwable> c) {
try (Socket socket = SocketFactory.getDefault().createSocket()) {
socket.connect(new InetSocketAddress(host, port), Math.toIntExact(timeout.toMillis()));
c.accept(true, null);
} catch (IOException e) {
c.accept(false, e);
}
}
}