Add and remove an integration
The run omits a capability it cannot serve. A test that needs it skips with a reason. This lesson watches that happen, adds the missing piece, and takes it away again.
- Run a capability-gated journey and read its skip.
- Add the broker to the composition and watch the same journey pass.
- Remove it again without touching the test.
- Capabilities and the host (lesson 1).
- For the container step: Docker running. The skip and its archive need nothing installed.
The scenario
The broker journey pays an invoice and then waits for the application's invoice.paid event on its own tap. In an ordinary run it skips: no broker is configured.
The journey is not broken. The run simply cannot serve the capability it declares, and the skip says so before the test starts.
The journey and its gate
BrokerJourney declares the capability it needs on the class:
[Application(NorthstarTargets.Api)]
[NorthstarMember(PlanIds.Growth)]
[RequiresCapability(ProtoCapabilityKinds.Broker)]
public sealed class BrokerJourney
Run it alone and the runner reports a skip:
dotnet test samples/Northstar.ProtoTest --filter "FullyQualifiedName~BrokerJourney"
The reason is the one the composition registered: "No broker is configured; set ProtoTest:Messaging:Broker=container."
The composition decides
This is ConfigureMessaging from Setup.cs:
1private static void ConfigureMessaging(IProtoHostBuilder builder, NorthstarRun run)2{3// Registered last so the application exists before messaging binds its taps. The tap is declared4// in code so it is bound during setup, not at the first await, and cannot miss the publish.5if (run.UsesMessaging)6{7builder.AddMessaging(messaging => messaging8.CaptureAttachments()9.UseRabbitMq()10.Declare("invoice.paid")11.Tap("invoice.paid"));12}13else14{15builder.AddMessaging(messaging => messaging.CaptureAttachments());16}17}
- One switch, two compositions
The run decides per configuration whether it has a broker, and the test never asks.
- Messaging with attachments
Both branches compose messaging; only the adapter differs.
- The adapter is the capability
UseRabbitMq declares the Broker capability and registers the broker as a run resource. Without an adapter, the in-memory default serves the API but declares no Broker capability.
- Declare and tap before the first await
The event is declared and tapped during setup, so the test cannot miss a publish.
- No adapter, no capability
The in-memory broker keeps the API usable, and a test that needs a real broker skips instead of passing against the double.
samples/Northstar.ProtoTest/Setup.cs. The reason in the skip comes from AddCapabilityReason(ProtoCapabilityKinds.Broker, "No broker is configured; ...") in the same file.What the skipped run recorded
Open l2-broker-skip.prototrace and the run has no tests in it. Its only operations are the run's own releases: the broker resource, the readiness probe and the loopback application. No setup, no execution, no checks.
That is worth knowing before you debug a skip: there is no test trace to read, because the test never started. The runner output is where the reason lives, and the reason is real text from the composition, not a generic "test skipped".
Add the broker
Give the run a broker it owns. The container needs Docker:
$env:ProtoTest__Messaging__Broker = "container"
dotnet test samples/Northstar.ProtoTest --filter "FullyQualifiedName~BrokerJourney"
The run starts a RabbitMQ container, the journey pays the invoice over REST, and the test awaits invoice.paid on the tap. It passes, and the trace now holds the request, the messaging publish and await, and the container in the run layer. The test file did not change.
Remove it
Start a new terminal, or clear the variable, and run the journey again. Clear it with -ErrorAction SilentlyContinue so the command also works in a terminal that never set it:
Remove-Item Env:ProtoTest__Messaging__Broker -ErrorAction SilentlyContinue
dotnet test samples/Northstar.ProtoTest --filter "FullyQualifiedName~BrokerJourney"
The skip is back, with the same reason. The composition reads the setting once per run, so adding or removing an integration is a run decision.
The same run, both ways
The whole lesson is one setting and its two outcomes. Nothing in BrokerJourney changes between them.
| No broker configured | ProtoTest__Messaging__Broker=container | |
|---|---|---|
| The run's messaging | the in-memory default, no adapter | UseRabbitMq(), which declares the Broker capability |
| Run resources | the in-memory broker resource | the RabbitMQ container the run owns |
BrokerJourney | skipped, with the registered reason | runs: it pays the invoice and awaits invoice.paid |
| The archive | three releases and no test | the request, the publish, the await and the container |
| The test file | unchanged | unchanged |
Checkpoint
The skipped run's trace holds three entries, all of them releases, and no test execution. Why not?
AddCapabilityReason.What you learned
- The run omits a capability it cannot serve.
- A gated test skips before its lifecycle starts, so its trace holds no test.
- Adding or removing an integration is a composition change, not a test change.