AbstractCoroutinesTransactionAspectTests.kt (spring-framework-5.3.23) | : | AbstractCoroutinesTransactionAspectTests.kt (spring-framework-5.3.24) | ||
---|---|---|---|---|
/* | /* | |||
* Copyright 2002-2021 the original author or authors. | * Copyright 2002-2022 the original author or authors. | |||
* | * | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | |||
* | * | |||
* https://www.apache.org/licenses/LICENSE-2.0 | * https://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
package org.springframework.transaction.interceptor | package org.springframework.transaction.interceptor | |||
import kotlinx.coroutines.delay | import kotlinx.coroutines.delay | |||
import kotlinx.coroutines.runBlocking | import kotlinx.coroutines.runBlocking | |||
import org.assertj.core.api.Assertions | import org.assertj.core.api.Assertions.assertThat | |||
import org.assertj.core.api.Fail | import org.assertj.core.api.Fail | |||
import org.junit.jupiter.api.BeforeEach | import org.junit.jupiter.api.BeforeEach | |||
import org.junit.jupiter.api.Test | import org.junit.jupiter.api.Test | |||
import org.mockito.BDDMockito | import org.mockito.BDDMockito | |||
import org.mockito.Mockito | import org.mockito.Mockito | |||
import org.springframework.transaction.* | import org.springframework.transaction.* | |||
import org.springframework.transaction.reactive.TransactionContext | import org.springframework.transaction.reactive.TransactionContext | |||
import reactor.core.publisher.Mono | import reactor.core.publisher.Mono | |||
import reactor.core.publisher.SynchronousSink | import reactor.core.publisher.SynchronousSink | |||
import reactor.util.context.ContextView | import reactor.util.context.ContextView | |||
skipping to change at line 191 | skipping to change at line 191 | |||
/** | /** | |||
* Check that the when exception thrown by the target can produce the | * Check that the when exception thrown by the target can produce the | |||
* desired behavior with the appropriate transaction attribute. | * desired behavior with the appropriate transaction attribute. | |||
* @param ex exception to be thrown by the target | * @param ex exception to be thrown by the target | |||
* @param shouldRollback whether this should cause a transaction rollback | * @param shouldRollback whether this should cause a transaction rollback | |||
*/ | */ | |||
protected fun doTestRollbackOnException( | protected fun doTestRollbackOnException( | |||
ex: Exception, shouldRollback: Boolean, rollbackException : Boolean) { | ex: Exception, shouldRollback: Boolean, rollbackException : Boolean) { | |||
val txatt: TransactionAttribute = object : DefaultTransactionAttr ibute() { | val txatt: TransactionAttribute = object : DefaultTransactionAttr ibute() { | |||
override fun rollbackOn(t: Throwable): Boolean { | override fun rollbackOn(t: Throwable): Boolean { | |||
Assertions.assertThat(t).isSameAs(ex) | assertThat(t).isSameAs(ex) | |||
return shouldRollback | return shouldRollback | |||
} | } | |||
} | } | |||
val m = exceptionalMethod | val m = exceptionalMethod | |||
val tas = MapTransactionAttributeSource() | val tas = MapTransactionAttributeSource() | |||
tas.register(m!!, txatt) | tas.register(m!!, txatt) | |||
val status = Mockito.mock(ReactiveTransaction::class.java) | val status = Mockito.mock(ReactiveTransaction::class.java) | |||
val rtm = Mockito.mock(ReactiveTransactionManager::class.java) | val rtm = Mockito.mock(ReactiveTransactionManager::class.java) | |||
// Gets additional call(s) from TransactionControl | // Gets additional call(s) from TransactionControl | |||
BDDMockito.given(rtm.getReactiveTransaction(txatt)).willReturn(Mo no.just(status)) | BDDMockito.given(rtm.getReactiveTransaction(txatt)).willReturn(Mo no.just(status)) | |||
skipping to change at line 221 | skipping to change at line 221 | |||
BDDMockito.given(rtm.rollback(status)).willReturn(Mono.em pty()) | BDDMockito.given(rtm.rollback(status)).willReturn(Mono.em pty()) | |||
} | } | |||
val tb = DefaultTestBean() | val tb = DefaultTestBean() | |||
val itb = advised(tb, rtm, tas) as TestBean | val itb = advised(tb, rtm, tas) as TestBean | |||
runBlocking { | runBlocking { | |||
try { | try { | |||
itb.exceptional(ex) | itb.exceptional(ex) | |||
} | } | |||
catch (actual: Exception) { | catch (actual: Exception) { | |||
if (rollbackException) { | if (rollbackException) { | |||
Assertions.assertThat(actual).hasMessage( tex.message).isInstanceOf(tex::class.java) | assertThat(actual).hasMessage(tex.message ).isInstanceOf(tex::class.java) | |||
} else { | } else { | |||
Assertions.assertThat(actual).hasMessage( ex.message).isInstanceOf(ex::class.java) | assertThat(actual).hasMessage(ex.message) .isInstanceOf(ex::class.java) | |||
} | } | |||
} | } | |||
} | } | |||
if (!rollbackException) { | if (!rollbackException) { | |||
if (shouldRollback) { | if (shouldRollback) { | |||
Mockito.verify(rtm).rollback(status) | Mockito.verify(rtm).rollback(status) | |||
} else { | } else { | |||
Mockito.verify(rtm).commit(status) | Mockito.verify(rtm).commit(status) | |||
} | } | |||
} | } | |||
skipping to change at line 262 | skipping to change at line 262 | |||
throw UnsupportedOperationException( | throw UnsupportedOperationException( | |||
"Shouldn't have invoked target me thod when couldn't create transaction for transactional method") | "Shouldn't have invoked target me thod when couldn't create transaction for transactional method") | |||
} | } | |||
} | } | |||
val itb = advised(tb, rtm, tas) as TestBean | val itb = advised(tb, rtm, tas) as TestBean | |||
runBlocking { | runBlocking { | |||
try { | try { | |||
itb.getName() | itb.getName() | |||
} | } | |||
catch (actual: Exception) { | catch (actual: Exception) { | |||
Assertions.assertThat(actual).isInstanceOf(Cannot CreateTransactionException::class.java) | assertThat(actual).isInstanceOf(CannotCreateTrans actionException::class.java) | |||
} | } | |||
} | } | |||
} | } | |||
/** | /** | |||
* Simulate failure of the underlying transaction infrastructure to commi t. | * Simulate failure of the underlying transaction infrastructure to commi t. | |||
* Check that the target method was invoked, but that the transaction | * Check that the target method was invoked, but that the transaction | |||
* infrastructure exception was thrown to the client | * infrastructure exception was thrown to the client | |||
*/ | */ | |||
@Test | @Test | |||
skipping to change at line 294 | skipping to change at line 294 | |||
BDDMockito.given(rtm.commit(status)).willReturn(Mono.error(ex)) | BDDMockito.given(rtm.commit(status)).willReturn(Mono.error(ex)) | |||
BDDMockito.given(rtm.rollback(status)).willReturn(Mono.empty()) | BDDMockito.given(rtm.rollback(status)).willReturn(Mono.empty()) | |||
val tb = DefaultTestBean() | val tb = DefaultTestBean() | |||
val itb = advised(tb, rtm, tas) as TestBean | val itb = advised(tb, rtm, tas) as TestBean | |||
val name = "new name" | val name = "new name" | |||
runBlocking { | runBlocking { | |||
try { | try { | |||
itb.setName(name) | itb.setName(name) | |||
} | } | |||
catch (ex: Exception) { | catch (ex: Exception) { | |||
Assertions.assertThat(ex).isInstanceOf(RuntimeExc | assertThat(ex).isInstanceOf(RuntimeException::cla | |||
eption::class.java) | ss.java) | |||
Assertions.assertThat(ex.cause).hasMessage(ex.mes | assertThat(ex.cause).hasMessage(ex.message).isIns | |||
sage).isInstanceOf(ex::class.java) | tanceOf(ex::class.java) | |||
} | } | |||
// Should have invoked target and changed name | // Should have invoked target and changed name | |||
Assertions.assertThat(itb.getName()).isEqualTo(name) | assertThat(itb.getName()).isEqualTo(name) | |||
} | } | |||
} | } | |||
private fun checkReactiveTransaction(expected: Boolean) { | private fun checkReactiveTransaction(expected: Boolean) { | |||
Mono.deferContextual{context -> Mono.just(context)} | Mono.deferContextual{context -> Mono.just(context)} | |||
.handle { context: ContextView, sink: Synchronous Sink<Any?> -> | .handle { context: ContextView, sink: Synchronous Sink<Any?> -> | |||
if (context.hasKey(TransactionContext::cl ass.java) != expected) { | if (context.hasKey(TransactionContext::cl ass.java) != expected) { | |||
Fail.fail<Any>("Should have throw n NoTransactionException") | Fail.fail<Any>("Should have throw n NoTransactionException") | |||
} | } | |||
sink.complete() | sink.complete() | |||
End of changes. 8 change blocks. | ||||
11 lines changed or deleted | 11 lines changed or added |