Failed to run TestWorkflowExtension-driven tests against a local Temporal service instance

My team is working on a project that involves multiple Temporal workflow definitions. To accelerate development, we primarily rely on integration tests to launch and validate workflows as they are being developed. While the combination of JUnit 5, TestWorkflowExtension, and an embedded Temporal instance works well, we want to use a locally running Temporal instance in Docker to gain better insights into the execution process using Temporal’s UI tools.

To switch our existing integration tests to use the local Temporal service, we utilize TestWorkflowExtension.Builder::useExternalService(). This setup fails with an error which looks like generic gRPC request parameter validation problem:

io.grpc.StatusRuntimeException: INVALID_ARGUMENT: taskQueue length exceeds limit
	at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:268)
	at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:249)
	at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:167)
	at io.temporal.api.workflowservice.v1.WorkflowServiceGrpc$WorkflowServiceBlockingStub.pollWorkflowTaskQueue(WorkflowServiceGrpc.java:5634)
	at io.temporal.internal.worker.WorkflowPollTask.doPoll(WorkflowPollTask.java:167)
	at io.temporal.internal.worker.WorkflowPollTask.poll(WorkflowPollTask.java:148)
	at io.temporal.internal.worker.WorkflowPollTask.poll(WorkflowPollTask.java:46)
	at io.temporal.internal.worker.Poller$PollExecutionTask.run(Poller.java:314)
	at io.temporal.internal.worker.Poller$PollLoopTask.run(Poller.java:274)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

We get the same problem when try to run JUnit5 tests from the GitHub - temporalio/samples-java: Temporal Java SDK samples when ask them to useExternalService().

Can the community please help identify what might be wrong with our setup?

Java Setup
OpenJDK 17
io.temporal:temporal-testing-junit5:1.5.0
io.temporal:temporal-testing:1.28.0

Docker Compose
Repo: GitHub - temporalio/docker-compose: Temporal docker-compose files
Command: docker compose up
The content of .env

COMPOSE_PROJECT_NAME=temporal
CASSANDRA_VERSION=3.11.9
ELASTICSEARCH_VERSION=7.17.27
MYSQL_VERSION=8
TEMPORAL_VERSION=latest
TEMPORAL_ADMINTOOLS_VERSION=latest
TEMPORAL_UI_VERSION=latest
POSTGRESQL_VERSION=13
POSTGRES_PASSWORD=temporal
POSTGRES_USER=temporal
POSTGRES_DEFAULT_PORT=5432
OPENSEARCH_VERSION=2.5.0

Code Sample

  @RegisterExtension
  val testWorkflowExtension: TestWorkflowExtension =
      getDefaultTestEnvironmentBuilder<WorkflowImpl>()
          // Switches to external Temporal service implementation with default endpoint of 127.0.0.1:7233.
          .useExternalService()
          .build()

  @BeforeEach
  fun setUpTest(testEnv: TestWorkflowEnvironment, worker: Worker) {
      activities = mock(WorkflowActivities::class.java, withSettings().withoutAnnotations())
      worker.registerActivitiesImplementations(activities)
      testEnv.start()
  }

  @Test
  fun `happy path`(workflow: Workflow) {
      val userId = 123L
      given { activities.first(eq(userId)) }.willReturn(true)

      // Start workflow asynchronously to avoid waiting on a separate thread.
      WorkflowClient.start { workflow.start(userId) }
      workflow.signal(SignalDetails(...))

      val condition = timeout(5_000).times(1)
      verify(activities, condition).first(userId)
      verify(activities, condition).second()
  }

Thanks,
Maxim

MYSQL_VERSION=8

Id limit for sql-based persistence is 256 chars.
Test extension task queue name generation here

With @tihomir’s help, we were able to identify the root cause of the problem and implement a workaround.

TestWorkflowExtension generates a queue name that exceeds 256 characters. According to @tihomir, this is the effective limit for queue names in MySQL, PostgreSQL, and Cassandra persistence backends. However, this contradicts the information in the Temporal documentation, which specifies a 1000-character limit.

The workaround is straightforward: initialize the test environment manually instead of relying on TestWorkflowExtension.

private const val TASK_QUEUE = "TASK_QUEUE"

private lateinit var activities: WorkflowActivities
private lateinit var testEnv: TestWorkflowEnvironment
private lateinit var worker: Worker
private lateinit var workflow: Workflow

...

    @BeforeEach
    fun setUpTest() {
        activities = mock(WorkflowActivities::class.java, withSettings().withoutAnnotations())

        testEnv = TestWorkflowEnvironment.newInstance(
            testEnvironmentOptions {
                // Switches to external Temporal service implementation with default endpoint of 127.0.0.1:7233.
                setUseExternalService(true)
            }
        )

        worker = testEnv.newWorker(TASK_QUEUE).apply {
            registerWorkflowImplementationType<WorkflowImpl>()
            registerActivitiesImplementations(activities)
        }

        workflow = testEnv.workflowClient.newWorkflowStub {
            setTaskQueue(TASK_QUEUE)
            setWorkflowExecutionTimeout(5.seconds.toJavaDuration())
        }

        testEnv.start()
    }

    @AfterEach
    fun tearDown() {
        testEnv.close()
    }

    companion object {
        private inline fun testEnvironmentOptions(
            options: TestEnvironmentOptions.Builder.() -> Unit
        ): TestEnvironmentOptions = TestEnvironmentOptions.newBuilder().apply(options).build()
    }