Is your feature request related to a problem? Please describe.
Request: Make it possible for test setup to override ActivityOptions set for activities in workflow.
Problem:
In production code I have high retry count on activities, but in testing I want to override that to have maxAttempts=1 so that workflow gets it’s failure right away. Or in case I didn’t mock some activity properly the test will fail right away with NullPointerException instead of hanging indefinitely.
Another thing is that, when stubbing activities in workflow I hardcode the queue name, because it might not be the same the workflow is on. And in tests I need to override it to make things run, without reproducing all the queue-worker combinations in prod.
Describe the solution you'd like
Sth like overrideAllActivityOptions or overrideActivityOptions in example below.
import io.temporal.activity.ActivityOptions
import io.temporal.client.WorkflowException
import io.temporal.client.WorkflowOptions
import io.temporal.common.RetryOptions
import io.temporal.failure.ActivityFailure
import io.temporal.failure.ApplicationFailure
import io.temporal.testing.TestWorkflowEnvironment
import io.temporal.worker.WorkflowImplementationOptions
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.ArgumentMatchers.anyString
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
class HelloWorldWorkflowImplTest {
private val taskQueue = "TASK_QUEUE"
private val testEnv = TestWorkflowEnvironment.newInstance();
private val testActivityOptions = ActivityOptions.newBuilder()
.setTaskQueue(taskQueue)
.setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).validateBuildWithDefaults())
.validateAndBuildWithDefaults()
private val opts = WorkflowImplementationOptions.newBuilder()
.setFailWorkflowExceptionTypes(
Throwable::class.java,
)
.setDefaultActivityOptions(
testActivityOptions
)
.overrideAllActivityOptions(
testActivityOptions
)
.overrideActivityOptions(
mapOf(HelloWorldActivities::class.java to testActivityOptions)
)
.build()!!
private val worker = testEnv.newWorker(taskQueue).also {
it.registerWorkflowImplementationTypes(
opts,
HelloWorldWorkflowImpl::class.java
)
}
@Test
fun `activity error should fail workflow`() {
val formatActivities = mock<HelloWorldActivities>()
var count = 1
whenever(formatActivities.composeGreeting(anyString())).then {
println("CALL $count")
count += 1
error("test error")
}
worker.registerActivitiesImplementations(formatActivities)
testEnv.start()
val workflow = testEnv.workflowClient.newWorkflowStub(
HelloWorldWorkflow::class.java,
WorkflowOptions.newBuilder().setTaskQueue(taskQueue).build()!!
)
try {
workflow.getGreeting("Mock")
error("unreachable")
} catch (e: WorkflowException) {
assertTrue(e.cause is ActivityFailure)
assertTrue(e.cause?.cause is ApplicationFailure)
assertEquals(
"test error",
(e.cause?.cause as ApplicationFailure).originalMessage
)
}
}
}
Describe alternatives you've considered
Right now I am flagging to code directly to use testActivityOptions when executed from test.
@BeforeEach
fun `setup overrides`() {
GlobalWorkflowOptions.set(testActivityOptions)
}
@AfterEach
fun `reset overrides`() {
GlobalWorkflowOptions.clear()
}
and in code
class HelloWorldWorkflowImpl : HelloWorldWorkflow {
private val activityOptions = ActivityOptions.newBuilder()
.setTaskQueue(HELLO_WORLD_TASK_QUEUE)
.setStartToCloseTimeout(Duration.ofSeconds(60))
.validateAndBuildWithDefaults()!!
private val activity = Workflow.newActivityStub(
HelloWorldActivities::class.java,
GlobalWorkflowOptions.activityOptions(activityOptions)
)
override fun getGreeting(name: String): String {
return activity.composeGreeting(name)
}
}
Is your feature request related to a problem? Please describe. Request: Make it possible for test setup to override ActivityOptions set for activities in workflow.
Problem: In production code I have high retry count on activities, but in testing I want to override that to have maxAttempts=1 so that workflow gets it’s failure right away. Or in case I didn’t mock some activity properly the test will fail right away with NullPointerException instead of hanging indefinitely.
Another thing is that, when stubbing activities in workflow I hardcode the queue name, because it might not be the same the workflow is on. And in tests I need to override it to make things run, without reproducing all the queue-worker combinations in prod.
Describe the solution you'd like
Sth like
overrideAllActivityOptions
oroverrideActivityOptions
in example below.Describe alternatives you've considered Right now I am flagging to code directly to use testActivityOptions when executed from test.
and in code
Additional context https://community.temporal.io/t/throwing-exception-in-mocked-activity-hangs-the-test/10932
Related issues: #499 #626