This document provides an overview of the comprehensive testing framework for SourceFlow's AWS cloud integration, covering property-based testing, performance validation, security testing, and resilience patterns.
SourceFlow.Net includes a sophisticated testing framework that validates AWS cloud integration across multiple dimensions:
- Functional Correctness - Property-based testing ensures universal correctness properties with 16 comprehensive properties
- Performance Validation - Comprehensive benchmarking of cloud service performance with BenchmarkDotNet
- Security Testing - Validation of encryption, authentication, and access control with IAM and KMS
- Resilience Testing - Circuit breakers, retry policies, and failure handling with comprehensive fault injection
- Local Development - Emulator-based testing for rapid development cycles with LocalStack
- CI/CD Integration - Automated testing with resource provisioning and cleanup for continuous validation
All phases of the AWS cloud integration testing framework have been successfully implemented:
- ✅ Phase 1-3: Enhanced test infrastructure with LocalStack, resource management, and test environment abstractions
- ✅ Phase 4-5: Comprehensive SQS and SNS integration tests with property-based validation
- ✅ Phase 6: KMS encryption integration tests with round-trip, key rotation, and security validation
- ✅ Phase 7: AWS health check integration tests for SQS, SNS, and KMS services
- ✅ Phase 9: AWS performance testing with benchmarks for throughput, latency, and scalability
- ✅ Phase 10: AWS resilience testing with circuit breakers, retry policies, and failure handling
- ✅ Phase 11: AWS security testing with IAM, encryption in transit, and audit logging validation
- ✅ Phase 12-15: CI/CD integration, comprehensive documentation, and final validation
Key Achievements:
- 16 property-based tests validating universal correctness properties
- 100+ integration tests covering all AWS services (SQS, SNS, KMS)
- Comprehensive performance benchmarks with BenchmarkDotNet
- Full security validation including IAM, KMS, and audit logging
- Complete CI/CD integration with automated resource provisioning
- Extensive documentation for setup, execution, and troubleshooting
- Enhanced wildcard permission validation logic
- Supports scenarios with zero wildcards or controlled wildcard usage
- Validates least privilege principles with realistic constraints
tests/
├── SourceFlow.Core.Tests/ # Core framework tests
│ ├── Unit/ # Unit tests (Category=Unit)
│ └── Integration/ # Integration tests
├── SourceFlow.Stores.EntityFramework.Tests/ # EF persistence tests
│ ├── Unit/ # Unit tests (Category=Unit)
│ └── E2E/ # Integration tests (Category=Integration)
├── SourceFlow.Cloud.AWS.Tests/ # AWS-specific testing
│ ├── Unit/ # Unit tests with mocks
│ ├── Integration/ # LocalStack integration tests
│ ├── Performance/ # BenchmarkDotNet performance tests
│ ├── Security/ # IAM and KMS security tests
│ ├── Resilience/ # Circuit breaker and retry tests
│ └── E2E/ # End-to-end scenario tests
All test projects use xUnit [Trait("Category", "...")] attributes for filtering:
Category=Unit- Fast, isolated unit tests with no external dependenciesCategory=Integration- Integration tests requiring databases or external servicesCategory=RequiresLocalStack- AWS integration tests requiring LocalStack container
Test Filtering Examples:
# Run only unit tests (fast feedback)
dotnet test --filter "Category=Unit"
# Run integration tests
dotnet test --filter "Category=Integration"
# Run security tests
dotnet test --filter "Category=Security"
# Run AWS integration tests with LocalStack
dotnet test --filter "Category=Integration&Category=RequiresLocalStack"
# Run all tests except LocalStack tests
dotnet test --filter "Category!=RequiresLocalStack"
# Run all tests except integration and security tests (CI pattern)
dotnet test --filter "FullyQualifiedName!~Integration&FullyQualifiedName!~Security"- FsCheck - Generates randomized test data to validate universal properties
- 100+ iterations per property test for comprehensive coverage
- Custom generators for cloud service configurations
- Automatic shrinking to find minimal failing examples
- BenchmarkDotNet - Precise micro-benchmarking with statistical analysis
- Memory diagnostics - Allocation tracking and GC pressure analysis
- Throughput measurement - Messages per second across cloud services
- Latency analysis - End-to-end processing times with percentile reporting
- LocalStack - AWS service emulation for local development
- TestContainers - Automated container lifecycle management
- Real cloud services - Validation against actual AWS services
- FIFO Queue Testing - Message ordering and deduplication
- Standard Queue Testing - High-throughput message delivery
- Dead Letter Queue Testing - Failed message handling and recovery
- Batch Operations - Efficient bulk message processing
- Message Attributes - Metadata preservation and routing
- Topic Publishing - Event distribution to multiple subscribers
- Fan-out Messaging - Delivery to SQS, Lambda, and HTTP endpoints
- Message Filtering - Subscription-based selective delivery
- Correlation Tracking - End-to-end message correlation
- Error Handling - Failed delivery retry mechanisms
- Round-trip Encryption - Message encryption and decryption validation
- Key Rotation - Seamless key rotation without service interruption
- Sensitive Data Masking - Automatic masking of sensitive properties
- Performance Impact - Encryption overhead measurement
The testing framework validates these universal correctness properties:
- ✅ SQS Message Processing Correctness - Commands delivered with proper attributes and ordering
- ✅ SQS Dead Letter Queue Handling - Failed messages captured with complete metadata
- ✅ SNS Event Publishing Correctness - Events delivered to all subscribers with fan-out
- ✅ SNS Message Filtering and Error Handling - Subscription filters and error handling work correctly
- ✅ KMS Encryption Round-Trip Consistency - Encryption/decryption preserves message integrity
- Property test validates: decrypt(encrypt(plaintext)) == plaintext for all inputs
- Ensures encryption non-determinism (different ciphertext for same plaintext)
- Verifies sensitive data protection (plaintext not visible in ciphertext)
- Validates performance characteristics (encryption/decryption within bounds)
- Tests Unicode safety and base64 encoding correctness
- Implemented in:
KmsEncryptionRoundTripPropertyTests.cswith 100+ test iterations - ✅ Integration tests complete: Comprehensive test suite in
KmsEncryptionIntegrationTests.cs- End-to-end encryption/decryption with various message types
- Algorithm validation (AES-256-GCM with envelope encryption)
- Encryption context and AAD (Additional Authenticated Data) validation
- Performance testing with different message sizes and concurrent operations
- Data key caching performance improvements
- Error handling for invalid ciphertext and corrupted envelopes
- ✅ KMS Key Rotation Seamlessness - Seamless key rotation without service interruption
- Property test validates: messages encrypted with old keys decrypt after rotation
- Ensures backward compatibility with previous key versions
- Verifies automatic key version management
- Tests rotation monitoring and alerting
- Implemented in:
KmsKeyRotationPropertyTests.csandKmsKeyRotationIntegrationTests.cs
- ✅ KMS Security and Performance - Sensitive data masking and performance validation
- Property test validates: [SensitiveData] attributes properly masked in logs
- Ensures encryption performance within acceptable bounds
- Verifies IAM permission enforcement
- Tests audit logging and compliance
- Implemented in:
KmsSecurityAndPerformancePropertyTests.csandKmsSecurityAndPerformanceTests.cs
- ✅ AWS Health Check Accuracy - Health checks reflect actual service availability
- Property test validates: health checks accurately detect service availability, accessibility, and permissions
- Ensures health checks complete within acceptable latency (< 5 seconds)
- Verifies reliability under concurrent access (90%+ consistency)
- Tests SQS queue existence, accessibility, send/receive permissions
- Tests SNS topic availability, attributes, publish permissions, subscription status
- Tests KMS key accessibility, encryption/decryption permissions, key status
- Implemented in:
AwsHealthCheckPropertyTests.csandAwsHealthCheckIntegrationTests.cs
- ✅ AWS Performance Measurement Consistency - Reliable performance metrics across test runs
- Property test validates: performance measurements are consistent within acceptable variance
- Ensures throughput measurements are reliable across iterations
- Verifies latency measurements under various load conditions
- Tests resource utilization tracking accuracy
- Implemented in:
AwsPerformanceMeasurementPropertyTests.cs
- ✅ LocalStack AWS Service Equivalence - LocalStack provides equivalent functionality to AWS
- ✅ AWS Resilience Pattern Compliance - Circuit breakers, retry policies work correctly
- Property test validates: circuit breakers open on failures and close on recovery
- Ensures retry policies implement exponential backoff with jitter
- Verifies maximum retry limits are enforced
- Tests graceful handling of service throttling
- Implemented in:
AwsResiliencePatternPropertyTests.csand resilience integration tests
- ✅ AWS Dead Letter Queue Processing - Failed message analysis and reprocessing
- Property test validates: failed messages captured with complete metadata
- Ensures message analysis and categorization work correctly
- Verifies reprocessing capabilities and workflows
- Tests monitoring and alerting integration
- Implemented in:
AwsDeadLetterQueuePropertyTests.csand DLQ integration tests
- ✅ AWS IAM Security Enforcement - Proper authentication and authorization
- Property test validates: IAM role assumption and credential management
- Ensures least privilege access enforcement with flexible wildcard validation
- Verifies cross-account access and permission boundaries
- Tests IAM policy effectiveness and compliance
- Enhanced Validation Logic: Handles property-based test generation edge cases
- Lenient required permission validation when test generation produces more required permissions than available actions
- Validates that granted actions include required permissions up to the available action count
- Prevents false negatives from random test data generation
- Supports zero wildcards or controlled wildcard usage (up to 50% of actions)
- Implemented in:
IamSecurityPropertyTests.csandIamRoleTests.cs
- ✅ AWS Encryption in Transit - TLS encryption for all communications
- ✅ AWS Audit Logging - CloudTrail integration and event logging
- ✅ AWS CI/CD Integration Reliability - Tests run successfully in CI/CD with proper isolation
- SQS Standard Queues - High-throughput message processing
- SQS FIFO Queues - Ordered message processing performance
- SNS Topic Publishing - Event publishing rates and fan-out performance
- End-to-End Latency - Complete message processing times
- Network Overhead - Cloud service communication latency
- Encryption Overhead - Performance impact of message encryption
- Serialization Impact - Message serialization/deserialization costs
- Concurrent Connections - Performance under increasing load
- Resource Utilization - Memory, CPU, and network usage
- Service Limits - Behavior at cloud service limits
- Auto-scaling - Performance during scaling events
- AWS IAM Roles - Proper role assumption and credential management
- Least Privilege - Access control enforcement testing
- Cross-Account Access - Multi-account permission validation
- AWS KMS - Message encryption with key rotation
- Sensitive Data Masking - Automatic masking in logs
- Encryption in Transit - TLS validation for all communications
- Audit Logging - CloudTrail integration
- Data Sovereignty - Regional data handling compliance
- Security Standards - Validation against security best practices
- Failure Detection - Automatic circuit opening on service failures
- Recovery Testing - Circuit closing on service recovery
- Half-Open State - Gradual recovery validation
- Configuration Testing - Threshold and timeout validation
- Exponential Backoff - Proper retry timing implementation
- Jitter Implementation - Randomization to prevent thundering herd
- Maximum Retry Limits - Proper retry limit enforcement
- Poison Message Handling - Failed message isolation
- Failed Message Capture - Complete failure metadata preservation
- Message Analysis - Failure pattern detection and categorization
- Reprocessing Capabilities - Message recovery and retry workflows
- Monitoring Integration - Alerting and operational visibility
The Bus Configuration System requires testing at multiple levels to ensure routing is configured correctly and resources are created as expected.
Unit tests validate configuration without connecting to cloud services:
Testing Configuration Structure:
using SourceFlow.Cloud.Configuration;
using Xunit;
public class BusConfigurationTests
{
[Fact]
public void BusConfiguration_Should_Register_Command_Routes()
{
// Arrange
var builder = new BusConfigurationBuilder();
// Act
var config = builder
.Send
.Command<CreateOrderCommand>(q => q.Queue("orders.fifo"))
.Command<UpdateOrderCommand>(q => q.Queue("orders.fifo"))
.Build();
// Assert
Assert.Equal(2, config.CommandRoutes.Count);
Assert.Equal("orders.fifo", config.CommandRoutes[typeof(CreateOrderCommand)]);
Assert.Equal("orders.fifo", config.CommandRoutes[typeof(UpdateOrderCommand)]);
}
[Fact]
public void BusConfiguration_Should_Register_Event_Routes()
{
// Arrange
var builder = new BusConfigurationBuilder();
// Act
var config = builder
.Raise
.Event<OrderCreatedEvent>(t => t.Topic("order-events"))
.Event<OrderUpdatedEvent>(t => t.Topic("order-events"))
.Build();
// Assert
Assert.Equal(2, config.EventRoutes.Count);
Assert.Equal("order-events", config.EventRoutes[typeof(OrderCreatedEvent)]);
Assert.Equal("order-events", config.EventRoutes[typeof(OrderUpdatedEvent)]);
}
[Fact]
public void BusConfiguration_Should_Register_Listening_Queues()
{
// Arrange
var builder = new BusConfigurationBuilder();
// Act
var config = builder
.Listen.To
.CommandQueue("orders.fifo")
.CommandQueue("inventory.fifo")
.Build();
// Assert
Assert.Equal(2, config.ListeningQueues.Count);
Assert.Contains("orders.fifo", config.ListeningQueues);
Assert.Contains("inventory.fifo", config.ListeningQueues);
}
[Fact]
public void BusConfiguration_Should_Register_Topic_Subscriptions()
{
// Arrange
var builder = new BusConfigurationBuilder();
// Act
var config = builder
.Subscribe.To
.Topic("order-events")
.Topic("payment-events")
.Build();
// Assert
Assert.Equal(2, config.SubscribedTopics.Count);
Assert.Contains("order-events", config.SubscribedTopics);
Assert.Contains("payment-events", config.SubscribedTopics);
}
[Fact]
public void BusConfiguration_Should_Validate_Listening_Queue_Required_For_Subscriptions()
{
// Arrange
var builder = new BusConfigurationBuilder();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() =>
builder
.Subscribe.To
.Topic("order-events")
.Build());
Assert.Contains("at least one command queue", exception.Message);
}
}Integration tests validate Bus Configuration with LocalStack:
AWS Integration Test Example:
using SourceFlow.Cloud.AWS;
using Xunit;
public class AwsBusConfigurationIntegrationTests : IClassFixture<LocalStackFixture>
{
private readonly LocalStackFixture _localStack;
public AwsBusConfigurationIntegrationTests(LocalStackFixture localStack)
{
_localStack = localStack;
}
[Fact]
public async Task Bootstrapper_Should_Create_SQS_Queues()
{
// Arrange
var services = new ServiceCollection();
services.UseSourceFlowAws(
options => {
options.ServiceUrl = _localStack.ServiceUrl;
options.Region = RegionEndpoint.USEast1;
},
bus => bus
.Send
.Command<CreateOrderCommand>(q => q.Queue("test-orders.fifo"))
.Listen.To
.CommandQueue("test-orders.fifo"));
var provider = services.BuildServiceProvider();
// Act
var bootstrapper = provider.GetRequiredService<IHostedService>();
await bootstrapper.StartAsync(CancellationToken.None);
// Assert
var sqsClient = provider.GetRequiredService<IAmazonSQS>();
var response = await sqsClient.GetQueueUrlAsync("test-orders.fifo");
Assert.NotNull(response.QueueUrl);
Assert.Contains("test-orders.fifo", response.QueueUrl);
}
[Fact]
public async Task Bootstrapper_Should_Create_SNS_Topics()
{
// Arrange
var services = new ServiceCollection();
services.UseSourceFlowAws(
options => {
options.ServiceUrl = _localStack.ServiceUrl;
options.Region = RegionEndpoint.USEast1;
},
bus => bus
.Raise
.Event<OrderCreatedEvent>(t => t.Topic("test-order-events"))
.Listen.To
.CommandQueue("test-orders"));
var provider = services.BuildServiceProvider();
// Act
var bootstrapper = provider.GetRequiredService<IHostedService>();
await bootstrapper.StartAsync(CancellationToken.None);
// Assert
var snsClient = provider.GetRequiredService<IAmazonSimpleNotificationService>();
var topics = await snsClient.ListTopicsAsync();
Assert.Contains(topics.Topics, t => t.TopicArn.Contains("test-order-events"));
}
[Fact]
public async Task Bootstrapper_Should_Subscribe_Queues_To_Topics()
{
// Arrange
var services = new ServiceCollection();
services.UseSourceFlowAws(
options => {
options.ServiceUrl = _localStack.ServiceUrl;
options.Region = RegionEndpoint.USEast1;
},
bus => bus
.Listen.To
.CommandQueue("test-orders")
.Subscribe.To
.Topic("test-order-events"));
var provider = services.BuildServiceProvider();
// Act
var bootstrapper = provider.GetRequiredService<IHostedService>();
await bootstrapper.StartAsync(CancellationToken.None);
// Assert
var snsClient = provider.GetRequiredService<IAmazonSimpleNotificationService>();
var topics = await snsClient.ListTopicsAsync();
var topicArn = topics.Topics.First(t => t.TopicArn.Contains("test-order-events")).TopicArn;
var subscriptions = await snsClient.ListSubscriptionsByTopicAsync(topicArn);
Assert.NotEmpty(subscriptions.Subscriptions);
Assert.Contains(subscriptions.Subscriptions, s => s.Protocol == "sqs");
}
}Strategy 1: Configuration Snapshot Testing
Capture and compare Bus Configuration snapshots:
[Fact]
public void BusConfiguration_Should_Match_Expected_Snapshot()
{
// Arrange
var builder = new BusConfigurationBuilder();
var config = builder
.Send
.Command<CreateOrderCommand>(q => q.Queue("orders.fifo"))
.Raise
.Event<OrderCreatedEvent>(t => t.Topic("order-events"))
.Listen.To
.CommandQueue("orders.fifo")
.Subscribe.To
.Topic("order-events")
.Build();
// Act
var snapshot = config.ToSnapshot();
// Assert
var expected = LoadExpectedSnapshot("bus-configuration-v1.json");
Assert.Equal(expected, snapshot);
}Strategy 2: End-to-End Routing Validation
Test complete message flow through configured routing:
[Fact]
public async Task Message_Should_Flow_Through_Configured_Routes()
{
// Arrange
var services = ConfigureServicesWithBusConfiguration();
var provider = services.BuildServiceProvider();
// Start bootstrapper
var bootstrapper = provider.GetRequiredService<IHostedService>();
await bootstrapper.StartAsync(CancellationToken.None);
// Act
var commandBus = provider.GetRequiredService<ICommandBus>();
var command = new CreateOrderCommand(new CreateOrderPayload { /* ... */ });
await commandBus.PublishAsync(command);
// Assert
// Verify command was routed to correct queue
// Verify event was published to correct topic
// Verify listeners received messages
}Strategy 3: Resource Existence Validation
Verify all configured resources exist after bootstrapping:
[Fact]
public async Task All_Configured_Resources_Should_Exist_After_Bootstrapping()
{
// Arrange
var services = ConfigureServicesWithBusConfiguration();
var provider = services.BuildServiceProvider();
var config = provider.GetRequiredService<BusConfiguration>();
// Act
var bootstrapper = provider.GetRequiredService<IHostedService>();
await bootstrapper.StartAsync(CancellationToken.None);
// Assert
foreach (var queue in config.ListeningQueues)
{
var exists = await QueueExistsAsync(queue);
Assert.True(exists, $"Queue {queue} should exist");
}
foreach (var topic in config.SubscribedTopics)
{
var exists = await TopicExistsAsync(topic);
Assert.True(exists, $"Topic {topic} should exist");
}
}-
Use LocalStack for Integration Tests
- LocalStack for AWS testing
- Faster feedback than real cloud services
- No cloud costs during development
-
Test Configuration Validation
- Verify invalid configurations throw exceptions
- Test edge cases (empty queues, missing topics)
- Validate required relationships (queue for subscriptions)
-
Test Resource Creation Idempotency
- Run bootstrapper multiple times
- Verify no errors on repeated execution
- Ensure resources aren't duplicated
-
Test FIFO Queue Detection
- Verify .fifo suffix enables sessions/FIFO
- Test both FIFO and standard queues
- Validate message ordering guarantees
-
Mock Bootstrapper for Unit Tests
- Test application logic without cloud dependencies
- Mock IBusBootstrapConfiguration interface
- Verify routing decisions without resource creation
- LocalStack - Complete AWS service emulation (SQS, SNS, KMS, IAM)
- Container Management - Automatic lifecycle with TestContainers
- Health Checking - Service availability validation
- Smart Container Detection - Automatically detects and reuses existing LocalStack instances (e.g., in CI/CD environments) to avoid redundant container creation
- Fast Feedback - Rapid test execution without cloud dependencies
- Cost Optimization - No cloud resource costs during development
- Offline Development - Full functionality without internet connectivity
- Debugging Support - Local service inspection and troubleshooting
- CI/CD Efficiency - Seamlessly integrates with pre-configured LocalStack services in GitHub Actions and other CI platforms
- Multi-Environment - Tests against both LocalStack and real AWS services
- Resource Provisioning - Automatic cloud resource creation and cleanup via
AwsResourceManager - Parallel Execution - Concurrent test execution for faster feedback
- Test Isolation - Proper resource isolation to prevent interference with unique naming and tagging
- Smart Container Management - Detects pre-existing LocalStack services in CI/CD environments (e.g., GitHub Actions service containers) and reuses them instead of creating redundant containers, improving test execution speed and resource efficiency
- Adaptive Timeouts - Automatically adjusts LocalStack health check timeouts based on environment (90 seconds for CI, 30 seconds for local development)
- Shared Container Fixtures - xUnit collection fixtures ensure single LocalStack instance per test run, preventing port conflicts in parallel test execution
The test infrastructure includes specific optimizations for GitHub Actions CI environments:
LocalStack Service Container Integration:
- Pre-Started Container - Release-CI workflow includes LocalStack as a service container
- Port Mapping - LocalStack exposed on port 4566 for test access
- Service Configuration - Configured with SQS, SNS, KMS, and IAM services
- Health Checks - Container health validated before test execution begins
- Automatic Lifecycle - GitHub Actions manages container startup and cleanup
- Resource Efficiency - Single shared container across all test jobs
- Fail-Fast Behavior - Tests fail immediately if LocalStack service container is not detected in CI (prevents Docker-in-Docker issues)
- Anonymous Credentials - Uses
AnonymousAWSCredentialsto bypass credential validation in LocalStack (no dummy credentials needed)
LocalStack Timeout Handling:
- Environment Detection - Automatically detects GitHub Actions via
GITHUB_ACTIONSenvironment variable - Extended Timeouts - Uses 90-second health check timeout in CI (vs 30 seconds locally) to accommodate slower container initialization
- Enhanced Retry Logic - Increases retry attempts (30 vs 15) and delays (3 seconds vs 2 seconds) for CI environments
- External Instance Detection - 10-second timeout (vs 3 seconds locally) with 3 retry attempts to reliably detect pre-started LocalStack service containers
- Lenient Detection - Accepts HTTP 200 from health endpoint even if services aren't fully initialized, deferring full readiness validation to main wait loop
Container Sharing:
- xUnit Collection Fixtures -
AwsIntegrationTestCollectionenforces sharedLocalStackTestFixtureacross all test classes - Port Conflict Prevention - Single LocalStack instance eliminates port 4566 allocation conflicts
- Resource Efficiency - Reduces CI execution time by avoiding redundant container startups
- CI Service Container Detection - In GitHub Actions, tests detect and reuse pre-started LocalStack service containers
- Fail-Fast in CI - Tests fail immediately if LocalStack service container is not available in GitHub Actions (prevents Docker-in-Docker issues)
- Local Development - Tests can start their own LocalStack containers when running locally
Configuration Classes:
LocalStackConfiguration.CreateForIntegrationTesting()- Returns CI-optimized configuration with 90-second timeoutLocalStackConfiguration.IsCI- Property that detects GitHub Actions environmentLocalStackManager.WaitForServicesAsync()- Adaptive retry logic based on environment detection
GitHub Actions Workflow Configuration:
The Release-CI workflow includes LocalStack as a service container with AWS credentials and simplified security settings for testing:
env:
# AWS credentials for LocalStack (dummy values)
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
AWS_DEFAULT_REGION: us-east-1
services:
localstack:
image: localstack/localstack:latest
ports:
- 4566:4566
env:
SERVICES: sqs,sns,kms,iam
DEBUG: 1
DOCKER_HOST: unix:///var/run/docker.sock
# Disable IAM enforcement for easier testing
ENFORCE_IAM: 0
# Skip SSL certificate validation
SKIP_SSL_CERT_DOWNLOAD: 1
# Disable signature validation (accept any credentials)
DISABLE_CUSTOM_CORS_S3: 1
DISABLE_CUSTOM_CORS_APIGATEWAY: 1
options: >-
--health-cmd "curl -f http://localhost:4566/_localstack/health || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 30
--health-start-period 30sAWS Credential Configuration:
The test infrastructure uses BasicAWSCredentials with dummy values for LocalStack testing. This approach provides better compatibility with AWS SDK endpoint resolution compared to AnonymousAWSCredentials.
// LocalStackTestFixture.cs
// Use BasicAWSCredentials with dummy values for LocalStack
// AnonymousAWSCredentials can cause issues with endpoint resolution
var credentials = new Amazon.Runtime.BasicAWSCredentials("test", "test");
var config = new Amazon.SQS.AmazonSQSConfig
{
ServiceURL = LocalStackEndpoint,
UseHttp = true,
// Don't set RegionEndpoint when using ServiceURL - it can override the endpoint
AuthenticationRegion = _configuration.Region.SystemName
};Credential Configuration Details:
- BasicAWSCredentials - Uses dummy "test"/"test" credentials for LocalStack
- ServiceURL - Explicitly set to LocalStack endpoint (http://localhost:4566)
- UseHttp - Enables HTTP instead of HTTPS for LocalStack
- AuthenticationRegion - Set to match configured region (us-east-1)
- No RegionEndpoint - Omitted when using ServiceURL to prevent endpoint override
- No ForcePathStyle - Not required for LocalStack; ServiceURL configuration is sufficient
Benefits:
- Endpoint Compatibility - BasicAWSCredentials works reliably with custom ServiceURL
- LocalStack Support - Dummy credentials accepted by LocalStack without validation
- Consistent Behavior - Same credential approach across all AWS service clients (SQS, SNS, KMS)
- CI/CD Integration - Works seamlessly in GitHub Actions with LocalStack service containers
- Local Development - No configuration needed for LocalStack testing
LocalStack Security Configuration:
ENFORCE_IAM: 0- Disables IAM policy enforcement for simplified testing with dummy credentialsSKIP_SSL_CERT_DOWNLOAD: 1- Skips SSL certificate downloads to speed up container initializationDISABLE_CUSTOM_CORS_S3: 1- Disables custom CORS for S3 (not used in tests but reduces overhead)DISABLE_CUSTOM_CORS_APIGATEWAY: 1- Disables custom CORS for API Gateway (not used in tests but reduces overhead)
These settings optimize LocalStack for CI testing by:
- Accepting any AWS credentials (test/test) without validation
- Reducing container startup time by skipping unnecessary downloads
- Simplifying test execution without strict IAM policy enforcement
- Maintaining functional equivalence for SQS, SNS, KMS, and IAM service testing
Service Container Benefits:
- Container starts before test job begins
- Health checks ensure services are ready before tests run
- Automatic cleanup after job completion
- No manual container management required in test code
- Consistent environment across all CI runs
- Comprehensive Reports - Detailed test results with metrics and analysis
- Performance Trends - Historical performance tracking and regression detection
- Security Validation - Security test results with compliance reporting
- Failure Analysis - Actionable error messages with troubleshooting guidance
The AwsResourceManager provides comprehensive automated resource lifecycle management for AWS integration testing:
- Resource Provisioning - Automatic creation of SQS queues, SNS topics, KMS keys, and IAM roles
- CloudFormation Integration - Stack-based resource provisioning for complex scenarios
- Resource Tracking - Automatic tagging and cleanup with unique test prefixes
- Cost Estimation - Resource cost calculation and monitoring capabilities
- Multi-Account Support - Cross-account resource management and cleanup
- Test Isolation - Unique naming prevents conflicts in parallel test execution
The LocalStackManager provides comprehensive container lifecycle management for AWS service emulation with enhanced features:
- Smart Container Detection - Automatically detects and reuses existing LocalStack instances (e.g., in CI/CD environments) to avoid redundant container creation
- Adaptive Timeout Configuration - Automatically adjusts health check timeouts based on environment (90 seconds for CI, 30 seconds for local development)
- Health Endpoint Detection - Uses LocalStack's
/_localstack/healthendpoint for fast, reliable instance detection instead of attempting AWS service operations - Lenient Detection Strategy - Accepts HTTP 200 responses from health endpoint even if services aren't fully initialized, deferring full service readiness validation to the main wait loop
- Retry Logic - Configurable retry attempts with delays for reliable external instance detection (3 attempts with 2-second delays)
- Port Management - Automatic port conflict detection and resolution
- Service Validation - Comprehensive AWS service emulation validation (SQS, SNS, KMS, IAM)
- Diagnostic Logging - Detailed logging for troubleshooting container startup and service initialization issues
External Instance Detection Behavior:
- Checks for existing LocalStack instances before starting new containers
- Uses HTTP health endpoint (
/_localstack/health) for faster detection than AWS SDK calls - Accepts HTTP 200 status code regardless of individual service status
- Allows services to continue initializing after detection succeeds
- Full service readiness validation occurs in
WaitForServicesAsyncwith appropriate timeouts - Prevents port conflicts and reduces CI execution time by reusing pre-started containers
- CI Fail-Fast: In GitHub Actions, tests fail immediately if LocalStack service container is not detected (prevents Docker-in-Docker issues)
- Local Development: Tests can start their own LocalStack containers when no external instance is detected
CI/CD Optimizations:
- Detects GitHub Actions environment via
GITHUB_ACTIONSenvironment variable - Uses extended timeouts (10 seconds vs 3 seconds) for external instance detection in CI
- Increases retry attempts and delays for slower CI environments
- Adds initial delay after container start (5 seconds in CI, 2 seconds locally) for initialization scripts
Enhanced LocalStack container management with comprehensive AWS service emulation:
- Service Emulation - Full support for SQS (standard and FIFO), SNS, KMS, and IAM
- Health Checking - Service availability validation and readiness detection with adaptive timeouts
- Port Management - Automatic port allocation and conflict resolution
- Container Lifecycle - Automated startup, health checks, and cleanup
- Service Validation - AWS SDK compatibility testing for each service
- CI/CD Optimization - Detects pre-existing LocalStack instances (e.g., GitHub Actions services) to avoid redundant container creation
- Environment-Aware Configuration - Automatically adjusts health check timeouts and retry logic for CI environments (90 seconds) vs local development (30 seconds)
- Shared Container Support - xUnit collection fixtures ensure single LocalStack instance shared across all test classes to prevent port conflicts
Comprehensive test environment abstraction supporting both LocalStack and real AWS:
- Dual Mode Support - Seamless switching between LocalStack emulation and real AWS services
- Resource Creation - FIFO queues, standard queues, SNS topics, KMS keys with proper configuration
- Health Monitoring - Service-level health checks with response time tracking
- Managed Identity - Support for IAM roles and credential management
- Service Clients - Pre-configured SQS, SNS, KMS, and IAM clients
- Unique Naming - Test prefix-based resource naming to prevent conflicts
- Automatic Cleanup - Comprehensive resource cleanup to prevent cost leaks
- Resource Tagging - Metadata tagging for identification and cost allocation
- Health Monitoring - Resource availability and permission validation
- Batch Operations - Efficient bulk resource creation and deletion
var resourceManager = serviceProvider.GetRequiredService<IAwsResourceManager>();
var resourceSet = await resourceManager.CreateTestResourcesAsync("test-prefix",
AwsResourceTypes.SqsQueues | AwsResourceTypes.SnsTopics);
// Use resources for testing
// ...
// Automatic cleanup
await resourceManager.CleanupResourcesAsync(resourceSet);- .NET 9.0 SDK or later
- Docker Desktop for LocalStack support
- AWS CLI (optional, for real AWS testing)
# Run all tests
dotnet test
# Run only unit tests (fast feedback, no external dependencies)
dotnet test --filter "Category=Unit"
# Run integration tests
dotnet test --filter "Category=Integration"
# Run AWS integration tests with LocalStack
dotnet test --filter "Category=Integration&Category=RequiresLocalStack"
# Run specific test categories
dotnet test --filter "Category=Performance"
dotnet test --filter "Category=Security"
dotnet test --filter "Category=Property"
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"Tests can be configured via appsettings.json or environment variables:
Configuration File (appsettings.json):
{
"CloudIntegrationTests": {
"UseEmulators": true,
"RunPerformanceTests": false,
"RunSecurityTests": true,
"Aws": {
"UseLocalStack": true,
"Region": "us-east-1"
}
}
}Environment Variables:
The test infrastructure supports configuration via environment variables for CI/CD integration:
| Variable | Purpose | Default | Example |
|---|---|---|---|
AWS_ACCESS_KEY_ID |
AWS access key for LocalStack | test |
test |
AWS_SECRET_ACCESS_KEY |
AWS secret key for LocalStack | test |
test |
AWS_DEFAULT_REGION |
AWS region for testing | us-east-1 |
us-east-1 |
GITHUB_ACTIONS |
Detects CI environment | (none) | true |
Credential Resolution:
The AwsTestConfiguration class automatically resolves credentials in the following order:
- Environment Variables - Checks
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY - Default Values - Falls back to "test"/"test" for local development
This approach provides:
- CI/CD Compatibility - Works seamlessly with GitHub Actions and other CI systems
- Local Development - No configuration needed for LocalStack testing
- Flexibility - Override credentials via environment variables when needed
- Security - Credentials managed through CI/CD secrets, not hardcoded
- Property-based testing for universal correctness validation
- Unit tests for specific scenarios and edge cases
- Integration tests for end-to-end validation
- Performance tests for scalability and optimization
- Unique naming with test prefixes to prevent conflicts
- Automatic cleanup to prevent resource leaks and costs
- Resource tagging for identification and cost tracking
- Least privilege access for security testing
- Baseline establishment for regression detection
- Multiple iterations for statistical significance
- Environment consistency for reliable measurements
- Resource monitoring during test execution
- Symptom: Tests fail with "LocalStack services did not become ready within timeout"
- Cause: Container startup slower than expected, especially in CI environments
- Solution:
- Verify Docker Desktop is running and has sufficient resources
- Check that
GITHUB_ACTIONSenvironment variable is set correctly in CI - Ensure health check timeout is appropriate for environment (90s for CI, 30s for local)
- Review LocalStack logs for service initialization errors
- Symptom: Tests fail with "LocalStack service container not detected in GitHub Actions CI"
- Cause: GitHub Actions workflow missing
services.localstackconfiguration - Solution:
- Verify workflow YAML includes LocalStack service container definition
- Check service container health checks are configured correctly
- Ensure port 4566 is mapped correctly in service configuration
- Review GitHub Actions logs to confirm service container started successfully
- Note: Tests cannot start their own containers in CI due to Docker-in-Docker limitations
- Symptom: Tests fail with "port is already allocated" or "address already in use"
- Cause: Multiple test classes attempting to start separate LocalStack instances
- Solution:
- Verify
AwsIntegrationTestCollectionclass exists with[CollectionDefinition]andICollectionFixture<LocalStackTestFixture> - Ensure all integration test classes use
[Collection("AWS Integration Tests")]attribute - Check that only one LocalStack container is running (use
docker ps)
- Verify
- Symptom: Tests start new LocalStack container despite existing instance
- Cause: External instance detection timeout too short or instance not responding to health endpoint
- Solution:
- Increase external detection timeout (10 seconds recommended for CI)
- Verify existing LocalStack instance is healthy and responding to
/_localstack/healthendpoint - Check network connectivity between test runner and LocalStack container
- Review console output for health check diagnostic messages
- Ensure LocalStack is accepting HTTP connections on port 4566
- Symptom: Tests pass locally but timeout in GitHub Actions CI
- Cause: CI environment has slower container initialization than local development
- Solution:
- Verify
LocalStackConfiguration.IsCIcorrectly detects GitHub Actions environment - Ensure
CreateForIntegrationTesting()returns 90-second timeout configuration - Check GitHub Actions runner has sufficient resources allocated
- Review CI logs for container startup timing information
- Verify
- Detailed logging for test execution visibility
- Service health checking for LocalStack availability
- Resource inspection - Cloud service validation
- Performance profiling for optimization opportunities
- Environment detection - Verify CI vs local environment detection
- Container inspection - Check LocalStack container status and logs with
docker logs
When adding new cloud integration tests:
- Follow existing patterns - Use established test structures and naming
- Include property tests - Add universal correctness properties
- Add performance benchmarks - Measure new functionality performance
- Document test scenarios - Provide clear test descriptions
- Ensure cleanup - Proper resource management and cleanup
- Update documentation - Keep guides current with new capabilities
- AWS Cloud Architecture
- Architecture Overview
- Cloud Message Idempotency Guide
- GitHub Actions LocalStack Timeout Fix - Technical details on CI timeout handling
Document Version: 2.2
Last Updated: 2026-03-07
Covers: AWS cloud integration testing capabilities with GitHub Actions CI optimizations and environment variable credential configuration