Upgrade to Spring Data Neo4j 6

See gh-22299
pull/22681/head
Gerrit Meier 4 years ago committed by Stephane Nicoll
parent ff038be773
commit 15cd343737

@ -171,9 +171,6 @@ dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.mockito:mockito-core")
testImplementation("org.neo4j:neo4j-ogm-bolt-native-types")
testImplementation("org.neo4j:neo4j-ogm-http-driver")
testImplementation("org.neo4j:neo4j-ogm-embedded-driver")
testImplementation("org.springframework:spring-test")
testImplementation("org.springframework.kafka:spring-kafka-test")
testImplementation("org.springframework.security:spring-security-test")

@ -1,65 +0,0 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.bookmark.BeanFactoryBookmarkOperationAdvisor;
import org.springframework.data.neo4j.bookmark.BookmarkInterceptor;
import org.springframework.data.neo4j.bookmark.BookmarkManager;
import org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager;
import org.springframework.web.context.WebApplicationContext;
/**
* Provides a {@link BookmarkManager} for Neo4j's bookmark support based on Caffeine if
* available. Depending on the application's type (web or not) the bookmark manager will
* be bound to the application or the request, as recommend by Spring Data Neo4j.
*
* @author Michael Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
@ConditionalOnMissingBean(BookmarkManager.class)
@ConditionalOnBean({ BeanFactoryBookmarkOperationAdvisor.class, BookmarkInterceptor.class })
class Neo4jBookmarkManagementConfiguration {
private static final String BOOKMARK_MANAGER_BEAN_NAME = "bookmarkManager";
@Bean(BOOKMARK_MANAGER_BEAN_NAME)
@ConditionalOnWebApplication
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
BookmarkManager requestScopedBookmarkManager() {
return new CaffeineBookmarkManager();
}
@Bean(BOOKMARK_MANAGER_BEAN_NAME)
@ConditionalOnNotWebApplication
BookmarkManager singletonScopedBookmarkManager() {
return new CaffeineBookmarkManager();
}
}

@ -16,111 +16,62 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import java.util.List;
import java.util.Set;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.event.EventListener;
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.schema.Node;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j.
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. Automatic
* configuration of base infrastructure that imports configuration for both imperative and
* reactive Neo4j repositories.
*
* @author Michael Hunger
* @author Josh Long
* @author Vince Bickers
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @author Michael Simons
* @author Michael J Simons
* @since 1.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SessionFactory.class, Neo4jTransactionManager.class, PlatformTransactionManager.class })
@EnableConfigurationProperties(Neo4jProperties.class)
@Import(Neo4jBookmarkManagementConfiguration.class)
@ConditionalOnBean(Driver.class)
@EnableConfigurationProperties(Neo4jDataProperties.class)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@AutoConfigureBefore(TransactionAutoConfiguration.class)
@Import({ Neo4jDataConfiguration.class, Neo4jReactiveDataConfiguration.class })
public class Neo4jDataAutoConfiguration {
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public Neo4jTransactionManager transactionManager(SessionFactory sessionFactory,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(sessionFactory);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
@ConditionalOnMissingBean
public Neo4jConversions neo4jConversions() {
return new Neo4jConversions();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(SessionFactory.class)
static class Neo4jOgmSessionFactoryConfiguration {
@Bean
@ConditionalOnMissingBean
org.neo4j.ogm.config.Configuration configuration(Neo4jProperties properties) {
return properties.createConfiguration();
}
@Bean
SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration, BeanFactory beanFactory,
ObjectProvider<EventListener> eventListeners) {
SessionFactory sessionFactory = new SessionFactory(configuration, getPackagesToScan(beanFactory));
eventListeners.orderedStream().forEach(sessionFactory::register);
return sessionFactory;
}
private String[] getPackagesToScan(BeanFactory beanFactory) {
List<String> packages = EntityScanPackages.get(beanFactory).getPackageNames();
if (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) {
packages = AutoConfigurationPackages.get(beanFactory);
}
return StringUtils.toStringArray(packages);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ WebMvcConfigurer.class, OpenSessionInViewInterceptor.class })
@ConditionalOnMissingBean(OpenSessionInViewInterceptor.class)
@ConditionalOnProperty(prefix = "spring.data.neo4j", name = "open-in-view", havingValue = "true")
static class Neo4jWebConfiguration {
@Bean
OpenSessionInViewInterceptor neo4jOpenSessionInViewInterceptor() {
return new OpenSessionInViewInterceptor();
}
@Bean
WebMvcConfigurer neo4jOpenSessionInViewInterceptorConfigurer(OpenSessionInViewInterceptor interceptor) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addWebRequestInterceptor(interceptor);
}
};
}
@Bean
@ConditionalOnMissingBean
public Neo4jMappingContext neo4jMappingContext(ApplicationContext applicationContext,
Neo4jConversions neo4jConversions) throws ClassNotFoundException {
Set<Class<?>> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class);
Neo4jMappingContext context = new Neo4jMappingContext(neo4jConversions);
context.setInitialEntitySet(initialEntityClasses);
return context;
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Internal configuration of Neo4j client and transaction manager.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Neo4jTransactionManager.class, PlatformTransactionManager.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@AutoConfigureBefore(Neo4jRepositoriesConfiguration.class)
@Import(Neo4jDefaultCallbacksRegistrar.class)
class Neo4jDataConfiguration {
@Bean("databaseSelectionProvider")
@ConditionalOnMissingBean
DatabaseSelectionProvider defaultSelectionProvider(Environment environment) {
String database = environment.getProperty("spring.data.neo4j.database");
if (database != null) {
return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database);
}
return DatabaseSelectionProvider.getDefaultSelectionProvider();
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)
@ConditionalOnMissingBean
Neo4jClient neo4jClient(Driver driver) {
return Neo4jClient.create(driver);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
@ConditionalOnMissingBean(Neo4jOperations.class)
Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
DatabaseSelectionProvider databaseNameProvider) {
return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(PlatformTransactionManager.class)
Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,
ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);
optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager));
return transactionManager;
}
}

@ -0,0 +1,47 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
/**
* Configuration properties for Spring Data Neo4j.
*
* @author Michael J. Simons
* @since 2.4.0
*/
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jDataProperties {
/**
* A statically configured database. This property is only applicable when connecting
* against a 4.0 cluster or server and will lead to errors if used with a prior
* version of Neo4j. Leave this null (the default) to indicate that you like the
* server to decide the default database to use.
*/
private String database;
public String getDatabase() {
return this.database;
}
public void setDatabase(String database) {
this.database = database;
}
}

@ -1,177 +0,0 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.ogm.config.AutoIndexMode;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.config.Configuration.Builder;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;
/**
* Configuration properties for Neo4j.
*
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
* @author Aurélien Leboulanger
* @author Michael Simons
* @since 1.4.0
*/
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jProperties implements ApplicationContextAware {
static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver";
static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver";
static final String DEFAULT_BOLT_URI = "bolt://localhost:7687";
static final String BOLT_DRIVER = "org.neo4j.ogm.drivers.bolt.driver.BoltDriver";
/**
* URI used by the driver. Auto-detected by default.
*/
private String uri;
/**
* Login user of the server.
*/
private String username;
/**
* Login password of the server.
*/
private String password;
/**
* Auto index mode.
*/
private AutoIndexMode autoIndex = AutoIndexMode.NONE;
/**
* Whether to use Neo4j native types wherever possible.
*/
private boolean useNativeTypes = false;
private final Embedded embedded = new Embedded();
private ClassLoader classLoader = Neo4jProperties.class.getClassLoader();
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public AutoIndexMode getAutoIndex() {
return this.autoIndex;
}
public void setAutoIndex(AutoIndexMode autoIndex) {
this.autoIndex = autoIndex;
}
public boolean isUseNativeTypes() {
return this.useNativeTypes;
}
public void setUseNativeTypes(boolean useNativeTypes) {
this.useNativeTypes = useNativeTypes;
}
public Embedded getEmbedded() {
return this.embedded;
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.classLoader = ctx.getClassLoader();
}
/**
* Create a {@link Configuration} based on the state of this instance.
* @return a configuration
*/
public Configuration createConfiguration() {
Builder builder = new Builder();
configure(builder);
return builder.build();
}
private void configure(Builder builder) {
if (this.uri != null) {
builder.uri(this.uri);
}
else {
configureUriWithDefaults(builder);
}
if (this.username != null && this.password != null) {
builder.credentials(this.username, this.password);
}
builder.autoIndex(getAutoIndex().getName());
if (this.useNativeTypes) {
builder.useNativeTypes();
}
}
private void configureUriWithDefaults(Builder builder) {
if (!getEmbedded().isEnabled() || !ClassUtils.isPresent(EMBEDDED_DRIVER, this.classLoader)) {
builder.uri(DEFAULT_BOLT_URI);
}
}
public static class Embedded {
/**
* Whether to enable embedded mode if the embedded driver is available.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

@ -0,0 +1,92 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.driver.Driver;
import reactor.core.publisher.Flux;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.data.neo4j.config.Neo4jDefaultReactiveCallbacksRegistrar;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;
import org.springframework.transaction.ReactiveTransactionManager;
/**
* Internal configuration for the reactive Neo4j client.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, Flux.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@AutoConfigureBefore(Neo4jReactiveRepositoriesConfiguration.class)
@Import(Neo4jDefaultReactiveCallbacksRegistrar.class)
class Neo4jReactiveDataConfiguration {
@Bean("reactiveDatabaseSelectionProvider")
@ConditionalOnProperty(prefix = "spring.data.neo4j", name = "database")
@ConditionalOnMissingBean
@Order(-30)
ReactiveDatabaseSelectionProvider staticDatabaseSelectionProvider(Neo4jDataProperties dataProperties) {
return ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(dataProperties.getDatabase());
}
@Bean("reactiveDatabaseSelectionProvider")
@ConditionalOnMissingBean
@Order(-20)
ReactiveDatabaseSelectionProvider defaultSelectionProvider() {
return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider();
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)
@ConditionalOnMissingBean
ReactiveNeo4jClient neo4jClient(Driver driver) {
return ReactiveNeo4jClient.create(driver);
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
@ConditionalOnMissingBean(ReactiveNeo4jOperations.class)
ReactiveNeo4jTemplate neo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
ReactiveDatabaseSelectionProvider databaseNameProvider) {
return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(ReactiveTransactionManager.class)
ReactiveTransactionManager transactionManager(Driver driver,
ReactiveDatabaseSelectionProvider databaseNameProvider) {
return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import reactor.core.publisher.Flux;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;
/**
* Imports the registrar for reactive Neo4j repositories.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Flux.class, ReactiveNeo4jRepository.class })
@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class,
ReactiveNeo4jRepositoryConfigurationExtension.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE)
@Import(Neo4jReactiveRepositoriesConfigureRegistrar.class)
final class Neo4jReactiveRepositoriesConfiguration {
}

@ -0,0 +1,54 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import java.lang.annotation.Annotation;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} used to auto-configure reactive Spring Data Neo4j
* Repositories.
*
* @author Michael J. Simons
*/
final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableReactiveNeo4jRepositories.class;
}
@Override
protected Class<?> getConfiguration() {
return SpringDataNeo4jConfiguration.class;
}
@Override
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
return new ReactiveNeo4jRepositoryConfigurationExtension();
}
@EnableReactiveNeo4jRepositories
private static class SpringDataNeo4jConfiguration {
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,45 +16,29 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j
* Repositories.
* <p>
* Activates when there is no bean of type {@link Neo4jRepositoryFactoryBean} configured
* in the context, the Spring Data Neo4j {@link Neo4jRepository} type is on the classpath,
* the Neo4j client driver API is on the classpath, and there is no other configured
* {@link Neo4jRepository}.
* <p>
* Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories
* using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation.
* Shared entry point for the configuration of Spring Data Neo4j repositories in their
* imperative and reactive forms.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Josh Long
* @since 1.4.0
* @author Michael J. Simons
* @see EnableNeo4jRepositories
* @since 1.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Neo4jSession.class, Neo4jRepository.class })
@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true",
matchIfMissing = true)
@Import(Neo4jRepositoriesRegistrar.class)
@ConditionalOnClass(Driver.class)
@AutoConfigureAfter(Neo4jDataAutoConfiguration.class)
@Import({ Neo4jRepositoriesConfiguration.class, Neo4jReactiveRepositoriesConfiguration.class })
public class Neo4jRepositoriesAutoConfiguration {
}

@ -0,0 +1,41 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;
/**
* Imports the registrar for imperative Neo4j repositories.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Neo4jRepository.class)
@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE)
@Import(Neo4jRepositoriesConfigureRegistrar.class)
class Neo4jRepositoriesConfiguration {
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import java.lang.annotation.Annotation;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
@ -29,8 +28,9 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
* Repositories.
*
* @author Michael Hunger
* @author Michael J. Simons
*/
class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {
class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
@ -39,7 +39,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu
@Override
protected Class<?> getConfiguration() {
return EnableNeo4jRepositoriesConfiguration.class;
return SpringDataNeo4jConfiguration.class;
}
@Override
@ -48,7 +48,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu
}
@EnableNeo4jRepositories
private static class EnableNeo4jRepositoriesConfiguration {
private static class SpringDataNeo4jConfiguration {
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,12 +34,11 @@ import org.springframework.core.annotation.AliasFor;
* <li>Set the
* {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...)
* packages scanned} for JPA entities.</li>
* <li>Set the packages used with Neo4J's {@link org.neo4j.ogm.session.SessionFactory
* SessionFactory}.</li>
* <li>Set the
* {@link org.springframework.data.mapping.context.AbstractMappingContext#setInitialEntitySet(java.util.Set)
* initial entity set} used with Spring Data
* {@link org.springframework.data.mongodb.core.mapping.MongoMappingContext MongoDB},
* {@link org.springframework.data.neo4j.core.mapping.Neo4jMappingContext Neo4j},
* {@link org.springframework.data.cassandra.core.mapping.CassandraMappingContext
* Cassandra} and
* {@link org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext
@ -52,6 +51,7 @@ import org.springframework.core.annotation.AliasFor;
* annotation.
*
* @author Phillip Webb
* @author Michael J. Simons
* @since 1.4.0
* @see EntityScanPackages
*/

@ -19,8 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.city.City;
@ -31,13 +29,19 @@ import org.springframework.boot.autoconfigure.data.neo4j.empty.EmptyMarker;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.internal.logging.Slf4jLogging;
import static org.assertj.core.api.Assertions.assertThat;
/**
@ -48,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Michael Hunger
* @author Vince Bickers
* @author Stephane Nicoll
* @author Michael J. Simons
*/
class MixedNeo4jRepositoriesAutoConfigurationTests {
@ -94,7 +99,6 @@ class MixedNeo4jRepositoriesAutoConfigurationTests {
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class));
TestPropertyValues.of(environment).and("spring.datasource.initialization-mode=never").applyTo(context);
context.register(config);
context.register(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
@ -108,7 +112,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests {
@TestAutoConfigurationPackage(EmptyMarker.class)
// Not this package or its parent
@EnableNeo4jRepositories(basePackageClasses = Country.class)
static class TestConfiguration {
static class TestConfiguration extends AbstractNeo4jConfig {
@Override
@Bean
public Driver driver() {
return GraphDatabase.driver("bolt://neo4j.test:7687",
Config.builder().withLogging(new Slf4jLogging()).build());
}
}
@ -117,7 +128,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests {
@EnableNeo4jRepositories(basePackageClasses = Country.class)
@EntityScan(basePackageClasses = City.class)
@EnableJpaRepositories(basePackageClasses = CityRepository.class)
static class MixedConfiguration {
static class MixedConfiguration extends AbstractNeo4jConfig {
@Override
@Bean
public Driver driver() {
return GraphDatabase.driver("bolt://neo4j.test:7687",
Config.builder().withLogging(new Slf4jLogging()).build());
}
}

@ -0,0 +1,49 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.types.TypeSystem;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Driver configuration mocked to avoid instantiation of a real driver with connection
* creation.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
class MockedDriverConfiguration {
@Bean
Driver driver() {
Driver driver = mock(Driver.class);
TypeSystem typeSystem = mock(TypeSystem.class);
Session session = mock(Session.class);
when(driver.defaultTypeSystem()).thenReturn(typeSystem);
when(driver.session(Mockito.any(SessionConfig.class))).thenReturn(session);
return driver;
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,257 +16,168 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.junit.jupiter.api.Test;
import org.neo4j.ogm.driver.NativeTypesNotAvailableException;
import org.neo4j.ogm.driver.NativeTypesNotSupportedException;
import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.event.Event;
import org.neo4j.ogm.session.event.EventListener;
import org.neo4j.ogm.session.event.PersistenceEvent;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.neo4j.city.City;
import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.annotation.EnableBookmarkManagement;
import org.springframework.data.neo4j.bookmark.BookmarkManager;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.springframework.data.neo4j.core.DatabaseSelection;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Tests for {@link Neo4jDataAutoConfiguration}. Tests should not use the embedded driver
* as it requires the complete Neo4j-Kernel and server to function properly.
*
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
* @author Andy Wilkinson
* @author Kazuki Shimizu
* @author Michael Simons
* @author Michael J. Simons
*/
class Neo4jDataAutoConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withClassLoader(new FilteredClassLoader(EmbeddedDriver.class))
.withUserConfiguration(TestConfiguration.class).withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class));
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class));
@Test
void defaultConfiguration() {
this.contextRunner.withPropertyValues("spring.data.neo4j.uri=http://localhost:8989").run((context) -> {
assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class);
assertThat(context).hasSingleBean(SessionFactory.class);
assertThat(context).hasSingleBean(Neo4jTransactionManager.class);
assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class);
assertThat(context).doesNotHaveBean(BookmarkManager.class);
});
}
@Test
void customNeo4jTransactionManagerUsingProperties() {
this.contextRunner.withPropertyValues("spring.transaction.default-timeout=30",
"spring.transaction.rollback-on-commit-failure:true").run((context) -> {
Neo4jTransactionManager transactionManager = context.getBean(Neo4jTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);
assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();
});
void shouldProvideConversions() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class));
}
@Test
void customSessionFactory() {
this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> {
assertThat(context).doesNotHaveBean(org.neo4j.ogm.config.Configuration.class);
assertThat(context).hasSingleBean(SessionFactory.class);
void shouldProvideDefaultDatabaseNameProvider() {
contextRunner.run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider).isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider());
});
}
@Test
void customSessionFactoryShouldNotDisableOtherDefaults() {
this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> {
assertThat(context).hasSingleBean(SessionFactory.class);
assertThat(context.getBean(SessionFactory.class)).isSameAs(context.getBean("customSessionFactory"));
assertThat(context).hasSingleBean(Neo4jTransactionManager.class);
assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class);
void shouldProvideStaticDatabaseNameProviderIfConfigured() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider.getDatabaseSelection()).isEqualTo(DatabaseSelection.byName("foobar"));
});
}
@Test
void customConfiguration() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context.getBean(org.neo4j.ogm.config.Configuration.class))
.isSameAs(context.getBean("myConfiguration"));
assertThat(context).hasSingleBean(SessionFactory.class);
assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class);
});
}
@Test
void usesAutoConfigurationPackageToPickUpDomainTypes() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class));
String cityPackage = City.class.getPackage().getName();
AutoConfigurationPackages.register(context, cityPackage);
context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class);
try {
context.refresh();
assertDomainTypesDiscovered(context.getBean(Neo4jMappingContext.class), City.class);
}
finally {
context.close();
}
void shouldRespectExistingDatabaseNameProvider() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar")
.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider.getDatabaseSelection())
.isEqualTo(DatabaseSelection.byName("whatever"));
});
}
@Test
void openSessionInViewInterceptorCanBeEnabled() {
this.contextRunner.withPropertyValues("spring.data.neo4j.open-in-view:true")
.run((context) -> assertThat(context).hasSingleBean(OpenSessionInViewInterceptor.class));
void shouldRequireAllNeededClasses() {
contextRunner
.withClassLoader(
new FilteredClassLoader(Neo4jTransactionManager.class, PlatformTransactionManager.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jClient.class).doesNotHaveBean(Neo4jTemplate.class)
.doesNotHaveBean(Neo4jTransactionManager.class));
}
@Test
void shouldBeAbleToUseNativeTypesWithBolt() {
this.contextRunner
.withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687",
"spring.data.neo4j.use-native-types:true")
.withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class))
.run((context) -> assertThat(context).getBean(org.neo4j.ogm.config.Configuration.class)
.hasFieldOrPropertyWithValue("useNativeTypes", true));
void shouldCreateNewNeo4jClient() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class));
}
@Test
void shouldFailWhenNativeTypesAreNotAvailable() {
this.contextRunner.withClassLoader(new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types"))
.withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687",
"spring.data.neo4j.use-native-types:true")
.withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure())
.hasRootCauseInstanceOf(NativeTypesNotAvailableException.class);
});
void shouldNotReplaceExistingNeo4jClient() {
contextRunner.withUserConfiguration(ConfigurationWithExistingClient.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient"));
}
@Test
void shouldFailWhenNativeTypesAreNotSupported() {
this.contextRunner
.withPropertyValues("spring.data.neo4j.uri=http://localhost:7474",
"spring.data.neo4j.use-native-types:true")
.withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasFailed();
assertThat(context.getStartupFailure())
.hasRootCauseInstanceOf(NativeTypesNotSupportedException.class);
});
void shouldCreateNewNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(Neo4jTemplate.class);
// Verify that the template uses the provided database name
// provider
Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class);
DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils.getField(template,
"databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class));
});
}
@Test
void eventListenersAreAutoRegistered() {
this.contextRunner.withUserConfiguration(EventListenerConfiguration.class).run((context) -> {
Session session = context.getBean(SessionFactory.class).openSession();
session.notifyListeners(new PersistenceEvent(null, Event.TYPE.PRE_SAVE));
verify(context.getBean("eventListenerOne", EventListener.class)).onPreSave(any(Event.class));
verify(context.getBean("eventListenerTwo", EventListener.class)).onPreSave(any(Event.class));
});
void shouldNotReplaceExistingNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingTemplate.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations"));
}
@Test
void providesARequestScopedBookmarkManagerIfNecessaryAndPossible() {
this.contextRunner.withUserConfiguration(BookmarkManagementEnabledConfiguration.class).run((context) -> {
BeanDefinition bookmarkManagerBean = context.getBeanFactory()
.getBeanDefinition("scopedTarget.bookmarkManager");
assertThat(bookmarkManagerBean.getScope()).isEqualTo(WebApplicationContext.SCOPE_REQUEST);
void shouldCreateNewTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class);
// Verify that the transaction manager uses the provided
// database name provider
Neo4jTransactionManager transactionManager = ctx.getBean(Neo4jTransactionManager.class);
DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils
.getField(transactionManager, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class));
});
}
@Test
void providesASingletonScopedBookmarkManagerIfNecessaryAndPossible() {
new ApplicationContextRunner().withClassLoader(new FilteredClassLoader(EmbeddedDriver.class))
.withUserConfiguration(TestConfiguration.class, BookmarkManagementEnabledConfiguration.class)
.withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasSingleBean(BookmarkManager.class);
assertThat(context.getBeanDefinitionNames()).doesNotContain("scopedTarget.bookmarkManager");
});
void shouldHonourExistingTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingTransactionManager.class)
.run(ctx -> assertThat(ctx).hasSingleBean(PlatformTransactionManager.class)
.hasBean("myCustomTransactionManager"));
}
@Test
void doesNotProvideABookmarkManagerIfNotPossible() {
this.contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class, EmbeddedDriver.class))
.withUserConfiguration(BookmarkManagementEnabledConfiguration.class)
.run((context) -> assertThat(context).doesNotHaveBean(BookmarkManager.class));
}
@Configuration
static class ConfigurationWithExistingClient {
private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext, Class<?>... types) {
for (Class<?> type : types) {
assertThat(mappingContext.getPersistentEntity(type)).isNotNull();
@Bean("myCustomClient")
Neo4jClient neo4jClient(Driver driver) {
return Neo4jClient.create(driver);
}
}
@Configuration(proxyBeanMethods = false)
@EntityScan(basePackageClasses = Country.class)
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
static class CustomSessionFactory {
@Configuration
static class ConfigurationWithExistingTemplate {
@Bean
SessionFactory customSessionFactory() {
return mock(SessionFactory.class);
@Bean("myCustomOperations")
Neo4jOperations neo4jOperations() {
return mock(Neo4jOperations.class);
}
}
@Configuration(proxyBeanMethods = false)
static class CustomConfiguration {
@Configuration
static class ConfigurationWithExistingTransactionManager {
@Bean
org.neo4j.ogm.config.Configuration myConfiguration() {
return new org.neo4j.ogm.config.Configuration.Builder().uri("http://localhost:12345").build();
@Bean("myCustomTransactionManager")
PlatformTransactionManager transactionManager() {
return mock(PlatformTransactionManager.class);
}
}
@Configuration(proxyBeanMethods = false)
@EnableBookmarkManagement
static class BookmarkManagementEnabledConfiguration {
}
@Configuration(proxyBeanMethods = false)
static class EventListenerConfiguration {
@Bean
EventListener eventListenerOne() {
return mock(EventListener.class);
}
@Configuration
static class ConfigurationWithExistingDatabaseSelectionProvider {
@Bean
EventListener eventListenerTwo() {
return mock(EventListener.class);
DatabaseSelectionProvider databaseSelectionProvider() {
return () -> DatabaseSelection.byName("whatever");
}
}

@ -1,191 +0,0 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import java.util.Base64;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.neo4j.ogm.config.AutoIndexMode;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.config.Credentials;
import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link Neo4jProperties}.
*
* @author Stephane Nicoll
* @author Michael Simons
*/
class Neo4jPropertiesTests {
private AnnotationConfigApplicationContext context;
@AfterEach
void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
void defaultUseEmbeddedInMemoryIfAvailable() {
Neo4jProperties properties = load(true);
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, null);
}
@Test
void defaultUseBoltDriverIfEmbeddedDriverIsNotAvailable() {
Neo4jProperties properties = load(false);
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI);
}
@Test
void httpUriUseHttpDriver() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474");
}
@Test
void httpsUriUseHttpDriver() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://localhost:7474");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://localhost:7474");
}
@Test
void boltUriUseBoltDriver() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=bolt://localhost:7687");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, "bolt://localhost:7687");
}
@Test
void fileUriUseEmbeddedServer() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file://var/tmp/graph.db");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file://var/tmp/graph.db");
}
@Test
void credentialsAreSet() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474",
"spring.data.neo4j.username=user", "spring.data.neo4j.password=secret");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474");
assertCredentials(configuration, "user", "secret");
}
@Test
void credentialsAreSetFromUri() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://user:secret@my-server:7474");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://my-server:7474");
assertCredentials(configuration, "user", "secret");
}
@Test
void autoIndexNoneByDefault() {
Neo4jProperties properties = load(true);
Configuration configuration = properties.createConfiguration();
assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.NONE);
}
@Test
void autoIndexCanBeConfigured() {
Neo4jProperties properties = load(true, "spring.data.neo4j.auto-index=validate");
Configuration configuration = properties.createConfiguration();
assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.VALIDATE);
}
@Test
void embeddedModeDisabledUseBoltUri() {
Neo4jProperties properties = load(true, "spring.data.neo4j.embedded.enabled=false");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI);
}
@Test
void embeddedModeWithRelativeLocation() {
Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file:relative/path/to/my.db");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file:relative/path/to/my.db");
}
@Test
void nativeTypesAreSetToFalseByDefault() {
Neo4jProperties properties = load(true);
Configuration configuration = properties.createConfiguration();
assertThat(configuration.getUseNativeTypes()).isFalse();
}
@Test
void nativeTypesCanBeConfigured() {
Neo4jProperties properties = load(true, "spring.data.neo4j.use-native-types=true");
Configuration configuration = properties.createConfiguration();
assertThat(configuration.getUseNativeTypes()).isTrue();
}
private static void assertDriver(Configuration actual, String driver, String uri) {
assertThat(actual).isNotNull();
assertThat(actual.getDriverClassName()).isEqualTo(driver);
assertThat(actual.getURI()).isEqualTo(uri);
}
private static void assertCredentials(Configuration actual, String username, String password) {
Credentials<?> credentials = actual.getCredentials();
if (username == null && password == null) {
assertThat(credentials).isNull();
}
else {
assertThat(credentials).isNotNull();
Object content = credentials.credentials();
assertThat(content).isInstanceOf(String.class);
String[] auth = new String(Base64.getDecoder().decode((String) content)).split(":");
assertThat(auth).containsExactly(username, password);
}
}
Neo4jProperties load(boolean embeddedAvailable, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
if (!embeddedAvailable) {
ctx.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class));
}
TestPropertyValues.of(environment).applyTo(ctx);
ctx.register(TestConfiguration.class);
ctx.refresh();
this.context = ctx;
return this.context.getBean(Neo4jProperties.class);
}
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(Neo4jProperties.class)
static class TestConfiguration {
}
}

@ -0,0 +1,76 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test to ensure that the properties get read and applied during the auto-configuration.
*
* @author Michael J. Simons
*/
@SpringBootTest(properties = "spring.data.neo4j.repositories.type=imperative")
@Testcontainers(disabledWithoutDocker = true)
public class Neo4jRepositoriesAutoConfigurationIntegrationTests {
@Container
private static Neo4jContainer<?> neo4jServer = new Neo4jContainer<>("neo4j:4.0");
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword);
}
private final CountryRepository countryRepository;
@Autowired
Neo4jRepositoriesAutoConfigurationIntegrationTests(CountryRepository countryRepository) {
this.countryRepository = countryRepository;
}
@Test
void ensureRepositoryIsReady() {
assertThat(countryRepository.count()).isEqualTo(0);
}
@Configuration
@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)
@ImportAutoConfiguration({ Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class })
static class TestConfiguration {
}
}

@ -16,25 +16,31 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository;
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
import org.springframework.boot.autoconfigure.data.neo4j.city.City;
import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;
import reactor.core.publisher.Flux;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link Neo4jRepositoriesAutoConfiguration}.
@ -44,73 +50,103 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Michael Hunger
* @author Vince Bickers
* @author Stephane Nicoll
* @author Michael J. Simons
*/
class Neo4jRepositoriesAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jRepositoriesAutoConfigurationTests.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class));
@AfterEach
void close() {
this.context.close();
@Test
void defaultRepositoryConfigurationShouldWork() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.run(ctx -> assertThat(ctx).hasSingleBean(CityRepository.class));
}
@Test
void testDefaultRepositoryConfiguration() {
prepareApplicationContext(TestConfiguration.class);
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
Neo4jMappingContext mappingContext = this.context.getBean(Neo4jMappingContext.class);
assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull();
void repositoryConfigurationShouldNotCreateArbitraryRepos() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx)
.hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class));
}
@Test
void testNoRepositoryConfiguration() {
prepareApplicationContext(EmptyConfiguration.class);
assertThat(this.context.getBean(SessionFactory.class)).isNotNull();
void configurationOfRepositoryTypeShouldWork() {
this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=none")
.withUserConfiguration(TestConfiguration.class).withClassLoader(new FilteredClassLoader(Flux.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jTransactionManager.class)
.doesNotHaveBean(ReactiveNeo4jClient.class).doesNotHaveBean(Neo4jRepository.class));
this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.withUserConfiguration(TestConfiguration.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class)
.hasSingleBean(Neo4jClient.class).doesNotHaveBean(ReactiveNeo4jRepository.class));
}
@Test
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
prepareApplicationContext(CustomizedConfiguration.class);
assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull();
void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx)
.hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class));
}
@Test
void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
prepareApplicationContext(SortOfInvalidCustomConfiguration.class);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.context.getBean(CityRepository.class));
void shouldRespectAtEnableNeo4jRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class)
.doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class)
.doesNotHaveBean(ReactiveCountryRepository.class));
}
private void prepareApplicationContext(Class<?>... configurationClasses) {
this.context = new AnnotationConfigApplicationContext();
TestPropertyValues.of("spring.data.neo4j.uri=http://localhost:9797").applyTo(this.context);
this.context.register(configurationClasses);
this.context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@Test
void shouldRespectAtEnableReactiveNeo4jRepositories() {
this.contextRunner
.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class)
.withPropertyValues("spring.data.neo4j.repositories.type=reactive")
.run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class)
.doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class)
.hasSingleBean(ReactiveCountryRepository.class));
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)
static class WithCustomRepositoryScan {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
@EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class)
static class WithCustomReactiveRepositoryScan {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class)
@EnableNeo4jRepositories(basePackageClasses = CityNeo4jRepository.class)
static class CustomizedConfiguration {
static class WithFakeEnabledReactiveNeo4jRepositories {
@Bean
ReactiveNeo4jRepositoryFactoryBean<?, ?, ?> reactiveNeo4jRepositoryFactoryBean() {
return Mockito.mock(ReactiveNeo4jRepositoryFactoryBean.class);
}
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
}
@Configuration(proxyBeanMethods = false)
// To not find any repositories
@EnableNeo4jRepositories("foo.bar")
@TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class)
static class SortOfInvalidCustomConfiguration {

@ -0,0 +1,197 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.DatabaseSelection;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.ReactiveTransactionManager;
/**
* @author Michael J. Simons
*/
class ReactiveNeo4jDataAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.data.neo4j.repositories.type=reactive")
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class));
@Test
void shouldProvideConversions() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class));
}
@Test
void shouldProvideDefaultDatabaseNameProvider() {
contextRunner.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
assertThat(databaseNameProvider).isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider());
});
}
@Test
void shouldProvideStaticDatabaseNameProviderIfConfigured() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue))
.expectNext("foobar").expectComplete();
});
}
@Test
void shouldRespectExistingDatabaseNameProvider() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar")
.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue))
.expectNext("whatever").expectComplete();
});
}
@Test
void shouldRequireAllNeededClasses() {
contextRunner
.withClassLoader(new FilteredClassLoader(ReactiveNeo4jTransactionManager.class,
ReactiveTransactionManager.class, Flux.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(ReactiveNeo4jClient.class)
.doesNotHaveBean(ReactiveNeo4jTemplate.class)
.doesNotHaveBean(ReactiveNeo4jTransactionManager.class));
}
@Test
void shouldCreateNewReactiveNeo4jClient() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class));
}
@Test
void shouldNotReplaceExistingReactiveNeo4jClient() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveClient.class)
.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class).hasBean("myCustomReactiveClient"));
}
@Test
void shouldCreateNewNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class)
.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveNeo4jTemplate.class);
// Verify that the template uses the provided database name
// provider
ReactiveNeo4jTemplate template = ctx.getBean(ReactiveNeo4jTemplate.class);
ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils
.getField(template, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldNotReplaceExistingNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTemplate.class).run(ctx -> assertThat(ctx)
.hasSingleBean(ReactiveNeo4jOperations.class).hasBean("myCustomReactiveOperations"));
}
@Test
void shouldCreateNewTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class)
.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveNeo4jTransactionManager.class);
// Verify that the transaction manager uses the provided
// database name provider
ReactiveNeo4jTransactionManager transactionManager = ctx
.getBean(ReactiveNeo4jTransactionManager.class);
ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils
.getField(transactionManager, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldHonourExistingTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTransactionManager.class)
.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveTransactionManager.class)
.hasBean("myCustomReactiveTransactionManager"));
}
@Configuration
static class ConfigurationWithExistingReactiveClient {
@Bean("myCustomReactiveClient")
ReactiveNeo4jClient neo4jClient(Driver driver) {
return ReactiveNeo4jClient.create(driver);
}
}
@Configuration
static class ConfigurationWithExistingReactiveTemplate {
@Bean("myCustomReactiveOperations")
ReactiveNeo4jOperations neo4jOperations() {
return mock(ReactiveNeo4jOperations.class);
}
}
@Configuration
static class ConfigurationWithExistingReactiveTransactionManager {
@Bean("myCustomReactiveTransactionManager")
ReactiveTransactionManager transactionManager() {
return mock(ReactiveTransactionManager.class);
}
}
@Configuration
static class ConfigurationWithExistingReactiveDatabaseSelectionProvider {
@Bean
ReactiveDatabaseSelectionProvider databaseNameProvider() {
return () -> Mono.just(DatabaseSelection.byName("whatever"));
}
}
}

@ -18,13 +18,12 @@ package org.springframework.boot.autoconfigure.data.neo4j.city;
import java.io.Serializable;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
@NodeEntity
@Node
public class City implements Serializable {
private static final long serialVersionUID = 1L;
@ -41,9 +40,6 @@ public class City implements Serializable {
private String map;
public City() {
}
public City(String name, Country country) {
this.name = name;
this.country = country;

@ -0,0 +1,26 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j.city;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
public interface ReactiveCityRepository extends ReactiveNeo4jRepository<City, Long> {
}

@ -16,13 +16,13 @@
package org.springframework.boot.autoconfigure.data.neo4j.country;
import java.io.Serializable;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import java.io.Serializable;
@NodeEntity
@Node
public class Country implements Serializable {
private static final long serialVersionUID = 1L;
@ -33,9 +33,6 @@ public class Country implements Serializable {
private String name;
public Country() {
}
public Country(String name) {
this.name = name;
}

@ -0,0 +1,23 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.autoconfigure.data.neo4j.country;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
public interface ReactiveCountryRepository extends ReactiveNeo4jRepository<Country, Long> {
}

@ -1177,19 +1177,6 @@ bom {
]
}
}
library("Neo4j OGM", "3.2.12") {
group("org.neo4j") {
modules = [
"neo4j-ogm-api",
"neo4j-ogm-bolt-driver",
"neo4j-ogm-bolt-native-types",
"neo4j-ogm-core",
"neo4j-ogm-embedded-driver",
"neo4j-ogm-embedded-native-types",
"neo4j-ogm-http-driver"
]
}
}
library("Netty", "4.1.50.Final") {
group("io.netty") {
imports = [

@ -19,7 +19,8 @@ package org.springframework.boot.test.autoconfigure.data.neo4j;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.neo4j.ogm.session.Session;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ -49,7 +50,7 @@ class DataNeo4jTestIntegrationTests {
.withStartupTimeout(Duration.ofMinutes(10));
@Autowired
private Session session;
private Neo4jTemplate neo4jTemplate;
@Autowired
private ExampleRepository exampleRepository;
@ -59,17 +60,16 @@ class DataNeo4jTestIntegrationTests {
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Test
void testRepository() {
ExampleGraph exampleGraph = new ExampleGraph();
exampleGraph.setDescription("Look, new @DataNeo4jTest!");
ExampleGraph exampleGraph = new ExampleGraph("Look, new @DataNeo4jTest!");
assertThat(exampleGraph.getId()).isNull();
ExampleGraph savedGraph = this.exampleRepository.save(exampleGraph);
assertThat(savedGraph.getId()).isNotNull();
assertThat(this.session.countEntitiesOfType(ExampleGraph.class)).isEqualTo(1);
assertThat(this.neo4jTemplate.count(ExampleGraph.class)).isEqualTo(1);
}
@Test

@ -49,7 +49,7 @@ class DataNeo4jTestPropertiesIntegrationTests {
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Test

@ -50,7 +50,7 @@ class DataNeo4jTestWithIncludeFilterIntegrationTests {
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Test

@ -0,0 +1,69 @@
/*
* Copyright (c) 2019-2020 "Neo4j,"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed 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
*
* https://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.springframework.boot.test.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Michael J. Simons
*/
class DataNeo4jTypeExcludeFilterTests {
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
@Test
void matchWithExcludeFilter() throws Exception {
DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithExcludeFilter.class);
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
}
@Test
void matchWithoutExcludeFilter() throws Exception {
DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithoutExcludeFilter.class);
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isFalse();
}
@DataNeo4jTest(
excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExampleRepository.class))
static class WithExcludeFilter {
}
@DataNeo4jTest
static class WithoutExcludeFilter {
}
private boolean excludes(DataNeo4jTypeExcludeFilter filter, Class<?> type) throws IOException {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());
return filter.match(metadataReader, this.metadataReaderFactory);
}
}

@ -16,17 +16,18 @@
package org.springframework.boot.test.autoconfigure.data.neo4j;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
/**
* Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests.
*
* @author Eddú Meléndez
* @author Michael J. Simons
*/
@NodeEntity
@Node
public class ExampleGraph {
@Id
@ -36,6 +37,10 @@ public class ExampleGraph {
@Property
private String description;
public ExampleGraph(String description) {
this.description = description;
}
public Long getId() {
return this.id;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,26 +16,26 @@
package org.springframework.boot.test.autoconfigure.data.neo4j;
import org.neo4j.ogm.session.Session;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.stereotype.Service;
/**
* Example service used with {@link DataNeo4jTest @DataNeo4jTest} tests.
*
* @author Eddú Meléndez
* @author Michael J. Simons
*/
@Service
public class ExampleService {
private final Session session;
private final Neo4jTemplate neo4jTemplate;
public ExampleService(Session session) {
this.session = session;
public ExampleService(Neo4jTemplate neo4jTemplate) {
this.neo4jTemplate = neo4jTemplate;
}
public boolean hasNode(Class<?> clazz) {
return this.session.countEntitiesOfType(clazz) == 1;
return this.neo4jTemplate.count(clazz) == 1;
}
}

@ -0,0 +1,100 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.boot.test.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.ReactiveTransactionManager;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.Duration;
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for the reactive SDN/RX Neo4j test slice.
*
* @author Michael J. Simons
* @since 2.4.0
*/
@DataNeo4jTest
@Testcontainers(disabledWithoutDocker = true)
class ReactiveDataNeo4jIntegrationTests {
@Container
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.0").withoutAuthentication()
.withStartupTimeout(Duration.ofMinutes(10));
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Autowired
private Driver driver;
@Autowired
private ReactiveNeo4jTemplate neo4jTemplate;
@Autowired
private ApplicationContext applicationContext;
@Test
void testTemplate() {
Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(neo4jTemplate::save)
.as(StepVerifier::create).expectNextCount(1).verifyComplete();
try (Session session = driver.session(SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build())) {
long cnt = session.run("MATCH (n:ExampleGraph) RETURN count(n) as cnt").single().get("cnt").asLong();
assertThat(cnt).isEqualTo(1L);
}
}
@Test
void didNotInjectExampleService() {
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));
}
@Test
void didProvideOnlyReactiveTransactionManager() {
assertThat(this.applicationContext.getBean(ReactiveTransactionManager.class))
.isInstanceOf(ReactiveNeo4jTransactionManager.class);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.applicationContext.getBean(PlatformTransactionManager.class));
}
}

@ -14,7 +14,6 @@ dependencies {
compileOnly("org.junit.jupiter:junit-jupiter")
compileOnly("org.junit.platform:junit-platform-engine")
compileOnly("org.mockito:mockito-core")
compileOnly("org.neo4j:neo4j-ogm-core")
compileOnly("org.springframework:spring-context")
compileOnly("org.springframework.data:spring-data-redis")
compileOnly("org.testcontainers:testcontainers")

@ -56,7 +56,6 @@ dependencies {
optional("org.hibernate.validator:hibernate-validator")
optional("org.jboss:jboss-transaction-spi")
optional("org.liquibase:liquibase-core")
optional("org.neo4j:neo4j-ogm-core")
optional("org.slf4j:jul-to-slf4j")
optional("org.slf4j:slf4j-api")
optional("org.springframework:spring-messaging")

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,11 @@
package smoketest.data.neo4j;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
@NodeEntity
@Node
public class Customer {
@Id

Loading…
Cancel
Save