Introduce JUnit 5 tags for various types of tests.
This introduces some constants to mark tests as tests that need reactive support and to distinguish between tests that run only on the commercial or community edition. The Neo4jExtension assumes on the requirements of the tags, so those tags have a dual use: They can be used to filter for tests, i.e. setup a pipeline that does only reactive tests on community edition. They make sure the project is easy to build for external contributors and people who might not have access to latest edition by assuming on the requirements and prevent the tests from failing in conditions where the tests are bound to fail.
This commit is contained in:
@@ -98,7 +98,7 @@ class AuditingIT extends AuditingITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -93,7 +93,7 @@ class CallbacksIT extends CallbacksITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -131,7 +131,7 @@ class IdGeneratorsIT extends IdGeneratorsITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1025,7 +1025,7 @@ class RepositoryIT {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -84,7 +84,7 @@ class KotlinIT {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
public Collection<String> getMappingBasePackages() {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.neo4j.springframework.data.integration.reactive;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.neo4j.springframework.data.test.Neo4jExtension.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -29,6 +30,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.springframework.data.config.AbstractReactiveNeo4jConfig;
|
||||
@@ -50,6 +52,7 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Tag(NEEDS_REACTIVE_SUPPORT)
|
||||
@ContextConfiguration(classes = ReactiveAuditingIT.Config.class)
|
||||
class ReactiveAuditingIT extends AuditingITBase {
|
||||
|
||||
@@ -125,7 +128,7 @@ class ReactiveAuditingIT extends AuditingITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.neo4j.springframework.data.integration.reactive;
|
||||
|
||||
import static org.neo4j.springframework.data.test.Neo4jExtension.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -28,6 +30,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.springframework.data.config.AbstractReactiveNeo4jConfig;
|
||||
@@ -47,6 +50,7 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Tag(NEEDS_REACTIVE_SUPPORT)
|
||||
@ContextConfiguration(classes = ReactiveCallbacksIT.Config.class)
|
||||
class ReactiveCallbacksIT extends CallbacksITBase {
|
||||
|
||||
@@ -148,7 +152,7 @@ class ReactiveCallbacksIT extends CallbacksITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.neo4j.springframework.data.integration.reactive;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.neo4j.springframework.data.test.Neo4jExtension.*;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -32,6 +33,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.springframework.data.config.AbstractReactiveNeo4jConfig;
|
||||
@@ -52,6 +54,7 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
/**
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Tag(NEEDS_REACTIVE_SUPPORT)
|
||||
@ContextConfiguration(classes = ReactiveIdGeneratorsIT.Config.class)
|
||||
class ReactiveIdGeneratorsIT extends IdGeneratorsITBase {
|
||||
|
||||
@@ -171,7 +174,7 @@ class ReactiveIdGeneratorsIT extends IdGeneratorsITBase {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.neo4j.springframework.data.integration.reactive;
|
||||
|
||||
import static org.neo4j.driver.Values.*;
|
||||
import static org.neo4j.springframework.data.test.Neo4jExtension.*;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -34,6 +35,7 @@ import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.neo4j.driver.Driver;
|
||||
@@ -47,7 +49,7 @@ import org.neo4j.springframework.data.integration.shared.PersonWithAllConstructo
|
||||
import org.neo4j.springframework.data.integration.shared.ThingWithAssignedId;
|
||||
import org.neo4j.springframework.data.repository.config.EnableReactiveNeo4jRepositories;
|
||||
import org.neo4j.springframework.data.test.Neo4jExtension;
|
||||
import org.neo4j.springframework.data.test.Neo4jExtension.Neo4jConnectionSupport;
|
||||
import org.neo4j.springframework.data.test.Neo4jExtension.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -64,6 +66,7 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
* @author Gerrit Meier
|
||||
* @author Michael J. Simons
|
||||
*/
|
||||
@Tag(NEEDS_REACTIVE_SUPPORT)
|
||||
@ExtendWith(Neo4jExtension.class)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ReactiveRepositoryIT.Config.class)
|
||||
@@ -725,7 +728,7 @@ class ReactiveRepositoryIT {
|
||||
|
||||
@Bean
|
||||
public Driver driver() {
|
||||
return neo4jConnectionSupport.openConnection();
|
||||
return neo4jConnectionSupport.getDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,21 +18,33 @@
|
||||
*/
|
||||
package org.neo4j.springframework.data.test;
|
||||
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.ReflectionUtils;
|
||||
import org.neo4j.driver.AccessMode;
|
||||
import org.neo4j.driver.AuthToken;
|
||||
import org.neo4j.driver.AuthTokens;
|
||||
import org.neo4j.driver.Config;
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.neo4j.driver.GraphDatabase;
|
||||
import org.neo4j.driver.Logging;
|
||||
import org.neo4j.driver.Session;
|
||||
import org.neo4j.driver.internal.SessionConfig;
|
||||
import org.neo4j.driver.internal.util.ServerVersion;
|
||||
import org.testcontainers.containers.Neo4jContainer;
|
||||
|
||||
/**
|
||||
@@ -45,12 +57,21 @@ import org.testcontainers.containers.Neo4jContainer;
|
||||
* @since 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class Neo4jExtension implements BeforeAllCallback {
|
||||
public class Neo4jExtension implements BeforeAllCallback, BeforeEachCallback {
|
||||
|
||||
public final static String NEEDS_REACTIVE_SUPPORT = "reactiveTest";
|
||||
public final static String COMMUNITY_EDITION_ONLY = "communityEdition";
|
||||
public final static String COMMERCIAL_EDITION_ONLY = "commercialEdition";
|
||||
|
||||
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace
|
||||
.create(Neo4jExtension.class);
|
||||
|
||||
private static final String KEY = "neo4j.standalone";
|
||||
private static final String KEY_NEO4J_INSTANCE = "neo4j.standalone";
|
||||
private static final String KEY_DRIVER_INSTANCE = "neo4j.driver";
|
||||
|
||||
private static Set<String> COMMUNITY_EDITION_INDICATOR = Collections.singleton("community");
|
||||
|
||||
private static Set<String> COMMERCIAL_EDITION_INDICATOR = new HashSet<>(Arrays.asList("commercial", "enterprise"));
|
||||
|
||||
@Override
|
||||
public void beforeAll(ExtensionContext context) throws Exception {
|
||||
@@ -66,30 +87,65 @@ public class Neo4jExtension implements BeforeAllCallback {
|
||||
String neo4jUrl = Optional.ofNullable(System.getenv("SDN_RX_NEO4J_URL")).orElse("");
|
||||
String neo4jPassword = Optional.ofNullable(System.getenv("SDN_RX_NEO4J_PASSWORD")).orElse("");
|
||||
|
||||
Neo4jConnectionSupport neo4jConnectionSupport;
|
||||
if (!(neo4jUrl.isEmpty() || neo4jPassword.isEmpty())) {
|
||||
log.warn("Using Neo4j instance at {}.", neo4jUrl);
|
||||
neo4jConnectionSupport = new Neo4jConnectionSupport(neo4jUrl,
|
||||
AuthTokens.basic("neo4j", neo4jPassword));
|
||||
} else {
|
||||
log.warn("Using Neo4j test container.");
|
||||
ExtensionContext.Store store = context.getStore(NAMESPACE);
|
||||
ContainerAdapter adapter = store
|
||||
.getOrComputeIfAbsent(KEY, key -> new Neo4jExtension.ContainerAdapter(), ContainerAdapter.class);
|
||||
adapter.start();
|
||||
neo4jConnectionSupport = new Neo4jConnectionSupport(adapter.getBoltUrl(), AuthTokens.none());
|
||||
ExtensionContext.Store contextStore = context.getStore(NAMESPACE);
|
||||
Neo4jConnectionSupport neo4jConnectionSupport = contextStore
|
||||
.get(KEY_DRIVER_INSTANCE, Neo4jConnectionSupport.class);
|
||||
|
||||
if (neo4jConnectionSupport == null) {
|
||||
if (!(neo4jUrl.isEmpty() || neo4jPassword.isEmpty())) {
|
||||
log.warn("Using Neo4j instance at {}.", neo4jUrl);
|
||||
neo4jConnectionSupport = new Neo4jConnectionSupport(neo4jUrl, AuthTokens.basic("neo4j", neo4jPassword));
|
||||
} else {
|
||||
log.warn("Using Neo4j test container.");
|
||||
ContainerAdapter adapter = contextStore
|
||||
.getOrComputeIfAbsent(KEY_NEO4J_INSTANCE, key -> new Neo4jExtension.ContainerAdapter(),
|
||||
ContainerAdapter.class);
|
||||
adapter.start();
|
||||
neo4jConnectionSupport = new Neo4jConnectionSupport(adapter.getBoltUrl(), AuthTokens.none());
|
||||
}
|
||||
contextStore.put(KEY_DRIVER_INSTANCE, neo4jConnectionSupport);
|
||||
}
|
||||
|
||||
checkRequiredFeatures(neo4jConnectionSupport, context.getTags());
|
||||
|
||||
Field field = injectableFields.get(0);
|
||||
field.setAccessible(true);
|
||||
field.set(null, neo4jConnectionSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
ExtensionContext.Store contextStore = context.getStore(NAMESPACE);
|
||||
Neo4jConnectionSupport neo4jConnectionSupport = contextStore
|
||||
.get(KEY_DRIVER_INSTANCE, Neo4jConnectionSupport.class);
|
||||
checkRequiredFeatures(neo4jConnectionSupport, context.getTags());
|
||||
}
|
||||
|
||||
private void checkRequiredFeatures(Neo4jConnectionSupport neo4jConnectionSupport, Set<String> tags) {
|
||||
if (tags.contains(NEEDS_REACTIVE_SUPPORT)) {
|
||||
assumeThat(neo4jConnectionSupport.getServerVersion().greaterThanOrEqual(ServerVersion.v4_0_0))
|
||||
.describedAs("This test requires at least Neo4j 4.0 for reactive database connectivity.")
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
if (tags.contains(COMMUNITY_EDITION_ONLY)) {
|
||||
assumeThat(neo4jConnectionSupport.isCommunityEdition())
|
||||
.describedAs("This test should be run on the community edition only")
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
if (tags.contains(COMMERCIAL_EDITION_ONLY)) {
|
||||
assumeThat(neo4jConnectionSupport.isCommercialEdition())
|
||||
.describedAs("This test should be run on the commercial edition only")
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support class that holds the connection information and opens a new connection on demand.
|
||||
* @since 1.0
|
||||
*/
|
||||
public static class Neo4jConnectionSupport {
|
||||
public static class Neo4jConnectionSupport implements ExtensionContext.Store.CloseableResource {
|
||||
|
||||
public final String url;
|
||||
|
||||
@@ -97,14 +153,88 @@ public class Neo4jExtension implements BeforeAllCallback {
|
||||
|
||||
public final Config config;
|
||||
|
||||
public volatile ServerVersion cachedServerVersion;
|
||||
|
||||
/**
|
||||
* Shared instance of the standard (non-routing) driver.
|
||||
*/
|
||||
public volatile Driver driverInstance;
|
||||
|
||||
public Neo4jConnectionSupport(String url, AuthToken authToken) {
|
||||
this.url = url;
|
||||
this.authToken = authToken;
|
||||
this.config = Config.builder().withLogging(Logging.slf4j()).build();
|
||||
}
|
||||
|
||||
public Driver openConnection() {
|
||||
return GraphDatabase.driver(url, authToken, config);
|
||||
/**
|
||||
* @return A possible shared driver instance, connected to either a database running inside test containers or
|
||||
* running locally.
|
||||
*/
|
||||
public Driver getDriver() {
|
||||
|
||||
Driver driver = this.driverInstance;
|
||||
if (driver == null) {
|
||||
synchronized (this) {
|
||||
driver = this.driverInstance;
|
||||
if (driver == null) {
|
||||
this.driverInstance = GraphDatabase.driver(url, authToken, config);
|
||||
driver = this.driverInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
|
||||
ServerVersion getServerVersion() {
|
||||
|
||||
ServerVersion serverVersion = this.cachedServerVersion;
|
||||
if (serverVersion == null) {
|
||||
synchronized (this) {
|
||||
serverVersion = this.cachedServerVersion;
|
||||
if (serverVersion == null) {
|
||||
this.cachedServerVersion = ServerVersion.version(getDriver());
|
||||
serverVersion = this.cachedServerVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
String getEdition() {
|
||||
String edition = "n/a";
|
||||
SessionConfig sessionConfig = SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build();
|
||||
try (Session session = getDriver().session(
|
||||
sessionConfig)) {
|
||||
edition = session.run("call dbms.components() yield edition").single().get("edition").asString();
|
||||
}
|
||||
return edition.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
boolean isCommunityEdition() {
|
||||
|
||||
return COMMUNITY_EDITION_INDICATOR.contains(getEdition());
|
||||
}
|
||||
|
||||
boolean isCommercialEdition() {
|
||||
|
||||
return COMMERCIAL_EDITION_INDICATOR.contains(getEdition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
// Don't open up a driver for just closing it
|
||||
if (driverInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Catch all the things... The driver has been closed maybe by a Spring Context already
|
||||
try {
|
||||
log.debug("Closing Neo4j connection support.");
|
||||
driverInstance.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user