Skip to content

Integration S3 Extension

Aryeh Citron edited this page Apr 27, 2026 · 10 revisions

The TestTrackingDiagrams.Extensions.S3 package adds Amazon S3 operation tracking to your test diagrams. Instead of showing raw HTTP requests like PUT https://my-bucket.s3.us-east-1.amazonaws.com/path/to/file.json, your sequence diagrams show classified operations like PutObject with a clean s3://my-bucket/path/to/file.json URI.

Using a shared library or abstraction layer? If your code doesn't use the S3 SDK directly — e.g. it goes through a shared storage 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>, and MessageTracker.


How It Works

The AWS SDK for .NET translates all S3 operations into HTTP requests to the S3 REST API. S3TrackingMessageHandler is a DelegatingHandler that intercepts these HTTP requests, classifies each one into an S3 operation (PutObject, GetObject, DeleteObject, ListObjectsV2, etc.) using the HTTP method, URL path, query parameters, and headers, then logs it to RequestResponseLogger with a human-readable label.

Because it logs to the same RequestResponseLogger as the standard TestTrackingMessageHandler, S3 operations appear alongside your HTTP API calls in the same sequence diagram — showing the complete flow from test → API → S3.

The classifier handles both path-style (s3.region.amazonaws.com/bucket/key) and virtual-hosted-style (bucket.s3.region.amazonaws.com/key) URL formats.


Install

dotnet add package TestTrackingDiagrams.Extensions.S3

Verbosity Levels

The 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 (PUT, GET, etc.) Full original URI All except excluded set Full content Full content
Detailed Classified operation (PutObject) s3://bucket/key Filtered (noisy AWS headers excluded) Full content Full content
Summarised Classified operation (PutObject) s3://bucket/ None None None

The default is Detailed.

Diagram Label Examples

Operation Raw Detailed Summarised
Upload object PUT: https://...amazonaws.com/bucket/file.json PutObject: s3://bucket/file.json PutObject: s3://bucket/
Download object GET: https://...amazonaws.com/bucket/file.json GetObject: s3://bucket/file.json GetObject: s3://bucket/
Delete object DELETE: https://...amazonaws.com/bucket/file.json DeleteObject: s3://bucket/file.json DeleteObject: s3://bucket/
List objects GET: https://...amazonaws.com/bucket?list-type=2 ListObjectsV2: s3://bucket/ ListObjectsV2: s3://bucket/
Copy object PUT: https://...amazonaws.com/bucket/dest.json CopyObject: s3://bucket/dest.json CopyObject: s3://bucket/
Multipart initiate POST: https://...amazonaws.com/bucket/file.zip?uploads CreateMultipartUpload: s3://bucket/file.zip CreateMultipartUpload: s3://bucket/
Unrecognised PATCH: https://...amazonaws.com/bucket/file Other: s3://bucket/file (skipped)

Classified Operations

The classifier recognises these S3 operations from the SDK's HTTP traffic:

Operation HTTP Pattern
PutObject PUT /{bucket}/{key} (no copy header, no partNumber or tagging query)
GetObject GET /{bucket}/{key} (no tagging query)
DeleteObject DELETE /{bucket}/{key} (no uploadId or tagging query)
HeadObject HEAD /{bucket}/{key}
CopyObject PUT /{bucket}/{key} with x-amz-copy-source header
DeleteObjects POST /{bucket}?delete
ListObjectsV2 GET /{bucket}?list-type=2
ListBuckets GET / (no bucket)
CreateBucket PUT /{bucket} (no key)
DeleteBucket DELETE /{bucket} (no key)
GetBucketLocation GET /{bucket}?location
ListObjectVersions GET /{bucket}?versions
CreateMultipartUpload POST /{bucket}/{key}?uploads
UploadPart PUT /{bucket}/{key}?partNumber=N&uploadId=X
CompleteMultipartUpload POST /{bucket}/{key}?uploadId=X
AbortMultipartUpload DELETE /{bucket}/{key}?uploadId=X
PutObjectTagging PUT /{bucket}/{key}?tagging
GetObjectTagging GET /{bucket}/{key}?tagging
DeleteObjectTagging DELETE /{bucket}/{key}?tagging
Other Unrecognised or SDK metadata requests

In Summarised mode, Other operations are silently skipped.


Setup

Option A: With AmazonS3Config Extension (Recommended)

var trackingOptions = new S3TrackingMessageHandlerOptions
{
    ServiceName = "S3",
    CallingServiceName = "My API",
    Verbosity = S3TrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var config = new AmazonS3Config
{
    RegionEndpoint = RegionEndpoint.USEast1
};
config.WithTestTracking(trackingOptions);

var client = new AmazonS3Client(credentials, config);

WithTestTracking sets the HttpClientFactory property on AmazonS3Config to route all HTTP requests through the tracking handler. This requires no production code changes.

Option B: Manual HttpClient Construction

If you need more control over the HTTP pipeline:

var trackingOptions = new S3TrackingMessageHandlerOptions
{
    ServiceName = "S3",
    CallingServiceName = "My API",
    Verbosity = S3TrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var trackingHandler = new S3TrackingMessageHandler(trackingOptions);
// Use trackingHandler with your own HttpClient / AWS pipeline customization

Option C: In DI-based Tests (WebApplicationFactory)

builder.ConfigureTestServices(services =>
{
    services.AddSingleton<IAmazonS3>(sp =>
    {
        var trackingOptions = new S3TrackingMessageHandlerOptions
        {
            ServiceName = "S3",
            CallingServiceName = "My API",
            Verbosity = S3TrackingVerbosity.Detailed,
            CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
        };

        var config = new AmazonS3Config
        {
            RegionEndpoint = RegionEndpoint.USEast1,
            ServiceURL = "http://localhost:4566" // e.g. LocalStack
        };
        config.WithTestTracking(trackingOptions);

        return new AmazonS3Client(new BasicAWSCredentials("test", "test"), config);
    });
});

Configuration Reference

S3TrackingMessageHandlerOptions

Property Type Default Description
ServiceName string "S3" The participant name shown in the diagram for the S3 service
CallingServiceName string "Caller" The participant name shown for the service making S3 calls
Verbosity S3TrackingVerbosity 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+)

v2.23.0+ Dual-Resolution: S3TrackingMessageHandler accepts an optional IHttpContextAccessor? httpContextAccessor constructor parameter for resolving test identity from HTTP request headers when running inside the SUT's request pipeline. v2.26.3+: Set HttpContextAccessor on S3TrackingMessageHandlerOptions instead — the tracker reads it automatically. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for details. | ExcludedHeaders | HashSet<string> | See below | Headers to exclude from diagrams in Raw/Detailed mode | | SetupVerbosity | S3TrackingVerbosity? | null | Verbosity override for the Setup phase. See Phase-Aware Tracking | | ActionVerbosity | S3TrackingVerbosity? | 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 |

Default Excluded Headers

The following AWS headers are excluded by default (they add noise without diagnostic value):

  • Authorization
  • x-amz-date
  • x-amz-security-token
  • x-amz-content-sha256
  • User-Agent
  • amz-sdk-invocation-id
  • amz-sdk-request

Override ExcludedHeaders to customise:

new S3TrackingMessageHandlerOptions
{
    ExcludedHeaders = ["Authorization", "x-amz-date"] // Only exclude these two
}

CurrentTestInfoFetcher by Framework

Every framework package provides a CurrentTestInfo static class with a Fetcher property. The syntax is identical regardless of framework - just ensure you have the correct using directive:

CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
Framework using directive
xUnit v3 using TestTrackingDiagrams.xUnit3;
xUnit v2 using TestTrackingDiagrams.xUnit2;
NUnit 4 using TestTrackingDiagrams.NUnit4;
MSTest using TestTrackingDiagrams.MSTest;
TUnit using TestTrackingDiagrams.TUnit;
LightBDD using TestTrackingDiagrams.LightBDD;
ReqNRoll using TestTrackingDiagrams.ReqNRoll;
BDDfy using TestTrackingDiagrams.BDDfy.xUnit3;

Extension Methods

AmazonS3Config.WithTestTracking()

public static AmazonS3Config WithTestTracking(
    this AmazonS3Config config,
    S3TrackingMessageHandlerOptions trackingOptions,
    HttpMessageHandler? innerHandler = null)

Configures AmazonS3Config to use S3TrackingMessageHandler. Sets config.HttpClientFactory to a tracking factory that creates an HttpClient wrapping the tracking handler. The optional innerHandler parameter sets the inner handler (defaults to HttpClientHandler).


URL Format Support

S3 uses two URL styles, and the classifier handles both:

Style URL Format Example
Path-style https://s3.{region}.amazonaws.com/{bucket}/{key} https://s3.us-east-1.amazonaws.com/my-bucket/file.json
Virtual-hosted https://{bucket}.s3.{region}.amazonaws.com/{key} https://my-bucket.s3.us-east-1.amazonaws.com/file.json
Legacy global https://{bucket}.s3.amazonaws.com/{key} https://my-bucket.s3.amazonaws.com/file.json
Legacy dash https://{bucket}.s3-{region}.amazonaws.com/{key} https://my-bucket.s3-us-west-2.amazonaws.com/file.json

Virtual-hosted-style is the default for most regions since 2023. The classifier auto-detects the format from the hostname.


Invocation Validation

S3TrackingMessageHandler 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.

Home


Demo


Getting Started

Common Tasks

Integration Guides

Extensions

Configuration

Features

Reference

Clone this wiki locally