Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,52 @@ Tests are split into two projects. When creating or moving tests, follow these r
### Key constraint
The Integration project does **not** have `InternalsVisibleTo` access. If a test needs internal APIs, it belongs in Unit.

## Cross-Platform Testing (Dev Environment)

When investigating platform-specific test failures, use `scripts/dev-env.ps1` to reproduce issues locally on any platform + backend combination.

### Quick Reference

```powershell
# Check current state
./scripts/dev-env.ps1 status

# Reproduce a Linux CI failure
./scripts/dev-env.ps1 test -Platform linux -Target inmemory -Project integration -Filter "FullyQualifiedName~FailingTest"

# Reproduce a Linux + emulator CI failure
./scripts/dev-env.ps1 test -Platform linux -Target emulator-linux -Project integration -Filter "FullyQualifiedName~FailingTest"

# Run against Linux emulator from Windows host (tests emulator behavioral differences)
./scripts/dev-env.ps1 test -Platform windows -Target emulator-linux -Project integration

# Run arbitrary commands in the Linux container
./scripts/dev-env.ps1 exec -Cmd "dotnet build -c Release"

# Tear down when done
./scripts/dev-env.ps1 stop
```

### Investigation Workflow

When a test fails in CI on Linux but passes locally on Windows:

1. First try reproducing on Linux with in-memory: `./scripts/dev-env.ps1 test -Platform linux -Target inmemory -Filter "FullyQualifiedName~TestName"`
2. If it fails → it's a Linux .NET runtime difference (gateway fallback, string handling, etc.)
3. If it passes → try with the emulator: `./scripts/dev-env.ps1 test -Platform linux -Target emulator-linux -Filter "FullyQualifiedName~TestName"`
4. If that fails → it's a Linux + emulator interaction issue
5. Edit source files normally (they're mounted into the container), then re-run

### Supported Scenarios

| Platform | Target | Docker Required |
|----------|--------|----------------|
| windows | inmemory | No |
| windows | emulator-windows | No (needs Windows emulator installed) |
| windows | emulator-linux | Yes (emulator container) |
| linux | inmemory | Yes (dev container) |
| linux | emulator-linux | Yes (dev + emulator containers) |

## Documentation

After any changes are made that might effect the public API or functionality, documentation must be updated to reflect those changes. The documentation should be clear and comprehensive, covering all new features, changes to existing features, and any deprecations or removals. This includes updating README file (if relevant), but mainly the wiki which can be found in a sister folder to the main repository - ../CosmosDB.InMemoryEmulator.wiki.
36 changes: 32 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Thank you for your interest in contributing!

- .NET 8.0 SDK (or later)
- PowerShell (for test scripts)
- Docker (for cross-platform testing — Docker Desktop or Rancher Desktop)

## Building

Expand All @@ -24,16 +25,43 @@ dotnet build CosmosDB.InMemoryEmulator.sln
## Running Tests

```powershell
# Unit tests only
# Unit tests only (Windows, in-memory)
dotnet test tests/CosmosDB.InMemoryEmulator.Tests.Unit

# Integration tests (in-memory)
# Integration tests (Windows, in-memory)
dotnet test tests/CosmosDB.InMemoryEmulator.Tests.Integration
```

## Cross-Platform Testing

This project runs CI on both Windows and Linux. To reproduce platform-specific issues locally, use the dev environment script:

```powershell
# See what's running and available scenarios
./scripts/dev-env.ps1 status

# Run tests on Linux (catches gateway fallback / runtime differences)
./scripts/dev-env.ps1 test -Platform linux -Target inmemory -Project integration

# Full parity validation (requires Docker)
./scripts/validate-parity.ps1
# Run tests on Linux against the Linux Cosmos emulator
./scripts/dev-env.ps1 test -Platform linux -Target emulator-linux -Project integration

# Run tests on Windows against the Linux Cosmos emulator (emulator behavior differences)
./scripts/dev-env.ps1 test -Platform windows -Target emulator-linux -Project integration

# Run a specific failing test on Linux for investigation
./scripts/dev-env.ps1 test -Platform linux -Target inmemory -Filter "FullyQualifiedName~MyFailingTest"

# Start the Linux dev container for interactive exploration
./scripts/dev-env.ps1 start
./scripts/dev-env.ps1 exec -Cmd "dotnet build -c Release"

# Tear down all containers
./scripts/dev-env.ps1 stop
```

See [scripts/dev-env.ps1](scripts/dev-env.ps1) for full documentation of all commands and parameters.

## Guidelines

- **TDD**: Write a failing test first, then implement the minimum code to make it pass, then refactor.
Expand Down
83 changes: 83 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Cross-Platform Development Environment
#
# Defines services for local cross-platform testing:
# dev — Linux .NET SDK container for running tests on Linux
# emulator — Linux Cosmos DB emulator for integration tests
#
# Usage: managed via scripts/dev-env.ps1 (preferred) or directly:
# docker compose -f docker-compose.dev.yml up -d dev
# docker compose -f docker-compose.dev.yml up -d emulator
# docker compose -f docker-compose.dev.yml up -d # both
#
# Networking: The dev container shares the emulator's network namespace
# (network_mode: "service:emulator") so the tests can reach the emulator
# at localhost:8081 — exactly like CI. When only the dev container is running
# (no emulator), it uses bridge networking by default via the dev-standalone profile.

services:
dev:
image: mcr.microsoft.com/dotnet/sdk:8.0
container_name: cosmosdb-dev-linux
profiles: ["with-emulator"]
# Share the emulator's network namespace — tests see emulator at localhost:8081
# just like in CI (GitHub Actions service containers share localhost).
network_mode: "service:emulator"
depends_on:
emulator:
condition: service_healthy
volumes:
- .:/src
- ${NUGET_PACKAGES:-${USERPROFILE:-.}/.nuget/packages}:/root/.nuget/fallback-packages:ro
- nuget-cache:/root/.nuget/packages
working_dir: /src
command: >
bash -c "
if ! command -v pwsh &>/dev/null; then
apt-get update -qq && apt-get install -y -qq powershell >/dev/null 2>&1;
fi;
sleep infinity
"
environment:
- DOTNET_CLI_TELEMETRY_OPTOUT=1
- DOTNET_NOLOGO=1

# Standalone dev container (no emulator dependency) — for inmemory-only Linux testing
dev-standalone:
image: mcr.microsoft.com/dotnet/sdk:8.0
container_name: cosmosdb-dev-linux
profiles: ["standalone"]
volumes:
- .:/src
- ${NUGET_PACKAGES:-${USERPROFILE:-.}/.nuget/packages}:/root/.nuget/fallback-packages:ro
- nuget-cache:/root/.nuget/packages
working_dir: /src
command: >
bash -c "
if ! command -v pwsh &>/dev/null; then
apt-get update -qq && apt-get install -y -qq powershell >/dev/null 2>&1;
fi;
sleep infinity
"
environment:
- DOTNET_CLI_TELEMETRY_OPTOUT=1
- DOTNET_NOLOGO=1

emulator:
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
container_name: cosmosdb-emulator-linux
profiles: ["with-emulator", "emulator-only"]
ports:
- "8081:8081"
environment:
AZURE_COSMOS_EMULATOR_PARTITION_COUNT: 30
AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE: "false"
AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE: "127.0.0.1"
healthcheck:
test: ["CMD", "curl", "-fks", "https://localhost:8081/_explorer/emulator.pem"]
interval: 10s
timeout: 5s
retries: 60
start_period: 30s

volumes:
nuget-cache:
Loading
Loading