Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document that @DataNeo4jTest does not support transactional tests with a reactive setup #23630

Closed
hantsy opened this issue Oct 11, 2020 · 17 comments
Assignees
Labels
type: documentation A documentation update
Milestone

Comments

@hantsy
Copy link

hantsy commented Oct 11, 2020

The former SDN rx provides a @ReactiveDataNeo4jTest for reactive applications.

I am try to use @DataNeo4jTest(it declared working with Servlet stack and reactive stack) in the new sample, it failed.

Check the test examples: PostRepositoryTest.java

When running this test, I got a transaction exception.

java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test: [DefaultTestContext@4bd31064 testClass = PostRepositoryWithTestContainersTest, testInstance = com.example.demo.PostRepositoryWithTestContainersTest@1440c311, testMethod = testAllPosts@PostRepositoryWithTestContainersTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e3c0e40 testClass = PostRepositoryWithTestContainersTest, locations = '{}', classes = '{class com.example.demo.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@329dbdbf key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@121314f7, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@576d5deb, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@1ffaf86, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@20140db9, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@b783eabf, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3b0fe47a, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@29894581, org.springframework.boot.test.context.SpringBootTestArgs@1], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]
	at org.springframework.util.Assert.state(Assert.java:97) ~[spring-core-5.3.0-RC1.jar:5.3.0-RC1]
	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:199) ~[spring-test-5.3.0-RC1.jar:5.3.0-RC1]
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:289) ~[spring-test-5.3.0-RC1.jar:5.3.0-RC1]
	at org.springframework.test.context.junit.jupiter.SpringExtension.beforeEach(SpringExtension.java:109) ~[spring-test-5.3.0-RC1.jar:5.3.0-RC1]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$1(TestMethodTestDescriptor.java:159) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$5(TestMethodTestDescriptor.java:195) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:195) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:158) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:125) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65) ~[junit-jupiter-engine-5.7.0.jar:5.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) ~[junit-platform-engine-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75) ~[junit-platform-launcher-1.7.0.jar:1.7.0]
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) ~[junit5-rt.jar:na]
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) ~[junit-rt.jar:na]



java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test: [DefaultTestContext@4bd31064 testClass = PostRepositoryWithTestContainersTest, testInstance = com.example.demo.PostRepositoryWithTestContainersTest@1440c311, testMethod = testAllPosts@PostRepositoryWithTestContainersTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e3c0e40 testClass = PostRepositoryWithTestContainersTest, locations = '{}', classes = '{class com.example.demo.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@329dbdbf key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@121314f7, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@576d5deb, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@1ffaf86, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@20140db9, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@b783eabf, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@3b0fe47a, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@29894581, org.springframework.boot.test.context.SpringBootTestArgs@1], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]

	at org.springframework.util.Assert.state(Assert.java:97)
	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:199)
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:289)
	at org.springframework.test.context.junit.jupiter.SpringExtension.beforeEach(SpringExtension.java:109)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$1(TestMethodTestDescriptor.java:159)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$5(TestMethodTestDescriptor.java:195)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:195)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:158)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:125)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 11, 2020
@snicoll
Copy link
Member

snicoll commented Oct 11, 2020

in the new sample, it failed.

That test never worked the way you expect. The Test context framework does not have support for @Test rollback semantic and a reactive transaction manager. See spring-projects/spring-framework#24226

I am try to use @DataNeo4jTest(it declared working with Servlet stack and reactive stack) in

Where have you seen that?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Oct 11, 2020
@snicoll snicoll changed the title @DataNeoj4Test is not working as expected. @DataNeoj4Test does not work with a reactive setup Oct 11, 2020
@hantsy
Copy link
Author

hantsy commented Oct 11, 2020

The newest @DataNeo4jTest ported all features from SDN Rx? there is a testing autoconfiguration.

See here

@DataNeo4jTest provides both imperative and reactive infrastructure by default.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Oct 11, 2020
@hantsy
Copy link
Author

hantsy commented Oct 11, 2020

In the orignal SDN rx, there is another @ReactiveDataNeo4jTest for a reactive app.

@snicoll
Copy link
Member

snicoll commented Oct 11, 2020

See here

That's not in the Spring Boot codebase so you shouldn't rely on that. I am aware of what SDN Rx did and I think I've already mentioned that we've decided to go another route.

Please read my comment again. I mentioned that this test never worked the way you expect. @ReactiveDataNeo4jTest never worked as intended either since the @Test context framework doesn't support that feature at all.

Let's document the limitation in the meantime.

@snicoll snicoll changed the title @DataNeoj4Test does not work with a reactive setup Document that @DataNeoj4Test does not work with a reactive setup Oct 11, 2020
@snicoll snicoll added type: documentation A documentation update and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Oct 11, 2020
@snicoll snicoll added this to the 2.4.x milestone Oct 11, 2020
@snicoll
Copy link
Member

snicoll commented Oct 11, 2020

Removing @Transactional from @DataNeo4jTest would be another option but that would be a breaking change.

@snicoll snicoll added the for: team-attention An issue we'd like other members of the team to review label Oct 11, 2020
@hantsy
Copy link
Author

hantsy commented Oct 11, 2020

Is there any workaround to make my testing codes working again?

@hantsy
Copy link
Author

hantsy commented Oct 12, 2020

@snicoll Return to use @SpringBootTest to make it work.

@wilkinsona wilkinsona changed the title Document that @DataNeoj4Test does not work with a reactive setup Document that @DataNeo4jTest does not work with a reactive setup Oct 12, 2020
@wilkinsona wilkinsona removed the for: team-attention An issue we'd like other members of the team to review label Oct 12, 2020
@snicoll snicoll changed the title Document that @DataNeo4jTest does not work with a reactive setup Make transaction opt-in with @DataNeo4jTest to support reactive setup Oct 12, 2020
@snicoll snicoll added status: noteworthy A noteworthy issue to call out in the release notes type: enhancement A general enhancement and removed type: documentation A documentation update labels Oct 12, 2020
@snicoll
Copy link
Member

snicoll commented Oct 12, 2020

We've decided to remove @Transactional from @DataNeo4jTest to support a reactive setup. This would be a breaking change for users relying on transactional-based test that can hopefully get the previous behaviour by adding @Transactional on such test.

@snicoll snicoll self-assigned this Oct 12, 2020
@sbrannen
Copy link
Member

Another option would be to keep it @Transactional and add a note in the Javadoc that the user can annotate a given test class with @Transactional(propagation = NOT_SUPPORTED) to disable transactional test support. See the "Enabling and Disabling Transactions" section of the Javadoc for details.

@hantsy
Copy link
Author

hantsy commented Oct 13, 2020

@sbrannen I was confused that why transational became a must in this version?

@wilkinsona
Copy link
Member

@sbrannen AIUI, that won't work as there will be no PlatformTransactionManager bean in the context yet the presence of @Transactional at the class level will cause the test framework to require such a bean.

@sbrannen
Copy link
Member

@wilkinsona, I don't think that's the case.

https://github.com/spring-projects/spring-framework/blob/cd835b3124df094c3c4730270e9cb835738a315d/spring-test/src/main/java/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java#L216-L222

In the code above, if the propagation is set to PROPAGATION_NOT_SUPPORTED, the lookup for the TransactionManager will be skipped.

I'll see if I can throw together a simple test case that demonstrates this.

@sbrannen
Copy link
Member

The following test passes.

package example;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.junit.jupiter.api.Test;

import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.transaction.annotation.Propagation.NOT_SUPPORTED;

@SpringJUnitConfig
@TransactionalSliceTest
@Transactional(propagation = NOT_SUPPORTED)
class NonTransactionalTests {

	@Test
	void nonTransactional() {
		assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isFalse();
	}

	@Configuration
	static class Config {
		// no PlatformTransactionManager bean present
	}
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@interface TransactionalSliceTest {
}

If you comment out the @Transactional(propagation = NOT_SUPPORTED) declaration, it will fail with the following.

java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test: [DefaultTestContext@10b892d5 testClass = NonTransactionalTests, testInstance = example.NonTransactionalTests@3d3f761a, testMethod = nonTransactional@NonTransactionalTests, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@3546d80f testClass = NonTransactionalTests, locations = '{}', classes = '{class example.NonTransactionalTests$Config}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]]
	at org.springframework.util.Assert.state(Assert.java:97)
	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:221)
...

@wilkinsona
Copy link
Member

Thanks, @sbrannen. I tried with NEVER and it failed. I should have looked at the code.

Does never need to be treated differently to not supported? If there's no transaction manager then, presumably, there's never going to be a transaction so you don't need one to enforce never's fail-if-there-is-a-transaction semantics.

@sbrannen
Copy link
Member

sbrannen commented Oct 13, 2020

Thanks, @sbrannen. I tried with NEVER and it failed.

I can understand why you'd think NEVER would work the same. Unfortunately that's currently not the case.

See the Javadoc and reference manual for details.

Does never need to be treated differently to not supported? If there's no transaction manager then, presumably, there's never going to be a transaction so you don't need one to enforce never's fail-if-there-is-a-transaction semantics.

Good point. I think it would be safe to support NEVER the same as NOT_SUPPORTED.

TBH, that check was added as a workaround for the removal of the old @NotTransactional annotation from the Spring Framework 2.0 days, and I just didn't see a need to provide two ways to achieve the same thing.

But it certainly won't hurt to make that change. I'll get that done in time for Spring Framework 5.3 GA (see spring-projects/spring-framework#25909).

@snicoll
Copy link
Member

snicoll commented Oct 13, 2020

In case of @DataNeo4jTest, adding @Transactional(propagation = Propagation.NOT_SUPPORTED) does indeed prevent the TCF to check for a PlatformTransactionManager but it fails further down the road as ReactiveCrudRepository#save requires a ReactiveTransactionManager and we haven't auto-configured one:

Suppressed: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'reactiveTransactionManager' available: No matching TransactionManager bean found for qualifier 'reactiveTransactionManager' - neither qualifier match nor bean name match!
		at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:136)
		at org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils.qualifiedBeanOfType(BeanFactoryAnnotationUtils.java:95)
		at org.springframework.transaction.interceptor.TransactionAspectSupport.determineQualifiedTransactionManager(TransactionAspectSupport.java:494)
		at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:475)
		at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:336)
		at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
		at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
		at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
		at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
		at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
		at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
		at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
		at org.springframework.boot.test.autoconfigure.data.neo4j.$Proxy91.save(Unknown Source)
		at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:151)
		... 72 more

The fact this test passes with a non reactive transaction manager puzzles me quite a lot. We'll have to investigate a bit more.

@snicoll
Copy link
Member

snicoll commented Oct 14, 2020

We've changed our mind again based on @sbrannen's feedback and the fact we prefer an extra setup for the minority rather than breaking the mainstream use case. We will have to revisit this arrangement sooner than later which may lead us to remove @Transactional anyway but we think it's too late in 2.4.x to do it.

@snicoll snicoll changed the title Make transaction opt-in with @DataNeo4jTest to support reactive setup Document that @DataNeo4jTest does not work with a reactive setup out-of-the-box Oct 14, 2020
@snicoll snicoll added type: documentation A documentation update and removed status: noteworthy A noteworthy issue to call out in the release notes type: enhancement A general enhancement labels Oct 14, 2020
@snicoll snicoll changed the title Document that @DataNeo4jTest does not work with a reactive setup out-of-the-box Document that @DataNeo4jTest does not support transactional tests with a reactive setup Oct 14, 2020
@snicoll snicoll modified the milestones: 2.4.x, 2.4.0-M4 Oct 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

5 participants