Skip to content

Commit e2c67a7

Browse files
authored
Merge pull request #12 from AxonFramework/feature/10-gateway-extension-test
Feature/10 gateway extension test
2 parents ff8749e + 972d7b0 commit e2c67a7

File tree

12 files changed

+541
-132
lines changed

12 files changed

+541
-132
lines changed

kotlin/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
~ Copyright (c) 2010-2018. Axon Framework
3+
~ Copyright (c) 2010-2020. Axon Framework
44
~
55
~ Licensed under the Apache License, Version 2.0 (the "License");
66
~ you may not use this file except in compliance with the License.
Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,35 @@
1-
/*-
2-
* #%L
3-
* Axon Framework Kotlin Extension
4-
* %%
5-
* Copyright (C) 2019 AxonIQ
6-
* %%
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
74
* Licensed under the Apache License, Version 2.0 (the "License");
8-
* you may not use this file except in compliance with the License.
9-
* You may obtain a copy of the License at
10-
*
11-
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
13-
* Unless required by applicable law or agreed to in writing, software
14-
* distributed under the License is distributed on an "AS IS" BASIS,
15-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
* See the License for the specific language governing permissions and
17-
* limitations under the License.
18-
* #L%
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
1915
*/
2016
package org.axonframework.extensions.kotlin
2117

22-
import org.axonframework.commandhandling.CommandCallback
2318
import org.axonframework.commandhandling.CommandMessage
2419
import org.axonframework.commandhandling.gateway.CommandGateway
2520
import org.axonframework.messaging.MetaData
26-
import java.util.concurrent.TimeUnit
2721

2822
/**
29-
* Extension for command gateway.
23+
* Callback-style [CommandGateway.send] with dedicated on-success and on-error functions
24+
* @param command The command to send
25+
* @param onError Callback to handle failed execution
26+
* @param onSuccess Callback to handle successful execution
27+
* @param [R] the type of result of the command handling
28+
* @param [C] the type of payload of the command
29+
* @see CommandGateway.send
3030
*/
31-
object CommandGatewayExtensions {
32-
/**
33-
* Callback-style send with dedicated on-success and on-error functions (defaults do nothing)
34-
*/
35-
inline fun <reified C : Any, reified R : Any?> CommandGateway.send(
36-
command: C,
37-
crossinline onSuccess: (commandMessage: CommandMessage<out C>, result: R, metaData: MetaData) -> Unit = { _, _, _ -> },
38-
crossinline onError: (commandMessage: CommandMessage<out C>, exception: Throwable, metaData: MetaData) -> Unit = { _, _, _ -> }
39-
) {
40-
this.send(command, CommandCallback<C, R> { commandMessage, callBack ->
41-
val metaData = callBack.metaData ?: MetaData.emptyInstance()
42-
if (callBack.isExceptional) {
43-
onError(commandMessage, callBack.exceptionResult(), metaData)
44-
} else {
45-
onSuccess(commandMessage, callBack.payload, metaData)
46-
}
47-
})
48-
}
49-
50-
/**
51-
* Reified version of send and wait.
52-
*/
53-
inline fun <reified R : Any?> CommandGateway.sendAndWaitWithResponse(command: Any) =
54-
this.sendAndWait<R>(command)
55-
56-
/**
57-
* Reified version of send and wait with a timeout (defaulting to {@link TimeUnit.MILLISECONDS} unit)
58-
*/
59-
inline fun <reified R : Any?> CommandGateway.sendAndWaitWithResponse(command: Any, timeout: Long, unit: TimeUnit = TimeUnit.MILLISECONDS) =
60-
this.sendAndWait<R>(command, timeout, unit)
61-
}
31+
fun <C : Any, R : Any?> CommandGateway.send(
32+
command: C,
33+
onSuccess: (commandMessage: CommandMessage<out C>, result: R, metaData: MetaData) -> Unit = { _, _, _ -> },
34+
onError: (commandMessage: CommandMessage<out C>, exception: Throwable, metaData: MetaData) -> Unit = { _, _, _ -> }
35+
): Unit = this.send(command, ResultDiscriminatorCommandCallback<C, R>(onSuccess, onError))

kotlin/src/main/kotlin/org/axonframework/extensions/kotlin/EventUpcaster.kt

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
/*-
2-
* #%L
3-
* Axon Framework Kotlin Extension
4-
* %%
5-
* Copyright (C) 2019 AxonIQ
6-
* %%
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
74
* Licensed under the Apache License, Version 2.0 (the "License");
8-
* you may not use this file except in compliance with the License.
9-
* You may obtain a copy of the License at
10-
*
11-
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
13-
* Unless required by applicable law or agreed to in writing, software
14-
* distributed under the License is distributed on an "AS IS" BASIS,
15-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
* See the License for the specific language governing permissions and
17-
* limitations under the License.
18-
* #L%
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
1915
*/
2016
package org.axonframework.extensions.kotlin
2117

@@ -29,7 +25,7 @@ import kotlin.reflect.KClass
2925
*/
3026
object EventUpcaster {
3127
/**
32-
* Creates a singleEventUpcaster for given type and revisions and calls [IntermediateEventRepresentation#upcastPayload] using the [converter].
28+
* Creates a singleEventUpcaster for given type and revisions and calls [IntermediateEventRepresentation.upcastPayload] using the [converter].
3329
*/
3430
fun <T : Any> singleEventUpcaster(eventType: KClass<*>,
3531
storageType: KClass<T>,

kotlin/src/main/kotlin/org/axonframework/extensions/kotlin/GenericEventMessageExtensions.kt

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
/*-
2-
* #%L
3-
* Axon Framework Kotlin Extension
4-
* %%
5-
* Copyright (C) 2019 AxonIQ
6-
* %%
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
74
* Licensed under the Apache License, Version 2.0 (the "License");
8-
* you may not use this file except in compliance with the License.
9-
* You may obtain a copy of the License at
10-
*
11-
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
13-
* Unless required by applicable law or agreed to in writing, software
14-
* distributed under the License is distributed on an "AS IS" BASIS,
15-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
* See the License for the specific language governing permissions and
17-
* limitations under the License.
18-
* #L%
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
1915
*/
2016
package org.axonframework.extensions.kotlin
2117

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
/*-
2-
* #%L
3-
* Axon Framework Kotlin Extension
4-
* %%
5-
* Copyright (C) 2019 AxonIQ
6-
* %%
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
74
* Licensed under the Apache License, Version 2.0 (the "License");
8-
* you may not use this file except in compliance with the License.
9-
* You may obtain a copy of the License at
10-
*
11-
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
13-
* Unless required by applicable law or agreed to in writing, software
14-
* distributed under the License is distributed on an "AS IS" BASIS,
15-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
* See the License for the specific language governing permissions and
17-
* limitations under the License.
18-
* #L%
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
1915
*/
2016
package org.axonframework.extensions.kotlin
2117

@@ -25,29 +21,46 @@ import java.util.*
2521
import java.util.concurrent.CompletableFuture
2622

2723
/**
28-
* Extensions to access query gateway.
24+
* Reified version of [QueryGateway.query] with explicit query name
25+
* which expects a collection as a response using [org.axonframework.messaging.responsetypes.MultipleInstancesResponseType]
26+
* @param queryName Name of the query
27+
* @param query Query to send
28+
* @param [Q] the type of payload of the query
29+
* @param [R] the type of result of the query
30+
* @return [CompletableFuture] wrapping the result of the query
31+
* @see QueryGateway.query
32+
* @see ResponseTypes
2933
*/
30-
object QueryGatewayExtensions {
31-
32-
/**
33-
* Reified version of queryForMultiple.
34-
*/
35-
inline fun <reified R, reified Q> QueryGateway.queryForMultiple(queryName: String, query: Q): CompletableFuture<List<R>> {
36-
return this.query(queryName, query, ResponseTypes.multipleInstancesOf(R::class.java))
37-
}
38-
39-
/**
40-
* Reified version of queryForSingle.
41-
*/
42-
inline fun <reified R, reified Q> QueryGateway.queryForSingle(queryName: String, query: Q): CompletableFuture<R> {
43-
return this.query(queryName, query, ResponseTypes.instanceOf(R::class.java))
44-
}
34+
inline fun <reified R, reified Q> QueryGateway.queryForMultiple(queryName: String, query: Q): CompletableFuture<List<R>> {
35+
return this.query(queryName, query, ResponseTypes.multipleInstancesOf(R::class.java))
36+
}
4537

46-
/**
47-
* Reified version of queryForOptional.
48-
*/
49-
inline fun <reified R, reified Q> QueryGateway.queryForOptional(queryName: String, query: Q): CompletableFuture<Optional<R>> {
50-
return this.query(queryName, query, ResponseTypes.optionalInstanceOf(R::class.java))
51-
}
38+
/**
39+
* Reified version of [QueryGateway.query] with explicit query name
40+
* which expects a single object as a response using [org.axonframework.messaging.responsetypes.InstanceResponseType]
41+
* @param queryName Name of the query
42+
* @param query Query to send
43+
* @param [Q] the type of payload of the query
44+
* @param [R] the type of result of the query
45+
* @return [CompletableFuture] wrapping the result of the query
46+
* @see QueryGateway.query
47+
* @see ResponseTypes
48+
*/
49+
inline fun <reified R, reified Q> QueryGateway.queryForSingle(queryName: String, query: Q): CompletableFuture<R> {
50+
return this.query(queryName, query, ResponseTypes.instanceOf(R::class.java))
51+
}
5252

53+
/**
54+
* Reified version of [QueryGateway.query] with explicit query name
55+
* which expects an Optional object as a response using [org.axonframework.messaging.responsetypes.OptionalResponseType]
56+
* @param queryName Name of the query
57+
* @param query Query to send
58+
* @param [Q] the type of payload of the query
59+
* @param [R] the type of result of the query
60+
* @return [CompletableFuture] wrapping the result of the query
61+
* @see QueryGateway.query
62+
* @see ResponseTypes
63+
*/
64+
inline fun <reified R, reified Q> QueryGateway.queryForOptional(queryName: String, query: Q): CompletableFuture<Optional<R>> {
65+
return this.query(queryName, query, ResponseTypes.optionalInstanceOf(R::class.java))
5366
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.axonframework.extensions.kotlin
17+
18+
import org.axonframework.commandhandling.CommandCallback
19+
import org.axonframework.commandhandling.CommandMessage
20+
import org.axonframework.commandhandling.CommandResultMessage
21+
import org.axonframework.messaging.MetaData
22+
23+
/**
24+
* Implementation of the [CommandCallback] that is appropriate for dedicated [onError] and [onSuccess] callbacks
25+
* @param onError Callback to handle failed execution. Defaults to an empty function
26+
* @param onSuccess Callback to handle successful execution. Defaults to an empty function
27+
* @param [R] the type of result of the command handling
28+
* @param [C] the type of payload of the command
29+
* @see CommandCallback
30+
* @author Stefan Andjelkovic
31+
*/
32+
internal class ResultDiscriminatorCommandCallback<C, R>(
33+
val onSuccess: (commandMessage: CommandMessage<out C>, result: R, metaData: MetaData) -> Unit,
34+
val onError: (commandMessage: CommandMessage<out C>, exception: Throwable, metaData: MetaData) -> Unit
35+
) : CommandCallback<C, R> {
36+
override fun onResult(commandMessage: CommandMessage<out C>, commandResultMessage: CommandResultMessage<out R>) {
37+
val metaData = commandResultMessage.metaData ?: MetaData.emptyInstance()
38+
if (commandResultMessage.isExceptional) {
39+
onError(commandMessage, commandResultMessage.exceptionResult(), metaData)
40+
} else {
41+
onSuccess(commandMessage, commandResultMessage.payload, metaData)
42+
}
43+
}
44+
}
45+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2010-2020. Axon Framework
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.axonframework.extensions.kotlin
17+
18+
import io.mockk.Runs
19+
import io.mockk.every
20+
import io.mockk.just
21+
import io.mockk.mockk
22+
import io.mockk.verify
23+
import org.axonframework.commandhandling.CommandCallback
24+
import org.axonframework.commandhandling.CommandMessage
25+
import org.axonframework.commandhandling.gateway.CommandGateway
26+
import org.axonframework.messaging.MetaData
27+
import java.util.concurrent.TimeUnit
28+
import kotlin.test.Test
29+
30+
/**
31+
* Tests Command Gateway extensions.
32+
*
33+
* @author Stefan Andjelkovic
34+
*/
35+
class CommandGatewayExtensionsTest {
36+
private val subjectGateway = mockk<CommandGateway>()
37+
38+
private val exampleCommand = ExampleCommand("1")
39+
private val timeoutInterval: Long = 30
40+
private val defaultTimeUnit = TimeUnit.MILLISECONDS
41+
42+
@Test
43+
fun `Send extension should invoke correct method on the gateway`() {
44+
every { subjectGateway.send(exampleCommand, any<CommandCallback<ExampleCommand, Any>>()) } just Runs
45+
46+
subjectGateway.send<ExampleCommand, Any>(command = exampleCommand, onError = { _, _, _ -> }, onSuccess = { _, _, _ -> })
47+
48+
verify { subjectGateway.send(exampleCommand, any<CommandCallback<ExampleCommand, Any>>()) }
49+
}
50+
51+
@Test
52+
fun `Send extension should invoke correct method on the gateway without explicit generic parameters`() {
53+
every { subjectGateway.send(exampleCommand, any<CommandCallback<ExampleCommand, Any>>()) } just Runs
54+
55+
subjectGateway.send(
56+
command = exampleCommand,
57+
onError = { _: Any, _: Throwable, _: MetaData -> },
58+
onSuccess = { _: CommandMessage<out ExampleCommand>, _: Any, _: MetaData -> }
59+
)
60+
61+
verify { subjectGateway.send(exampleCommand, any<CommandCallback<ExampleCommand, Any>>()) }
62+
}
63+
}

0 commit comments

Comments
 (0)