Skip to content

test(cryptography): wait for CompleteAsync in the empty-stream tests - #1925

Draft
nelson-parente wants to merge 1 commit into
dapr:masterfrom
nelson-parente:test/cryptography-empty-stream-complete-race
Draft

nelson-parente wants to merge 1 commit into
dapr:masterfrom
nelson-parente:test/cryptography-empty-stream-complete-race

Conversation

@nelson-parente

Copy link
Copy Markdown
Contributor

Description

EncryptionStreamProcessorTests.ProcessStreamAsync_WithEmptyStream_SendsNoRequests can fail with this error:

Moq.MockException : Expected invocation on the mock once, but was 0 times: x => x.CompleteAsync()

The same error message lists CompleteAsync() under "Performed invocations", so the call happened, but after the verification. Master run 36749821550 on 2026-09-30 failed this way in Unit Tests .NET 8.0 / test/Dapr.Cryptography.Test. Since 2026-09-25 it is the only failure of the Cryptography unit jobs in the 20 sdk_build runs (64 jobs), so it is rare.

ProcessStreamAsync writes the requests and reads the responses on two separate tasks. The writer calls CompleteAsync in its finally block. In the test, the mocked response stream ends at once. So the reader can complete the output channel before the writer reaches CompleteAsync, and await foreach over GetProcessedDataAsync then returns before the call. With a real gRPC call this order cannot occur, because the server ends its response stream only after the client completes the request stream.

The tests ProcessStreamAsync_SendsOptionsOnlyInFirstRequest and ProcessStreamAsync_AssignsSequenceNumbersInOrder in the same files already handle this. They set a TaskCompletionSource in the CompleteAsync callback and wait for it before they assert. This PR applies the same pattern to ProcessStreamAsync_WithEmptyStream_SendsNoRequests in EncryptionStreamProcessorTests and DecryptionStreamProcessorTests, which have the same race. The change is in the tests only.

Issue reference

No issue.

Checklist

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation (not applicable)

Local checks (.NET SDK 10.0.401, macOS arm64)

  • To force the race, a local-only probe (not in this PR) delayed the writer. It gave the encryption test an empty input stream whose read waits 200 ms. Without the wait, the verification failed in 3 of 3 runs with the same MockException as CI. With the wait from this PR, it passed in 3 of 3 runs.
  • With this change, 20 of 20 full Dapr.Cryptography.Test runs (81 tests) passed on net10.0.
  • The test project builds for net8.0, net9.0 and net10.0 with no warnings. Only the .NET 10 runtime was available locally, so the net8.0 and net9.0 tests did not run.

🤖 Generated with Claude Code

https://claude.ai/code/session_017JhKUDV9dbs5JDz2uwZqz5

ProcessStreamAsync writes requests and reads responses on two separate
tasks. With a mocked response stream that ends at once, the reader can
complete the output channel before the writer calls CompleteAsync, so
Verify(CompleteAsync, Times.Once) can run too early. Wait for the request
stream to complete before the verification, as the other tests in these
files already do.

Signed-off-by: Nelson Parente <nelson_parente@live.com.pt>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017JhKUDV9dbs5JDz2uwZqz5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant