-
Notifications
You must be signed in to change notification settings - Fork 1
Integration CosmosDB Extension
The Kronikol.Extensions.CosmosDB package adds Azure Cosmos DB SDK operation tracking to your test diagrams. Instead of showing raw HTTP requests like POST /dbs/abc123/colls/xyz789/docs, your sequence diagrams show classified operations like Read: /colls/orders/docs/order-1 or Query: /orders.
Using a shared library or abstraction layer? If your code doesn't use the Cosmos DB SDK directly — e.g. it goes through a shared repository library, wrapper, or custom abstraction — this extension won't be able to intercept the underlying calls. See Tracking Custom Dependencies for alternative approaches including
RequestResponseLogger.LogPair(),TrackingProxy<T>, andMessageTracker.
The Azure Cosmos DB SDK translates all operations into HTTP requests internally. CosmosTrackingMessageHandler is a DelegatingHandler that intercepts these HTTP requests, classifies each one into a Cosmos operation (Create, Read, Query, Upsert, etc.) using the HTTP method, URL path, and headers, then logs it to RequestResponseLogger with a human-readable label.
Because it logs to the same RequestResponseLogger as the standard TestTrackingMessageHandler, Cosmos operations appear alongside your HTTP API calls in the same sequence diagram — showing the complete flow from test → API → Cosmos DB.
Important: This requires
ConnectionMode.Gateway. Cosmos DB's Direct mode uses a custom TCP protocol (RNTBD) that bypassesHttpMessageHandlerentirely. All setup methods in this package force Gateway mode automatically.
dotnet add package Kronikol.Extensions.CosmosDBThe extension supports three verbosity levels that control how much detail appears in the diagrams:
| Level | Method shown | URI shown | Headers | Request body | Response body |
|---|---|---|---|---|---|
| Raw | HTTP method (POST, GET, etc.) |
Full SDK URI (with _rid-encoded paths) |
All except excluded set | Full JSON | Full JSON |
| Detailed | Classified operation (Read) |
Clean path without database (/colls/orders/docs/order-1) |
Filtered (noisy Cosmos headers excluded) | SQL text for queries, full JSON for others | Full JSON |
| Summarised | Classified operation (Read) |
Collection name only (/orders) |
None | SQL text for queries only | Full JSON |
The default is Detailed. Response body is shown at all verbosity levels when LogResponseContent = true (the default). Set LogResponseContent = false for empty response arrows (previous behaviour).
| Operation | Raw | Detailed | Summarised |
|---|---|---|---|
| Create a document | POST: /dbs/mydb/colls/orders/docs |
Create: /colls/orders |
Create: /orders |
| Read a document | GET: /dbs/mydb/colls/orders/docs/order-1 |
Read: /colls/orders/docs/order-1 |
Read: /orders |
| Query documents | POST: /dbs/mydb/colls/orders/docs |
Query: /colls/orders |
Query: /orders |
| Upsert a document | POST: /dbs/mydb/colls/orders/docs |
Upsert: /colls/orders |
Upsert: /orders |
| Delete a document | DELETE: /dbs/mydb/colls/orders/docs/order-1 |
Delete: /colls/orders/docs/order-1 |
Delete: /orders |
| Replace a document | PUT: /dbs/mydb/colls/orders/docs/order-1 |
Replace: /colls/orders/docs/order-1 |
Replace: /orders |
| Patch a document | PATCH: /dbs/mydb/colls/orders/docs/order-1 |
Patch: /colls/orders/docs/order-1 |
Patch: /orders |
| List documents | GET: /dbs/mydb/colls/orders/docs |
List: /colls/orders |
List: /orders |
| Execute stored proc | POST: /dbs/mydb/colls/orders/sprocs/mysproc |
ExecStoredProc: /colls/orders/sprocs/mysproc |
ExecStoredProc: /orders |
| Batch operation | POST: /dbs/mydb/colls/orders/docs |
Batch: /colls/orders |
Batch: /orders |
| SDK metadata | GET: /dbs/mydb/colls/orders/pkranges |
Other: /colls/orders |
(skipped) |
The classifier recognises these Cosmos operations from the SDK's HTTP traffic:
| Operation | HTTP Pattern |
|---|---|
Create |
POST /docs (no upsert or query headers) |
Read |
GET /docs/{id} |
Replace |
PUT /docs/{id} |
Patch |
PATCH /docs/{id} |
Delete |
DELETE /docs/{id} |
Upsert |
POST /docs with x-ms-documentdb-is-upsert: true
|
Query |
POST /docs with x-ms-documentdb-isquery: true
|
List |
GET /docs (no document ID) |
ExecStoredProc |
POST /sprocs/{id} |
Batch |
POST /docs/{resourceId} |
Other |
SDK metadata requests (partition key ranges, collection reads, etc.) |
In Summarised mode, Other operations (SDK metadata) are silently skipped.
Which
TestContext? The examples below use xUnit v3'sXunit.TestContext— it's ambient, soTestContext.Currentis always available during test execution with no extra setup. If you're using a different framework (xUnit v2, NUnit, MSTest, TUnit, LightBDD), seeCurrentTestInfoFetcherby Framework below for the equivalent snippet.
CosmosTrackingMessageHandler is a standard DelegatingHandler — it works with any Cosmos DB backend: CosmosDB.InMemoryEmulator, the Microsoft Azure Cosmos DB Emulator, a Testcontainers instance, or a real Azure Cosmos DB account. Choose the setup option that matches your test infrastructure.
Recommendation: CosmosDB.InMemoryEmulator gives you the fastest feedback loop — instant startup, no Docker, no network, and sub-millisecond operations. It also has first-class integration with this tracking extension via
WithHttpMessageHandlerWrapper/WrapHandler. That said, the tracking handler itself is backend-agnostic and works identically regardless of what's behind it.
If you use CosmosDB.InMemoryEmulator with the UseInMemoryCosmosDB() DI extension, use WithHttpMessageHandlerWrapper to insert the tracking handler:
Requires CosmosDB.InMemoryEmulator 2.0.5 or later (the version that added
WithHttpMessageHandlerWrapper). Options B and C below require 3.0.0 or later.
builder.ConfigureTestServices(services =>
{
services.UseInMemoryCosmosDB(options => options
.AddContainer("orders", "/customerId")
.AddContainer("customers", "/id")
.WithHttpMessageHandlerWrapper(fakeHandler =>
new CosmosTrackingMessageHandler(
new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
// xUnit v3: Xunit.TestContext — ambient, always available during test execution
// For other frameworks, see 'CurrentTestInfoFetcher by Framework' below
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
},
fakeHandler)));
});The pipeline becomes:
CosmosClient → CosmosTrackingMessageHandler → FakeCosmosHandler → InMemoryContainer
The tracking handler intercepts and logs every operation, then forwards the request to FakeCosmosHandler which serves in-memory responses.
If you use InMemoryCosmos directly with a single container, use the wrapHandler parameter:
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};
using var cosmos = InMemoryCosmos.Create("orders", "/customerId",
wrapHandler: h => new CosmosTrackingMessageHandler(trackingOptions, h));
var client = cosmos.Client;
var container = cosmos.Container;For enterprise codebases with multiple Cosmos containers, use the InMemoryCosmos.Builder() with .WrapHandler() to insert the tracking handler around the internal routing handler:
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};
using var cosmos = InMemoryCosmos.Builder()
.AddContainer("orders", "/customerId")
.AddContainer("customers", "/id")
.AddContainer("products", "/categoryId")
.WrapHandler(h => new CosmosTrackingMessageHandler(trackingOptions, h))
.Build();
var client = cosmos.Client;
var orders = cosmos.Containers["orders"];
var customers = cosmos.Containers["customers"];
var products = cosmos.Containers["products"];The pipeline becomes:
CosmosClient → CosmosTrackingMessageHandler → RoutingHandler → FakeCosmosHandler[orders] → InMemoryContainer
→ FakeCosmosHandler[customers] → InMemoryContainer
→ FakeCosmosHandler[products] → InMemoryContainer
Key point:
.WrapHandler()wraps the internal routing handler, not individualFakeCosmosHandlerinstances. This means all container traffic flows through a single tracking handler and appears in the diagrams with the correct container name in the label (e.g.Create: /colls/orders,Query: /customers).
Deferred
HttpContextAccessorassignment (v2.26.3+): When usingWrapHandlerinside a collection fixture constructor, DI doesn't exist yet —IHttpContextAccessoris only available after theWebApplicationFactorybuilds its service provider. Assign it after the factory is ready:// In fixture constructor — DI doesn't exist yet: _trackingOptions = new CosmosTrackingMessageHandlerOptions { ServiceName = "CosmosDB", CallerName = "My API", CurrentTestInfoFetcher = CurrentTestInfo.Fetcher // HttpContextAccessor NOT set here }; _cosmos = InMemoryCosmos.Builder() .AddContainer("orders", "/id") .WrapHandler(h => new CosmosTrackingMessageHandler(_trackingOptions, h)) .Build(); // Later, after WebApplicationFactory is built: _trackingOptions.HttpContextAccessor = WebFactory.Services.GetRequiredService<IHttpContextAccessor>();This works because the handler reads
HttpContextAccessorfrom the options object at invocation time, not at construction time.
For use against a real Azure Cosmos DB account or the Microsoft Cosmos DB Emulator:
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};
var clientOptions = new CosmosClientOptions();
clientOptions.WithTestTracking(trackingOptions);
var client = new CosmosClient(connectionString, clientOptions);For the Microsoft Cosmos DB Emulator (which uses self-signed certificates):
var clientOptions = new CosmosClientOptions();
clientOptions.WithTestTrackingAndCustomSslValidation(trackingOptions);
var client = new CosmosClient(
"AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
clientOptions);WithTestTracking forces ConnectionMode.Gateway because Direct mode bypasses HttpMessageHandler.
WithTestTrackingAndCustomSslValidation additionally configures ServerCertificateCustomValidationCallback to accept self-signed certificates.
The pipeline becomes:
CosmosClient → CosmosTrackingMessageHandler → HttpClientHandler → Azure Cosmos DB (or Emulator)
If your production code registers CosmosClient in DI and you're using WebApplicationFactory, replace the client registration in ConfigureTestServices:
builder.ConfigureTestServices(services =>
{
// Remove the existing CosmosClient registration
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(CosmosClient));
if (descriptor is not null) services.Remove(descriptor);
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};
// Option 1: Against a real Azure Cosmos DB account
services.AddSingleton(_ =>
{
var clientOptions = new CosmosClientOptions();
clientOptions.WithTestTracking(trackingOptions);
return new CosmosClient(connectionString, clientOptions);
});
// Option 2: Against the Microsoft Cosmos DB Emulator (self-signed certs)
services.AddSingleton(_ =>
{
var clientOptions = new CosmosClientOptions();
clientOptions.WithTestTrackingAndCustomSslValidation(trackingOptions);
return new CosmosClient(
"AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
clientOptions);
});
});Tip: If you're using Testcontainers to spin up the Cosmos emulator, use the container's connection string in place of the hardcoded emulator endpoint above. The tracking integration is identical.
If you use Testcontainers to manage a Cosmos DB emulator container per test run:
public class CosmosFixture : IAsyncLifetime
{
private readonly CosmosDbEmulatorContainer _container =
new CosmosDbEmulatorBuilder().Build();
public CosmosClient Client { get; private set; } = null!;
public async ValueTask InitializeAsync()
{
await _container.StartAsync();
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My API",
Verbosity = CosmosTrackingVerbosity.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};
var clientOptions = new CosmosClientOptions();
clientOptions.WithTestTrackingAndCustomSslValidation(trackingOptions);
Client = new CosmosClient(_container.GetConnectionString(), clientOptions);
}
public async ValueTask DisposeAsync()
{
Client.Dispose();
await _container.DisposeAsync();
}
}Then share it across tests via xUnit's IClassFixture<CosmosFixture> or ICollectionFixture<CosmosFixture>.
| Property | Type | Default | Description |
|---|---|---|---|
ServiceName |
string |
"CosmosDB" |
The participant name shown in the diagram for the Cosmos DB service |
CallerName |
string |
"Caller" |
The participant name shown for the service making Cosmos calls |
Verbosity |
CosmosTrackingVerbosity |
Detailed |
Controls how much detail appears in the diagram (Raw, Detailed, Summarised) |
CurrentTestInfoFetcher |
Func<(string Name, string Id)>? |
null |
Returns the current test's name and ID. Required — if null, requests are forwarded but not logged |
CurrentStepTypeFetcher |
Func<string?>? |
null |
Optional — returns the current BDD step type (Given/When/Then) |
HttpContextAccessor |
IHttpContextAccessor? |
null |
Optional — enables dual-resolution of test identity from HTTP headers. Auto-resolved by DI extensions (v2.26.3+). See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) |
ExcludedHeaders |
HashSet<string> |
See below | Headers to exclude from diagrams in Raw/Detailed mode |
SetupVerbosity |
CosmosTrackingVerbosity? |
null |
Verbosity override for the Setup phase. See Phase-Aware Tracking |
ActionVerbosity |
CosmosTrackingVerbosity? |
null |
Verbosity override for the Action phase. See Phase-Aware Tracking |
TrackDuringSetup |
bool |
true |
When false, tracking is suppressed during Setup. See Phase-Aware Tracking
|
TrackDuringAction |
bool |
true |
When false, tracking is suppressed during Action. See Phase-Aware Tracking
|
AutoCorrelateWrites |
bool |
true |
When true, tracked write operations (Create, Upsert, Replace) auto-populate TestCorrelationStore for parallel-safe background thread correlation (e.g. Change Feed Processor attribution). See Change Feed Correlation
|
ChangeFeedKeyExtractor |
Func<string, string, string>? |
null |
Optional custom key extractor for Change Feed correlation. When null, uses the default key format cosmos:{ServiceName}:{documentId}
|
LogResponseContent |
bool |
true |
When true, response arrows show the HTTP response body at all verbosity levels. Set to false for empty response arrows (previous behaviour) |
v2.23.0+ Dual-Resolution:
CosmosTrackingMessageHandleraccepts an optionalIHttpContextAccessor? httpContextAccessorconstructor parameter. When provided, the handler resolves test identity from HTTP request headers first (propagated byTestTrackingMessageHandlerthrough the SUT pipeline), then falls back toCurrentTestInfoFetcher. v2.26.3+: SetHttpContextAccessoronCosmosTrackingMessageHandlerOptionsinstead — the tracker reads it automatically. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for full details and examples.
The following Cosmos SDK headers are excluded by default (they add noise without diagnostic value):
Authorizationx-ms-datex-ms-versionx-ms-session-tokenUser-AgentCache-Controlx-ms-cosmos-sdk-supportedcapabilitiesx-ms-cosmos-internal-operation-type
Override ExcludedHeaders to customise:
new CosmosTrackingMessageHandlerOptions
{
ExcludedHeaders = ["Authorization", "x-ms-date"] // Only exclude these two
}Every framework package provides a CurrentTestInfo static class with a Fetcher property. The syntax is identical regardless of framework — just make sure you have the correct using directive for your framework package:
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher| Framework | Package / using directive |
|---|---|
| xUnit v3 | using Kronikol.xUnit3; |
| xUnit v2 | using Kronikol.xUnit2; |
| NUnit 4 | using Kronikol.NUnit4; |
| MSTest | using Kronikol.MSTest; |
| TUnit | using Kronikol.TUnit; |
| LightBDD | using Kronikol.LightBDD; |
| ReqNRoll | using Kronikol.ReqNRoll; |
| BDDfy | using Kronikol.BDDfy.xUnit3; |
Note: If you're already using a framework-specific options class (e.g.
XUnitTestTrackingMessageHandlerOptions) for your main HTTP tracking,CurrentTestInfoFetcheris wired automatically — you only needCurrentTestInfo.Fetcherfor standalone extensions like CosmosDB that use their own options class.
public static CosmosClientOptions WithTestTracking(
this CosmosClientOptions options,
CosmosTrackingMessageHandlerOptions trackingOptions,
HttpMessageHandler? innerHandler = null)Configures CosmosClientOptions to use CosmosTrackingMessageHandler. Forces ConnectionMode.Gateway. The optional innerHandler parameter sets the inner handler (defaults to HttpClientHandler).
public static CosmosClientOptions WithTestTrackingAndCustomSslValidation(
this CosmosClientOptions options,
CosmosTrackingMessageHandlerOptions trackingOptions)Same as WithTestTracking but configures ServerCertificateCustomValidationCallback to accept all certificates.
┌──────────────┐ ┌───────────────────────────────┐ ┌──────────────────────┐
│ Cosmos SDK │ ── HTTP ──► │ CosmosTrackingMessageHandler │ ── HTTP ──► │ Inner Handler │
│ (real) │ ◄── HTTP ── │ • Classifies operation │ ◄── HTTP ── │ (FakeCosmosHandler │
│ │ │ • Logs to RequestResponseLog │ │ or HttpClientHandler)
└──────────────┘ └───────────────────────────────┘ └──────────────────────┘
│
▼
┌──────────────────────┐
│ RequestResponseLogger │
│ (shared with other │
│ tracking handlers) │
└──────────────────────┘
┌──────────────┐ ┌───────────────────────────────┐ ┌────────────────┐
│ Cosmos SDK │ ── HTTP ──► │ CosmosTrackingMessageHandler │ ── HTTP ──► │ RoutingHandler │
│ (real) │ ◄── HTTP ── │ • Classifies operation │ ◄── HTTP ── │ (routes by │
│ │ │ • Logs to RequestResponseLog │ │ container) │
└──────────────┘ └───────────────────────────────┘ └──────┬─────────┘
│ │
▼ ┌──────┴───────┐
┌──────────────────────┐ ┌────────┴────┐ ┌───────┴──────┐
│ RequestResponseLogger │ │FakeHandler │ │FakeHandler │
│ (shared with other │ │ [orders] │ │ [customers] │
│ tracking handlers) │ └─────────────┘ └──────────────┘
└──────────────────────┘
The CosmosTrackingMessageHandler logs to the same RequestResponseLogger used by TestTrackingMessageHandler. This means Cosmos operations appear alongside your HTTP API calls in the same sequence diagram.
TestTrackingMessageHandler |
CosmosTrackingMessageHandler |
|
|---|---|---|
| Target | HTTP calls between services | Cosmos DB SDK internal HTTP calls |
| Method label | HTTP method (GET, POST) |
Classified operation (Read, Create) |
| URI | Real URL | Clean path (database stripped, collection/resource path retained) |
| Service name resolution | Port-based (PortsToServiceNames) |
Fixed (ServiceName property) |
| Header forwarding | Propagates tracking headers downstream | Does not forward headers (SDK manages its own headers) |
| DiagramFocus | Supported | Not supported (SDK-initiated calls aren't from user code) |
| Metadata filtering | None |
Other operations skipped in Summarised mode |
CosmosTrackingMessageHandler implements ITrackingComponent and auto-registers with TrackingComponentRegistry on construction. At report generation time, unused components are automatically detected and surfaced as console warnings and in the diagnostic report (when DiagnosticMode=true). This never throws or fails tests.
See Diagnostics and Debugging for full details on the TrackingComponentRegistry API.
CosmosDB.InMemoryEmulator provides a FakeCosmosHandler that operates at the HTTP message handler level — exactly where CosmosTrackingMessageHandler sits. The two libraries compose naturally via WrapHandler():
var builder = InMemoryCosmos.Builder();
builder.AddContainer("event-stream", "/streamId");
builder.AddContainer("materialized-view", "/streamId");
// Insert CosmosTrackingMessageHandler into the handler chain
builder.WrapHandler(handler => new CosmosTrackingMessageHandler(
new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My Service",
Verbosity = CosmosTrackingVerbosity.Summarised,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher,
},
handler)); // handler = the FakeCosmosHandler from InMemoryEmulator
var result = builder.Build();
var cosmosClient = result.Client;When the CosmosClient is created before the WebApplicationFactory builds its DI container (the standard pattern with InMemoryEmulator), IHttpContextAccessor can't be set at construction time. Set it after the host is built:
// Phase 1: Create CosmosClient (before DI exists)
var trackingOptions = new CosmosTrackingMessageHandlerOptions
{
ServiceName = "CosmosDB",
CallerName = "My Service",
Verbosity = CosmosTrackingVerbosity.Summarised,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher,
// HttpContextAccessor = ??? — can't set yet
};
builder.WrapHandler(handler => new CosmosTrackingMessageHandler(trackingOptions, handler));
var cosmos = builder.Build();
// Phase 2: After WebApplicationFactory is initialized
trackingOptions.HttpContextAccessor =
WebFactory.Services.GetRequiredService<IHttpContextAccessor>();Tip:
CosmosTrackingMessageHandlerOptionsis a mutable record — settingHttpContextAccessorafter construction is the designed pattern for this scenario.
Use CosmosTrackingVerbosity.Summarised for InMemoryEmulator tests. The Detailed and Raw levels show HTTP bodies that are synthetic (generated by the emulator's handler), not real Cosmos wire protocol. Summarised shows clean operation labels (Read, Create, Query, etc.) without the noise.
When using FakeCosmosHandler.FaultInjector to simulate failures (429 Too Many Requests, 503 Service Unavailable), the injected responses are fully visible in diagrams because CosmosTrackingMessageHandler wraps the fake handler — it sees both the outgoing request and the faulted response:
Test -> API: GET /merchants/{id}
API -> CosmosDB: Query: event-stream
API <-- CosmosDB: 429 Too Many Requests
Test <-- API: 500 Internal Server Error
To expose fault injection from a fixture, use InMemoryCosmosResult.GetHandler():
public class CosmosDbFixture
{
private InMemoryCosmosResult? _cosmos;
public void SetFaultInjector(Func<HttpRequestMessage, HttpResponseMessage?>? injector)
{
// GetHandler() returns the FakeCosmosHandler directly,
// bypassing any tracking wrapper
_cosmos?.GetHandler("orders").FaultInjector = injector;
}
}Then in tests:
[Fact]
public async Task Returns_500_when_Cosmos_throttles()
{
_fixture.SetFaultInjector(_ =>
new HttpResponseMessage((HttpStatusCode)429)
{
Content = new StringContent("{}"),
Headers = { RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromMilliseconds(1)) }
});
try
{
var response = await Client.GetAsync("/api/orders/123");
response.StatusCode.Should().Be(HttpStatusCode.InternalServerError);
}
finally
{
_fixture.SetFaultInjector(null); // Always clear in finally
}
}If your application uses a Change Feed Processor, background polling generates tracking entries on threads where TestContext.Current is unavailable. This extension provides ChangeFeedCorrelation to attribute change items back to the originating test using TestCorrelationStore.
When AutoCorrelateWrites is true (the default), every tracked write (Create, Upsert, Replace) populates TestCorrelationStore with the document ID. When the Change Feed processes that document, ChangeFeedCorrelation looks up the test identity from the store.
Wraps a Change Feed Processor delegate to establish TestIdentityScope for each batch of change items:
var processor = container.GetChangeFeedProcessorBuilder<MyDocument>(
"processor",
ChangeFeedCorrelation.Wrap<MyDocument>(
async (changes, ct) =>
{
foreach (var change in changes)
await ProcessChange(change);
},
serviceName: "CosmosDB",
idSelector: doc => doc.Id)) // optional — defaults to "id" property
.Build();For JsonElement-based change feeds:
ChangeFeedCorrelation.WrapJson(
async (changes, ct) => { /* process changes */ },
serviceName: "CosmosDB")See Background Thread Correlation and Parallel-Safe Background Correlation for more details on the correlation system.
Getting Started
Common Tasks
Integration Guides
- Integration xUnit3
- Integration xUnit2
- Integration NUnit
- Integration MSTest
- Integration TUnit
- Integration BDDfy xUnit3
- Integration LightBDD xUnit2
- Integration LightBDD xUnit3
- Integration LightBDD TUnit
- Integration ReqNRoll xUnit2
- Integration ReqNRoll xUnit3
- Integration ReqNRoll TUnit
Extensions
- Integration AtlasDataApi Extension
- Integration BigQuery Extension
- Integration Bigtable Extension
- Integration BlobStorage Extension
- Integration CloudStorage Extension
- Integration CosmosDB Extension
- Integration Dapper Extension
- Integration DynamoDB Extension
- Integration EF Core Relational Extension
- Integration Elasticsearch Extension
- Integration EventBridge Extension
- Integration EventHubs Extension
- Integration Grpc Extension
- Integration Kafka Extension
- Integration MassTransit Extension
- Integration MongoDB Extension
- Integration MySqlConnector Extension
- Integration Npgsql Extension
- Integration Oracle Extension
- Integration PubSub Extension
- Integration Redis Extension
- Integration S3 Extension
- Integration ServiceBus Extension
- Integration SNS Extension
- Integration Spanner Extension
- Integration SqlClient Extension
- Integration Sqlite Extension
- Integration SQS Extension
- Integration StorageQueues Extension
- Integration OpenTelemetry Extension
- Integration DispatchProxy Extension
- Integration MediatR Extension
- Integration PlantUML IKVM
Configuration
- Tracking Dependencies
- Tracking Custom Dependencies
- HTTP Tracking Setup
- Report Configuration
- Diagram Customisation
- Phase-Aware Tracking
- Content Formatting
- PlantUML Server Configuration
Features
- Generated Reports
- Search Syntax
- Component Diagrams
- PlantUML Browser Rendering
- Inline SVG Rendering
- Internal Flow Tracking
- Tags and Attributes
- Excluding Requests
- Excluded Headers
- Multi-Host Test Architectures
- Event-Driven Architecture Testing
- Service Bus Tracking Patterns
- Background Thread Correlation
- Parallel-Safe Background Correlation
- Event & Message Tracking
- Assertion Tracking
- Step Tracking
- Tabular Attributes
- Large Response and Diagram Handling
- Diagnostics and Debugging
- CI Summary Integration
- CI Artifact Upload
Reference