diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml
index 3e723f602..58e32a9a0 100644
--- a/.github/workflows/aws.yml
+++ b/.github/workflows/aws.yml
@@ -17,63 +17,27 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start LocalStack and PostgreSQL
- run: docker compose up -d localstack postgresql
-
- - name: Build SQS Tests
- run: dotnet build src/Transports/AWS/Wolverine.AmazonSqs.Tests/Wolverine.AmazonSqs.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Build SNS Tests
- run: dotnet build src/Transports/AWS/Wolverine.AmazonSns.Tests/Wolverine.AmazonSns.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Wait for LocalStack
- run: |
- echo "Waiting for LocalStack to be ready..."
- for i in {1..60}; do
- if curl -s http://localhost:4566/_localstack/health > /dev/null 2>&1; then
- echo "LocalStack is ready"
- break
- fi
- echo "Attempt $i: LocalStack not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T postgresql pg_isready -U postgres; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Test SQS
- run: dotnet test src/Transports/AWS/Wolverine.AmazonSqs.Tests/Wolverine.AmazonSqs.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- - name: Test SNS
- run: dotnet test src/Transports/AWS/Wolverine.AmazonSns.Tests/Wolverine.AmazonSns.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run AWS Tests
+ run: ./build.sh CIAWS --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/azure-service-bus.yml b/.github/workflows/azure-service-bus.yml
new file mode 100644
index 000000000..3c60823de
--- /dev/null
+++ b/.github/workflows/azure-service-bus.yml
@@ -0,0 +1,44 @@
+name: azure-service-bus
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run Azure Service Bus Tests
+ run: ./build.sh CIAzureServiceBus --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/cosmosdb.yml b/.github/workflows/cosmosdb.yml
new file mode 100644
index 000000000..a504de599
--- /dev/null
+++ b/.github/workflows/cosmosdb.yml
@@ -0,0 +1,44 @@
+name: cosmosdb
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run CosmosDb Tests
+ run: ./build.sh CICosmosDb --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 424176fe0..d7e985878 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -7,20 +7,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index e9d3afcd0..73bdc452b 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -18,22 +18,22 @@ jobs:
steps:
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
diff --git a/.github/workflows/efcore.yml b/.github/workflows/efcore.yml
index f73bbfffb..9cffbc85d 100644
--- a/.github/workflows/efcore.yml
+++ b/.github/workflows/efcore.yml
@@ -17,62 +17,27 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start containers
- run: docker compose up -d postgresql sqlserver
-
- - name: Build
- run: |
- dotnet build src/Persistence/EfCoreTests/EfCoreTests.csproj --configuration ${{ env.config }} --framework net9.0
- dotnet build src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj --configuration ${{ env.config }} --framework net9.0
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T postgresql pg_isready -U postgres; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for SQL Server
- run: |
- echo "Waiting for SQL Server to be ready..."
- for i in {1..30}; do
- if docker compose exec -T sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'P@55w0rd' -C -Q "SELECT 1" > /dev/null 2>&1; then
- echo "SQL Server is ready"
- break
- fi
- echo "Attempt $i: SQL Server not ready yet, waiting..."
- sleep 2
- done
-
- - name: Test EfCoreTests
- run: dotnet test src/Persistence/EfCoreTests/EfCoreTests.csproj --configuration ${{ env.config }} --framework net9.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- - name: Test EfCoreTests.MultiTenancy
- run: dotnet test src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj --configuration ${{ env.config }} --framework net9.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run EF Core Tests
+ run: ./build.sh CIEfCore --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/http.yml b/.github/workflows/http.yml
index bdd38bdfa..e216a03fd 100644
--- a/.github/workflows/http.yml
+++ b/.github/workflows/http.yml
@@ -18,47 +18,27 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start PostgreSQL
- run: docker compose up -d postgresql
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T postgresql pg_isready -U postgres; then
- echo "PostgreSQL is ready"
- exit 0
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
- echo "PostgreSQL failed to start"
- exit 1
-
- - name: Build
- run: dotnet build src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj --framework net9.0 --configuration ${{ env.config }}
-
- - name: Test
- run: dotnet test src/Http/Wolverine.Http.Tests/Wolverine.Http.Tests.csproj -e Development --framework net9.0 --configuration ${{ env.config }} --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run HTTP Tests
+ run: ./build.sh CIHttp --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/kafka.yml b/.github/workflows/kafka.yml
index f06d33370..f076d5ea0 100644
--- a/.github/workflows/kafka.yml
+++ b/.github/workflows/kafka.yml
@@ -13,61 +13,31 @@ env:
jobs:
test:
runs-on: ubuntu-latest
- timeout-minutes: 10
+ timeout-minutes: 15
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start Kafka and PostgreSQL
- run: docker compose up -d kafka postgresql
-
- - name: Wait for Kafka
- run: |
- echo "Waiting for Kafka to be ready..."
- for i in {1..60}; do
- if curl -s http://localhost:8082/v3/clusters > /dev/null 2>&1; then
- echo "Kafka is ready"
- break
- fi
- echo "Attempt $i: Kafka not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if nc -z localhost 5433 > /dev/null 2>&1; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Build
- run: dotnet build src/Transports/Kafka/Wolverine.Kafka.Tests/Wolverine.Kafka.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Test
- run: dotnet test src/Transports/Kafka/Wolverine.Kafka.Tests/Wolverine.Kafka.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run Kafka Tests
+ run: ./build.sh CIKafka --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/marten.yml b/.github/workflows/marten.yml
new file mode 100644
index 000000000..fe9ce2d51
--- /dev/null
+++ b/.github/workflows/marten.yml
@@ -0,0 +1,44 @@
+name: marten
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run Marten Tests
+ run: ./build.sh CIMarten --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/mqtt.yml b/.github/workflows/mqtt.yml
index 43561cebb..c0eceb0f6 100644
--- a/.github/workflows/mqtt.yml
+++ b/.github/workflows/mqtt.yml
@@ -13,49 +13,31 @@ env:
jobs:
test:
runs-on: ubuntu-latest
- timeout-minutes: 10
+ timeout-minutes: 15
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start PostgreSQL
- run: docker compose up -d postgresql
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if nc -z localhost 5433 > /dev/null 2>&1; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Build
- run: dotnet build src/Transports/MQTT/Wolverine.MQTT.Tests/Wolverine.MQTT.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Test
- run: dotnet test src/Transports/MQTT/Wolverine.MQTT.Tests/Wolverine.MQTT.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run MQTT Tests
+ run: ./build.sh CIMQTT --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml
new file mode 100644
index 000000000..91d43649c
--- /dev/null
+++ b/.github/workflows/mysql.yml
@@ -0,0 +1,44 @@
+name: mysql
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run MySQL Tests
+ run: ./build.sh CIMySql --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/nats.yml b/.github/workflows/nats.yml
index 204cbd5b4..4c67d9af7 100644
--- a/.github/workflows/nats.yml
+++ b/.github/workflows/nats.yml
@@ -13,61 +13,31 @@ env:
jobs:
test:
runs-on: ubuntu-latest
- timeout-minutes: 10
+ timeout-minutes: 15
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start NATS and PostgreSQL
- run: docker compose up -d nats postgresql
-
- - name: Wait for NATS
- run: |
- echo "Waiting for NATS to be ready..."
- for i in {1..30}; do
- if nc -z localhost 4222 > /dev/null 2>&1; then
- echo "NATS is ready"
- break
- fi
- echo "Attempt $i: NATS not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if nc -z localhost 5433 > /dev/null 2>&1; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Build
- run: dotnet build src/Transports/NATS/Wolverine.Nats.Tests/Wolverine.Nats.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Test
- run: dotnet test src/Transports/NATS/Wolverine.Nats.Tests/Wolverine.Nats.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run NATS Tests
+ run: ./build.sh CINATS --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml
new file mode 100644
index 000000000..88ebc9ded
--- /dev/null
+++ b/.github/workflows/oracle.yml
@@ -0,0 +1,44 @@
+name: oracle
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run Oracle Tests
+ run: ./build.sh CIOracle --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/persistence.yml b/.github/workflows/persistence.yml
index 6b8d25a63..1d9dad533 100644
--- a/.github/workflows/persistence.yml
+++ b/.github/workflows/persistence.yml
@@ -17,99 +17,28 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
-
+
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start containers
- run: docker compose up -d postgresql sqlserver mysql rabbitmq
-
- - name: Build
- run: |
- dotnet build src/Persistence/PersistenceTests/PersistenceTests.csproj --configuration ${{ env.config }} --framework net9.0
- dotnet build src/Persistence/PostgresqlTests/PostgresqlTests.csproj --configuration ${{ env.config }} --framework net10.0
- dotnet build src/Persistence/SqlServerTests/SqlServerTests.csproj --configuration ${{ env.config }} --framework net10.0
- dotnet build src/Persistence/MySql/MySqlTests/MySqlTests.csproj --configuration ${{ env.config }} --framework net10.0
- dotnet build src/Persistence/SqliteTests/SqliteTests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T postgresql pg_isready -U postgres; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for MySQL
- run: |
- echo "Waiting for MySQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T mysql mysqladmin ping -h localhost -u root -pP@55w0rd --silent; then
- echo "MySQL is ready"
- break
- fi
- echo "Attempt $i: MySQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for RabbitMQ
- run: |
- echo "Waiting for RabbitMQ to be ready..."
- for i in {1..30}; do
- if docker compose exec -T rabbitmq rabbitmq-diagnostics -q ping; then
- echo "RabbitMQ is ready"
- break
- fi
- echo "Attempt $i: RabbitMQ not ready yet, waiting..."
- sleep 2
- done
-
- - name: Test SqliteTests
- run: dotnet test src/Persistence/SqliteTests/SqliteTests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- - name: Test MySqlTests
- run: dotnet test src/Persistence/MySql/MySqlTests/MySqlTests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- - name: Test PersistenceTests
- run: dotnet test src/Persistence/PersistenceTests/PersistenceTests.csproj --configuration ${{ env.config }} --framework net9.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- - name: Wait for SQL Server
- run: |
- echo "Waiting for SQL Server to be ready..."
- for i in {1..30}; do
- if docker compose exec -T sqlserver /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'P@55w0rd' -C -Q "SELECT 1" > /dev/null 2>&1; then
- echo "SQL Server is ready"
- break
- fi
- echo "Attempt $i: SQL Server not ready yet, waiting..."
- sleep 2
- done
-
- - name: Test SqlServerTests
- run: dotnet test src/Persistence/SqlServerTests/SqlServerTests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run Persistence Tests
+ run: ./build.sh CIPersistence --framework net9.0
- - name: Test PostgresqlTests
- run: dotnet test src/Persistence/PostgresqlTests/PostgresqlTests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
-
- name: Stop containers
if: always()
run: docker compose down
diff --git a/.github/workflows/polecat.yml b/.github/workflows/polecat.yml
new file mode 100644
index 000000000..039d5fd63
--- /dev/null
+++ b/.github/workflows/polecat.yml
@@ -0,0 +1,44 @@
+name: polecat
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run Polecat Tests
+ run: ./build.sh CIPolecat --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/publish_nugets.yml b/.github/workflows/publish_nugets.yml
index 67b7803f7..7b179c898 100644
--- a/.github/workflows/publish_nugets.yml
+++ b/.github/workflows/publish_nugets.yml
@@ -8,20 +8,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
diff --git a/.github/workflows/pulsar.yml b/.github/workflows/pulsar.yml
index 86a15f59d..0303d0ecc 100644
--- a/.github/workflows/pulsar.yml
+++ b/.github/workflows/pulsar.yml
@@ -17,45 +17,27 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
-
+
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start Pulsar
- run: docker compose up -d pulsar
-
- - name: Wait for Pulsar
- run: |
- echo "Waiting for Pulsar to be ready..."
- for i in {1..60}; do
- if curl -s http://localhost:8080/admin/v2/brokers/healthcheck > /dev/null 2>&1; then
- echo "Pulsar is ready"
- break
- fi
- echo "Attempt $i: Pulsar not ready yet, waiting..."
- sleep 2
- done
-
- - name: Build
- run: dotnet build src/Transports/Pulsar/Wolverine.Pulsar.Tests/Wolverine.Pulsar.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Test
- run: dotnet test src/Transports/Pulsar/Wolverine.Pulsar.Tests/Wolverine.Pulsar.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run Pulsar Tests
+ run: ./build.sh CIPulsar --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/rabbitmq.yml b/.github/workflows/rabbitmq.yml
new file mode 100644
index 000000000..ec869cd20
--- /dev/null
+++ b/.github/workflows/rabbitmq.yml
@@ -0,0 +1,44 @@
+name: rabbitmq
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run RabbitMQ Tests
+ run: ./build.sh CIRabbitMQ --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.github/workflows/redis.yml b/.github/workflows/redis.yml
index b0580efb5..bf059a517 100644
--- a/.github/workflows/redis.yml
+++ b/.github/workflows/redis.yml
@@ -13,61 +13,31 @@ env:
jobs:
test:
runs-on: ubuntu-latest
- timeout-minutes: 10
+ timeout-minutes: 15
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET 8
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Setup .NET 9
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Setup .NET 10
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- - name: Start Redis and PostgreSQL
- run: docker compose up -d redis-server postgresql
-
- - name: Build
- run: dotnet build src/Transports/Redis/Wolverine.Redis.Tests/Wolverine.Redis.Tests.csproj --configuration ${{ env.config }} --framework net10.0
-
- - name: Wait for Redis
- run: |
- echo "Waiting for Redis to be ready..."
- for i in {1..30}; do
- if docker compose exec -T redis-server redis-cli ping | grep -q PONG; then
- echo "Redis is ready"
- break
- fi
- echo "Attempt $i: Redis not ready yet, waiting..."
- sleep 2
- done
-
- - name: Wait for PostgreSQL
- run: |
- echo "Waiting for PostgreSQL to be ready..."
- for i in {1..30}; do
- if docker compose exec -T postgresql pg_isready -U postgres; then
- echo "PostgreSQL is ready"
- break
- fi
- echo "Attempt $i: PostgreSQL not ready yet, waiting..."
- sleep 2
- done
-
- - name: Test
- run: dotnet test src/Transports/Redis/Wolverine.Redis.Tests/Wolverine.Redis.Tests.csproj --configuration ${{ env.config }} --framework net10.0 --no-build --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
+ - name: Run Redis Tests
+ run: ./build.sh CIRedis --framework net9.0
- name: Stop containers
if: always()
diff --git a/.github/workflows/sqlite.yml b/.github/workflows/sqlite.yml
new file mode 100644
index 000000000..3e174f324
--- /dev/null
+++ b/.github/workflows/sqlite.yml
@@ -0,0 +1,40 @@
+name: sqlite
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run Sqlite Tests
+ run: ./build.sh CISqlite --framework net9.0
diff --git a/.github/workflows/sqlserver.yml b/.github/workflows/sqlserver.yml
new file mode 100644
index 000000000..2bbcda89b
--- /dev/null
+++ b/.github/workflows/sqlserver.yml
@@ -0,0 +1,44 @@
+name: sqlserver
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+env:
+ config: Release
+ disable_test_parallelization: true
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET 8
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Setup .NET 10
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 10.0.x
+
+ - name: Run SQL Server Tests
+ run: ./build.sh CISqlServer --framework net9.0
+
+ - name: Stop containers
+ if: always()
+ run: docker compose down
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
index cac017234..8c89ad57b 100644
--- a/.nuke/build.schema.json
+++ b/.nuke/build.schema.json
@@ -28,6 +28,24 @@
"Attach",
"BankingServiceSampleTests",
"CI",
+ "CIAWS",
+ "CIAzureServiceBus",
+ "CICosmosDb",
+ "CIEfCore",
+ "CIHttp",
+ "CIKafka",
+ "CIMarten",
+ "CIMQTT",
+ "CIMySql",
+ "CINATS",
+ "CIOracle",
+ "CIPersistence",
+ "CIPolecat",
+ "CIPulsar",
+ "CIRabbitMQ",
+ "CIRedis",
+ "CISqlite",
+ "CISqlServer",
"CodegenPreviewCommand",
"Commands",
"Compile",
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 4f092c87d..f265d5323 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -26,6 +26,7 @@
+
@@ -76,6 +77,13 @@
+
+
+
+
+
+
+
diff --git a/DomainEventsWithEfCore/BackLogService/Code.cs b/DomainEventsWithEfCore/BackLogService/Code.cs
index a5f52c1bd..3fca620fe 100644
--- a/DomainEventsWithEfCore/BackLogService/Code.cs
+++ b/DomainEventsWithEfCore/BackLogService/Code.cs
@@ -4,8 +4,8 @@ public class BacklogItem
{
public Guid Id { get; private set; }
- public string Description { get; private set; }
- public virtual Sprint Sprint { get; private set; }
+ public string Description { get; private set; } = null!;
+ public virtual Sprint Sprint { get; private set; } = null!;
public DateTime CreatedAtUtc { get; private set; } = DateTime.UtcNow;
public void CommitTo(Sprint sprint)
diff --git a/DomainEventsWithEfCore/BackLogService/Program.cs b/DomainEventsWithEfCore/BackLogService/Program.cs
index bf3f06a2f..e5f12a3b7 100644
--- a/DomainEventsWithEfCore/BackLogService/Program.cs
+++ b/DomainEventsWithEfCore/BackLogService/Program.cs
@@ -13,7 +13,7 @@
builder.UseWolverine(opts =>
{
opts.UseEntityFrameworkCoreTransactions();
- opts.PersistMessagesWithPostgresql(connectionString, "wolverine");
+ opts.PersistMessagesWithPostgresql(connectionString!, "wolverine");
opts.Policies.AutoApplyTransactions();
});
diff --git a/DomainEventsWithEfCore/BackLogService/Relay/Code.cs b/DomainEventsWithEfCore/BackLogService/Relay/Code.cs
index 1fd976198..163df39fd 100644
--- a/DomainEventsWithEfCore/BackLogService/Relay/Code.cs
+++ b/DomainEventsWithEfCore/BackLogService/Relay/Code.cs
@@ -11,8 +11,8 @@ public class BacklogItem
{
public Guid Id { get; private set; }
- public string Description { get; private set; }
- public virtual Sprint Sprint { get; private set; }
+ public string Description { get; private set; } = null!;
+ public virtual Sprint Sprint { get; private set; } = null!;
public DateTime CreatedAtUtc { get; private set; } = DateTime.UtcNow;
// The exact return type isn't hugely important here
diff --git a/DomainEventsWithEfCore/BackLogService/Scraping/Code.cs b/DomainEventsWithEfCore/BackLogService/Scraping/Code.cs
index 3d11f5a59..3caabde42 100644
--- a/DomainEventsWithEfCore/BackLogService/Scraping/Code.cs
+++ b/DomainEventsWithEfCore/BackLogService/Scraping/Code.cs
@@ -31,8 +31,8 @@ public class BacklogItem : Entity
{
public Guid Id { get; private set; }
- public string Description { get; private set; }
- public virtual Sprint Sprint { get; private set; }
+ public string Description { get; private set; } = null!;
+ public virtual Sprint Sprint { get; private set; } = null!;
public DateTime CreatedAtUtc { get; private set; } = DateTime.UtcNow;
public void CommitTo(Sprint sprint)
diff --git a/DomainEventsWithEfCore/BackLogService/UseEventPublisher/Code.cs b/DomainEventsWithEfCore/BackLogService/UseEventPublisher/Code.cs
index 830455d41..9b87ec4aa 100644
--- a/DomainEventsWithEfCore/BackLogService/UseEventPublisher/Code.cs
+++ b/DomainEventsWithEfCore/BackLogService/UseEventPublisher/Code.cs
@@ -30,7 +30,7 @@ public class RecordingEventPublisher : OutgoingMessages, IEventPublisher
{
public void Publish(T @event)
{
- Add(@event);
+ Add(@event!);
}
}
@@ -79,7 +79,7 @@ public async Task LoadAsync(Guid id)
item.Publisher = _publisher;
}
- return item;
+ return item!;
}
}
@@ -109,11 +109,11 @@ public class BacklogItem : Entity
{
public Guid Id { get; private set; } = Guid.CreateVersion7();
- public string Description { get; private set; }
-
+ public string Description { get; private set; } = null!;
+
// ZOMG, I forgot how annoying ORMs are. Use a document database
// and stop worrying about making things virtual just for lazy loading
- public virtual Sprint Sprint { get; private set; }
+ public virtual Sprint Sprint { get; private set; } = null!;
public void CommitTo(Sprint sprint)
{
@@ -144,6 +144,6 @@ ItemsDbContext dbContext
// This method would cause an event to be published within
// the BacklogItem object here that we need to gather up and
// relay to Wolverine later
- item.CommitTo(sprint);
+ item.CommitTo(sprint!);
}
}
\ No newline at end of file
diff --git a/NuGet.config b/NuGet.config
index 426bc9097..9636fc762 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -2,21 +2,13 @@
-
-
-
-
-
-
-
-
diff --git a/build/CITargets.cs b/build/CITargets.cs
new file mode 100644
index 000000000..349f5bf12
--- /dev/null
+++ b/build/CITargets.cs
@@ -0,0 +1,437 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using Nuke.Common;
+using Nuke.Common.IO;
+using Nuke.Common.Tooling;
+using Nuke.Common.Tools.DotNet;
+using Serilog;
+using static Nuke.Common.Tools.DotNet.DotNetTasks;
+
+partial class Build
+{
+ ///
+ /// Starts specific docker compose services and waits for them to be ready.
+ ///
+ void StartDockerServices(params string[] services)
+ {
+ bool IsToolAvailable(string toolName)
+ {
+ try
+ { ToolPathResolver.GetPathExecutable(toolName);
+ return true; }
+ catch (ArgumentException)
+ { return false; }
+ }
+
+ string toolName = new List { "docker", "podman" }
+ .FirstOrDefault(IsToolAvailable) ?? "docker";
+
+ var serviceList = string.Join(" ", services);
+ Log.Information("Starting docker services: {Services}", serviceList);
+
+ // Pass each service as a separate argument to avoid quoting issues
+ var args = "compose up -d " + serviceList;
+ ProcessTasks
+ .StartProcess(toolName, args, logOutput: false, logInvocation: false)
+ .AssertWaitForExit()
+ .AssertZeroExitCode();
+
+ // Wait for databases that were requested
+ if (services.Contains("postgresql"))
+ WaitForDatabaseToBeReady();
+ if (services.Contains("sqlserver"))
+ WaitForSqlServerToBeReady();
+ if (services.Contains("mysql"))
+ WaitForMySqlToBeReady();
+ if (services.Contains("oracle"))
+ WaitForOracleToBeReady();
+ if (services.Contains("localstack"))
+ WaitForLocalStackToBeReady();
+ if (services.Contains("asb-emulator"))
+ WaitForAzureServiceBusEmulatorToBeReady();
+ }
+
+ void WaitForSqlServerToBeReady()
+ {
+ var attempt = 0;
+ while (attempt < 30)
+ {
+ try
+ {
+ using var conn = new Microsoft.Data.SqlClient.SqlConnection("Server=localhost,1434;User Id=sa;Password=P@55w0rd;Timeout=5;Encrypt=False");
+ conn.Open();
+ var cmd = conn.CreateCommand();
+ cmd.CommandText = "SELECT 1";
+ cmd.ExecuteNonQuery();
+ Log.Information("SQL Server is up and ready!");
+ return;
+ }
+ catch (Exception)
+ {
+ Thread.Sleep(2000);
+ attempt++;
+ }
+ }
+
+ Log.Warning("SQL Server did not become ready after 60 seconds");
+ }
+
+ void WaitForMySqlToBeReady()
+ {
+ var attempt = 0;
+ while (attempt < 30)
+ {
+ try
+ {
+ using var conn = new MySqlConnector.MySqlConnection("Server=localhost;Port=3306;Database=wolverine;User=root;Password=P@55w0rd;");
+ conn.Open();
+ var cmd = conn.CreateCommand();
+ cmd.CommandText = "SELECT 1";
+ cmd.ExecuteNonQuery();
+ Log.Information("MySQL is up and ready!");
+ return;
+ }
+ catch (Exception)
+ {
+ Thread.Sleep(2000);
+ attempt++;
+ }
+ }
+
+ Log.Warning("MySQL did not become ready after 60 seconds");
+ }
+
+ void WaitForOracleToBeReady()
+ {
+ var attempt = 0;
+ while (attempt < 60)
+ {
+ try
+ {
+ using var conn = new Oracle.ManagedDataAccess.Client.OracleConnection("User Id=wolverine;Password=wolverine;Data Source=localhost:1521/FREEPDB1");
+ conn.Open();
+ var cmd = conn.CreateCommand();
+ cmd.CommandText = "SELECT 1 FROM DUAL";
+ cmd.ExecuteNonQuery();
+ Log.Information("Oracle is up and ready!");
+ return;
+ }
+ catch (Exception)
+ {
+ Thread.Sleep(2000);
+ attempt++;
+ }
+ }
+
+ Log.Warning("Oracle did not become ready after 120 seconds");
+ }
+
+ void WaitForLocalStackToBeReady()
+ {
+ var attempt = 0;
+ using var httpClient = new System.Net.Http.HttpClient { Timeout = TimeSpan.FromSeconds(5) };
+ while (attempt < 30)
+ {
+ try
+ {
+ var response = httpClient.GetAsync("http://localhost:4566/_localstack/health").GetAwaiter().GetResult();
+ if (response.IsSuccessStatusCode)
+ {
+ Log.Information("LocalStack is up and ready!");
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ // ignore connection errors
+ }
+
+ Thread.Sleep(2000);
+ attempt++;
+ }
+
+ Log.Warning("LocalStack did not become ready after 60 seconds");
+ }
+
+ void WaitForAzureServiceBusEmulatorToBeReady()
+ {
+ var attempt = 0;
+ while (attempt < 30)
+ {
+ try
+ {
+ using var tcpClient = new System.Net.Sockets.TcpClient();
+ tcpClient.Connect("localhost", 5673);
+ Log.Information("Azure Service Bus emulator is up and ready!");
+ return;
+ }
+ catch (Exception)
+ {
+ // ignore connection errors
+ }
+
+ Thread.Sleep(2000);
+ attempt++;
+ }
+
+ Log.Warning("Azure Service Bus emulator did not become ready after 60 seconds");
+ }
+
+ ///
+ /// Builds specific test projects (not the entire solution).
+ ///
+ void BuildTestProjects(params AbsolutePath[] projects)
+ {
+ BuildTestProjectsWithFramework(null, projects);
+ }
+
+ void BuildTestProjectsWithFramework(string frameworkOverride, params AbsolutePath[] projects)
+ {
+ var framework = frameworkOverride ?? Framework;
+ foreach (var project in projects)
+ {
+ Log.Information("Building {Project} ({Framework})...", project.Name, framework ?? "all");
+ DotNetBuild(c => c
+ .SetProjectFile(project)
+ .SetConfiguration(Configuration)
+ .SetFramework(framework));
+ }
+ }
+
+ // ─── Persistence CI Targets ────────────────────────────────────────
+
+ Target CIPersistence => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var persistenceTests = RootDirectory / "src" / "Persistence" / "PersistenceTests" / "PersistenceTests.csproj";
+ var postgresqlTests = RootDirectory / "src" / "Persistence" / "PostgresqlTests" / "PostgresqlTests.csproj";
+
+ BuildTestProjects(postgresqlTests);
+ // PersistenceTests only targets net8.0/net9.0
+ BuildTestProjectsWithFramework("net9.0", persistenceTests);
+ StartDockerServices("postgresql", "sqlserver", "rabbitmq");
+
+ RunSingleProjectOneClassAtATime(persistenceTests, frameworkOverride: "net9.0");
+ RunSingleProjectOneClassAtATime(postgresqlTests);
+ });
+
+ Target CISqlite => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var sqliteTests = RootDirectory / "src" / "Persistence" / "SqliteTests" / "SqliteTests.csproj";
+
+ BuildTestProjects(sqliteTests);
+
+ RunSingleProjectOneClassAtATime(sqliteTests);
+ });
+
+ Target CISqlServer => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var sqlServerTests = RootDirectory / "src" / "Persistence" / "SqlServerTests" / "SqlServerTests.csproj";
+
+ BuildTestProjects(sqlServerTests);
+ StartDockerServices("sqlserver");
+
+ RunSingleProjectOneClassAtATime(sqlServerTests);
+ });
+
+ Target CIMarten => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var martenTests = RootDirectory / "src" / "Persistence" / "MartenTests" / "MartenTests.csproj";
+ var martenSubscriptionTests = RootDirectory / "src" / "Persistence" / "MartenSubscriptionTests" / "MartenSubscriptionTests.csproj";
+
+ BuildTestProjects(martenTests, martenSubscriptionTests);
+ StartDockerServices("postgresql");
+
+ RunSingleProjectOneClassAtATime(martenTests);
+ RunSingleProjectOneClassAtATime(martenSubscriptionTests);
+ });
+
+ Target CIMySql => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var mySqlTests = RootDirectory / "src" / "Persistence" / "MySql" / "MySqlTests" / "MySqlTests.csproj";
+
+ BuildTestProjects(mySqlTests);
+ StartDockerServices("mysql");
+
+ RunSingleProjectOneClassAtATime(mySqlTests);
+ });
+
+ Target CIOracle => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var oracleTests = RootDirectory / "src" / "Persistence" / "Oracle" / "OracleTests" / "OracleTests.csproj";
+
+ BuildTestProjects(oracleTests);
+ StartDockerServices("oracle");
+
+ RunSingleProjectOneClassAtATime(oracleTests);
+ });
+
+ Target CIEfCore => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var efCoreTests = RootDirectory / "src" / "Persistence" / "EfCoreTests" / "EfCoreTests.csproj";
+ var efCoreMultiTenancy = RootDirectory / "src" / "Persistence" / "EfCoreTests.MultiTenancy" / "EfCoreTests.MultiTenancy.csproj";
+
+ BuildTestProjects(efCoreTests, efCoreMultiTenancy);
+ StartDockerServices("postgresql", "sqlserver");
+
+ RunSingleProjectOneClassAtATime(efCoreTests);
+ RunSingleProjectOneClassAtATime(efCoreMultiTenancy);
+ });
+
+ // ─── Transport CI Targets ──────────────────────────────────────────
+
+ Target CIAWS => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var sqsTests = RootDirectory / "src" / "Transports" / "AWS" / "Wolverine.AmazonSqs.Tests" / "Wolverine.AmazonSqs.Tests.csproj";
+ var snsTests = RootDirectory / "src" / "Transports" / "AWS" / "Wolverine.AmazonSns.Tests" / "Wolverine.AmazonSns.Tests.csproj";
+
+ BuildTestProjects(sqsTests, snsTests);
+ StartDockerServices("localstack", "postgresql");
+
+ RunSingleProjectOneClassAtATime(sqsTests);
+ RunSingleProjectOneClassAtATime(snsTests);
+ });
+
+ Target CIKafka => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "Kafka" / "Wolverine.Kafka.Tests" / "Wolverine.Kafka.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("postgresql");
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CIMQTT => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "MQTT" / "Wolverine.MQTT.Tests" / "Wolverine.MQTT.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("postgresql");
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CINATS => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "NATS" / "Wolverine.Nats.Tests" / "Wolverine.Nats.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("postgresql");
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CIPulsar => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "Pulsar" / "Wolverine.Pulsar.Tests" / "Wolverine.Pulsar.Tests.csproj";
+
+ BuildTestProjects(tests);
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CIRedis => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "Redis" / "Wolverine.Redis.Tests" / "Wolverine.Redis.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("postgresql");
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CIHttp => _ => _
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Http" / "Wolverine.Http.Tests" / "Wolverine.Http.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("postgresql");
+
+ var framework = Framework;
+ DotNetTest(c => c
+ .SetProjectFile(tests)
+ .SetConfiguration(Configuration)
+ .SetFramework(framework)
+ .EnableNoBuild());
+ });
+
+ Target CIRabbitMQ => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var rabbitTests = RootDirectory / "src" / "Transports" / "RabbitMQ" / "Wolverine.RabbitMQ.Tests" / "Wolverine.RabbitMQ.Tests.csproj";
+ var circuitTests = RootDirectory / "src" / "Transports" / "RabbitMQ" / "CircuitBreakingTests" / "CircuitBreakingTests.csproj";
+
+ BuildTestProjects(rabbitTests, circuitTests);
+ StartDockerServices("rabbitmq", "postgresql", "sqlserver");
+
+ RunSingleProjectOneClassAtATime(rabbitTests);
+ RunSingleProjectOneClassAtATime(circuitTests);
+ });
+
+ Target CICosmosDb => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var cosmosDbTests = RootDirectory / "src" / "Persistence" / "CosmosDbTests" / "CosmosDbTests.csproj";
+ var leaderElectionTests = RootDirectory / "src" / "Persistence" / "LeaderElection" / "CosmosDbTests.LeaderElection" / "CosmosDbTests.LeaderElection.csproj";
+
+ BuildTestProjects(cosmosDbTests, leaderElectionTests);
+
+ RunSingleProjectOneClassAtATime(cosmosDbTests);
+ RunSingleProjectOneClassAtATime(leaderElectionTests);
+ });
+
+ Target CIAzureServiceBus => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var tests = RootDirectory / "src" / "Transports" / "Azure" / "Wolverine.AzureServiceBus.Tests" / "Wolverine.AzureServiceBus.Tests.csproj";
+
+ BuildTestProjects(tests);
+ StartDockerServices("asb-emulator");
+
+ RunSingleProjectOneClassAtATime(tests);
+ });
+
+ Target CIPolecat => _ => _
+ .ProceedAfterFailure()
+ .Executes(() =>
+ {
+ var polecatTests = RootDirectory / "src" / "Persistence" / "PolecatTests" / "PolecatTests.csproj";
+
+ BuildTestProjectsWithFramework("net10.0", polecatTests);
+ StartDockerServices("sqlserver");
+
+ RunSingleProjectOneClassAtATime(polecatTests, frameworkOverride: "net10.0");
+ });
+}
diff --git a/build/TestAllPersistence.cs b/build/TestAllPersistence.cs
index 2dd51d0e8..fbbdebf9c 100644
--- a/build/TestAllPersistence.cs
+++ b/build/TestAllPersistence.cs
@@ -1,6 +1,8 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
using Nuke.Common;
using Nuke.Common.IO;
using Nuke.Common.Tools.DotNet;
@@ -15,10 +17,163 @@ partial class Build
.Executes(() =>
{
var persistenceDir = RootDirectory / "src" / "Persistence";
- RunTestProjectsOneFileAtATime(persistenceDir);
+ RunTestProjectsOneClassAtATime(persistenceDir);
});
- void RunTestProjectsOneFileAtATime(AbsolutePath directory)
+ ///
+ /// Files that are never test classes and should be skipped during discovery.
+ ///
+ static readonly HashSet SkippedFileNames = new(StringComparer.OrdinalIgnoreCase)
+ {
+ "NoParallelization",
+ "GlobalUsings",
+ "AssemblyInfo",
+ "Usings",
+ "ModuleInitializer",
+ };
+
+ ///
+ /// Regex patterns that indicate a file contains xUnit test methods.
+ ///
+ static readonly Regex TestAttributePattern = new(
+ @"\[\s*(Fact|Theory|InlineData|MemberData|ClassData)",
+ RegexOptions.Compiled);
+
+ ///
+ /// Determines if a project is a leader election test project,
+ /// which requires running each test method individually.
+ ///
+ static bool IsLeaderElectionProject(string projectPath)
+ {
+ var projectName = Path.GetFileNameWithoutExtension(projectPath);
+ return projectName.Contains("LeaderElection", StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Discovers test classes from source files by looking for [Fact] or [Theory] attributes.
+ /// Returns the class name (file name without extension) for files that contain tests.
+ ///
+ static List DiscoverTestClasses(string projectDir)
+ {
+ var testFiles = Directory.GetFiles(projectDir, "*.cs", SearchOption.AllDirectories)
+ .Where(f => !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}")
+ && !f.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}"))
+ .OrderBy(f => f)
+ .ToList();
+
+ var testClasses = new List();
+ foreach (var testFile in testFiles)
+ {
+ var className = Path.GetFileNameWithoutExtension(testFile);
+
+ if (SkippedFileNames.Contains(className))
+ continue;
+
+ try
+ {
+ var content = File.ReadAllText(testFile);
+ if (TestAttributePattern.IsMatch(content))
+ {
+ testClasses.Add(className);
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Warning("Could not read {File}: {Message}", testFile, ex.Message);
+ }
+ }
+
+ return testClasses;
+ }
+
+ ///
+ /// Discovers individual test method names from source files for leader election projects.
+ /// Returns tuples of (className, methodName).
+ ///
+ static List<(string ClassName, string MethodName)> DiscoverTestMethods(string projectDir)
+ {
+ var methodPattern = new Regex(
+ @"\[\s*(?:Fact|Theory).*?\]\s*(?:\[.*?\]\s*)*public\s+(?:async\s+)?(?:Task|void)\s+(\w+)\s*\(",
+ RegexOptions.Compiled | RegexOptions.Singleline);
+
+ var testFiles = Directory.GetFiles(projectDir, "*.cs", SearchOption.AllDirectories)
+ .Where(f => !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}")
+ && !f.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}"))
+ .ToList();
+
+ var results = new List<(string, string)>();
+
+ foreach (var testFile in testFiles)
+ {
+ var className = Path.GetFileNameWithoutExtension(testFile);
+ if (SkippedFileNames.Contains(className)) continue;
+
+ try
+ {
+ var content = File.ReadAllText(testFile);
+ var matches = methodPattern.Matches(content);
+ foreach (Match match in matches)
+ {
+ results.Add((className, match.Groups[1].Value));
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Warning("Could not read {File}: {Message}", testFile, ex.Message);
+ }
+ }
+
+ return results;
+ }
+
+ ///
+ /// Runs a single dotnet test invocation with retry logic.
+ /// Returns true if the test passed (on first attempt or retry).
+ ///
+ bool RunTestWithRetry(string projectPath, string filter, string description, int maxAttempts = 2, string frameworkOverride = null)
+ {
+ var framework = frameworkOverride ?? Framework;
+ for (var attempt = 1; attempt <= maxAttempts; attempt++)
+ {
+ try
+ {
+ if (attempt > 1)
+ {
+ Log.Warning(" Retry attempt {Attempt} for {Description}", attempt, description);
+ }
+
+ DotNetTest(c => c
+ .SetProjectFile(projectPath)
+ .SetConfiguration(Configuration)
+ .EnableNoBuild()
+ .EnableNoRestore()
+ .SetFramework(framework)
+ .SetFilter(filter));
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ if (attempt == maxAttempts)
+ {
+ Log.Error(" {Description} failed after {Attempts} attempts: {Message}",
+ description, maxAttempts, ex.Message);
+ return false;
+ }
+
+ Log.Warning(" {Description} failed on attempt {Attempt}, will retry: {Message}",
+ description, attempt, ex.Message);
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Improved test runner that discovers actual test classes from source,
+ /// runs each class in isolation, and supports leader election one-test-at-a-time mode.
+ ///
+ void RunTestProjectsOneClassAtATime(AbsolutePath directory)
{
var testProjects = directory.GlobFiles("**/*Tests.csproj", "**/*Tests/*.csproj")
.Select(p => p.ToString())
@@ -26,38 +181,127 @@ void RunTestProjectsOneFileAtATime(AbsolutePath directory)
.OrderBy(p => p)
.ToList();
+ var failedTests = new List();
+
foreach (var projectPath in testProjects)
{
- var projectDir = Path.GetDirectoryName(projectPath);
- var testFiles = Directory.GetFiles(projectDir!, "*.cs", SearchOption.AllDirectories)
- .Where(f => !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}")
- && !f.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}"))
- .OrderBy(f => f)
- .ToList();
-
+ var projectDir = Path.GetDirectoryName(projectPath)!;
var projectName = Path.GetFileNameWithoutExtension(projectPath);
- Log.Information("Running tests one file at a time for {Project} ({Count} files)", projectName, testFiles.Count);
- foreach (var testFile in testFiles)
+ if (IsLeaderElectionProject(projectPath))
+ {
+ // Leader election: run each test method individually
+ var testMethods = DiscoverTestMethods(projectDir);
+ Log.Information("Running leader election tests one method at a time for {Project} ({Count} tests)",
+ projectName, testMethods.Count);
+
+ foreach (var (className, methodName) in testMethods)
+ {
+ var filter = $"FullyQualifiedName~{className}.{methodName}";
+ var description = $"{projectName}/{className}.{methodName}";
+ Log.Information(" Running {Description}...", description);
+
+ if (!RunTestWithRetry(projectPath, filter, description))
+ {
+ failedTests.Add(description);
+ }
+ }
+ }
+ else
+ {
+ // Normal: run one class at a time
+ var testClasses = DiscoverTestClasses(projectDir);
+ Log.Information("Running tests one class at a time for {Project} ({Count} classes)",
+ projectName, testClasses.Count);
+
+ foreach (var className in testClasses)
+ {
+ var filter = AppendCategoryFilter($"FullyQualifiedName~{className}");
+ var description = $"{projectName}/{className}";
+ Log.Information(" Running {Description}...", description);
+
+ if (!RunTestWithRetry(projectPath, filter, description))
+ {
+ failedTests.Add(description);
+ }
+ }
+ }
+ }
+
+ if (failedTests.Any())
+ {
+ Log.Error("The following tests failed after retries:");
+ foreach (var test in failedTests)
+ {
+ Log.Error(" - {Test}", test);
+ }
+ }
+ }
+
+ ///
+ /// Appends Category!=Flaky to a test filter when running in CI.
+ ///
+ static string AppendCategoryFilter(string filter)
+ {
+ return filter + "&Category!=Flaky";
+ }
+
+ ///
+ /// Runs a single test project one class at a time with retry logic.
+ /// Used by individual Nuke targets for specific test projects.
+ ///
+ void RunSingleProjectOneClassAtATime(string projectPath, string frameworkOverride = null)
+ {
+ var projectDir = Path.GetDirectoryName(projectPath)!;
+ var projectName = Path.GetFileNameWithoutExtension(projectPath);
+ var failedTests = new List();
+
+ if (IsLeaderElectionProject(projectPath))
+ {
+ var testMethods = DiscoverTestMethods(projectDir);
+ Log.Information("Running leader election tests one method at a time for {Project} ({Count} tests)",
+ projectName, testMethods.Count);
+
+ foreach (var (className, methodName) in testMethods)
{
- var className = Path.GetFileNameWithoutExtension(testFile);
- Log.Information(" Running tests in {ClassName}...", className);
+ var filter = AppendCategoryFilter($"FullyQualifiedName~{className}.{methodName}");
+ var description = $"{projectName}/{className}.{methodName}";
+ Log.Information(" Running {Description}...", description);
- try
+ if (!RunTestWithRetry(projectPath, filter, description, frameworkOverride: frameworkOverride))
{
- DotNetTest(c => c
- .SetProjectFile(projectPath)
- .SetConfiguration(Configuration)
- .EnableNoBuild()
- .EnableNoRestore()
- .SetFramework(Framework)
- .SetFilter($"FullyQualifiedName~{className}"));
+ failedTests.Add(description);
}
- catch (Exception ex)
+ }
+ }
+ else
+ {
+ var testClasses = DiscoverTestClasses(projectDir);
+ Log.Information("Running tests one class at a time for {Project} ({Count} classes)",
+ projectName, testClasses.Count);
+
+ foreach (var className in testClasses)
+ {
+ var filter = AppendCategoryFilter($"FullyQualifiedName~{className}");
+ var description = $"{projectName}/{className}";
+ Log.Information(" Running {Description}...", description);
+
+ if (!RunTestWithRetry(projectPath, filter, description, frameworkOverride: frameworkOverride))
{
- Log.Error(" Tests in {ClassName} failed: {Message}", className, ex.Message);
+ failedTests.Add(description);
}
}
}
+
+ if (failedTests.Any())
+ {
+ Log.Error("The following tests failed after retries:");
+ foreach (var test in failedTests)
+ {
+ Log.Error(" - {Test}", test);
+ }
+
+ throw new Exception($"{failedTests.Count} test(s) failed in {projectName}");
+ }
}
}
diff --git a/build/TestAllTransports.cs b/build/TestAllTransports.cs
index ae8794895..a227f62dc 100644
--- a/build/TestAllTransports.cs
+++ b/build/TestAllTransports.cs
@@ -1,11 +1,4 @@
-using System;
-using System.IO;
-using System.Linq;
using Nuke.Common;
-using Nuke.Common.IO;
-using Nuke.Common.Tools.DotNet;
-using Serilog;
-using static Nuke.Common.Tools.DotNet.DotNetTasks;
partial class Build
{
@@ -15,6 +8,6 @@ partial class Build
.Executes(() =>
{
var transportsDir = RootDirectory / "src" / "Transports";
- RunTestProjectsOneFileAtATime(transportsDir);
+ RunTestProjectsOneClassAtATime(transportsDir);
});
}
diff --git a/build/build.csproj b/build/build.csproj
index 122f244a0..cdae85c67 100644
--- a/build/build.csproj
+++ b/build/build.csproj
@@ -12,8 +12,11 @@
+
+
+
\ No newline at end of file
diff --git a/ci-improvements.md b/ci-improvements.md
new file mode 100644
index 000000000..095cc18a1
--- /dev/null
+++ b/ci-improvements.md
@@ -0,0 +1,55 @@
+# CI Improvements - Remaining Work & Status
+
+## Completed TestContainers Migrations
+
+| Transport | Status | Notes |
+|-----------|--------|-------|
+| NATS | Done | Collection fixture with reference counting |
+| Redis | Done | ModuleInitializer, 87/87 pass |
+| Kafka | Done | ModuleInitializer, 91 pass / 2 transient DLQ failures |
+| Pulsar | Done | ModuleInitializer, 89 pass / 12 flaky reliability tests |
+| MQTT | Done | Generic ContainerBuilder for Mosquitto, 73 pass / 3 transient |
+| AWS SQS | Done | LocalStack v4, 140 pass / 4 RawJson failures (pre-existing) |
+| AWS SNS | Done | LocalStack v4, 78/78 pass |
+| CosmosDb | Done (testing) | Shared static container, awaiting test results |
+| Azure Service Bus | Done (untested locally) | ServiceBusBuilder with MsSql backing store |
+
+## Remaining TestContainers Work
+
+- **GCP Pub/Sub**: Not yet converted. Uses docker-compose `pubsub-emulator` on port 8085. Would need generic ContainerBuilder with `gcr.io/google.com/cloudsdktool/google-cloud-cli` or similar.
+- **CosmosDb test verification**: Test run `bzrh2vnsw` in progress with shared static container fix. Previous run failed (56/62) due to multiple AppFixture instances each starting their own emulator.
+- **Azure Service Bus test verification**: Not tested locally yet. The ServiceBusContainerFixture uses Testcontainers.ServiceBus module with MsSql backing store.
+
+## CI Target / Workflow Status
+
+| Target | Workflow | Status |
+|--------|----------|--------|
+| CIPersistence | persistence.yml | Reduced: sqlite, PersistenceTests, sqlserver, postgresql |
+| CIMySql | mysql.yml | New: split from persistence |
+| CIOracle | oracle.yml | New: split from persistence |
+| CIEfCore | efcore.yml | Existing |
+| CIAWS | aws.yml | Updated: no localstack in docker-compose |
+| CIKafka | kafka.yml | Updated: no kafka in docker-compose |
+| CIMQTT | mqtt.yml | Updated: no mosquitto in docker-compose |
+| CINATS | nats.yml | Updated: no nats in docker-compose |
+| CIPulsar | pulsar.yml | Updated: no docker-compose at all |
+| CIRedis | redis.yml | Updated: no redis in docker-compose |
+| CIRabbitMQ | rabbitmq.yml | Fixed: added sqlserver to docker services |
+| CIHttp | http.yml | Simplified: plain dotnet test (no retry) |
+| CICosmosDb | cosmosdb.yml | New |
+| CIAzureServiceBus | azure-service-bus.yml | New |
+
+## Known Pre-existing Test Failures
+
+- **SQS RawJson tests** (4 tests): `receive_raw_json_as_buffered` and `receive_raw_json_as_inline` - LocalStack v4 incompatibility with native JSON message handling
+- **Pulsar reliability tests** (~12 tests): Timing-sensitive retry/redelivery tests that are flaky
+- **Kafka DLQ tests** (2 tests): Transient timing issues with dead letter queue
+- **MQTT tests** (3 tests): Transient timing issues
+- **RabbitMQ flaky tests**: `use_fan_out_exchange`, `use_direct_exchange_with_binding_key`, DLQ polling tests with tight timeouts (1.25s)
+
+## Potential Future Improvements
+
+- Increase DLQ polling timeouts in RabbitMQ tests (currently 5 retries * 250ms = 1.25s)
+- Consider converting RabbitMQ to TestContainers (currently uses docker-compose)
+- Consider converting PostgreSQL/SQL Server to TestContainers (currently docker-compose, used by many projects)
+- Add `[Trait]` attributes to flaky tests for optional skip in CI
diff --git a/docker-compose.yml b/docker-compose.yml
index 019774d29..1ddd27c4e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,14 +6,14 @@ networks:
services:
mosquitto:
- image: "eclipse-mosquitto:latest"
+ image: "eclipse-mosquitto:2"
ports:
- "1883:1883"
volumes:
- ./docker/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
postgresql:
- image: "postgres:latest"
+ image: "postgres:17"
ports:
- "5433:5432"
environment:
@@ -42,15 +42,15 @@ services:
"--log-http",
"--user-output-enabled",
]
-
+
rabbitmq:
- image: "rabbitmq:management"
+ image: "rabbitmq:4-management"
ports:
- "5672:5672"
- "15672:15672"
sqlserver:
- image: "mcr.microsoft.com/azure-sql-edge"
+ image: "mcr.microsoft.com/azure-sql-edge:latest"
ports:
- "1434:1433"
environment:
@@ -59,14 +59,14 @@ services:
- "MSSQL_PID=Developer"
pulsar:
- image: "apachepulsar/pulsar:latest"
+ image: "apachepulsar/pulsar:4.0"
ports:
- "6650:6650"
- "8080:8080"
command: bin/pulsar standalone
localstack:
- image: localstack/localstack:stable
+ image: localstack/localstack:4
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:4510-4559:4510-4559" # external services port range
@@ -80,29 +80,21 @@ services:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
- zookeeper:
- image: confluentinc/cp-zookeeper:latest
- environment:
- ZOOKEEPER_CLIENT_PORT: 2181
- ZOOKEEPER_TICK_TIME: 2000
- ports:
- - 22181:2181
-
kafka:
- image: confluentinc/confluent-local:latest
+ image: confluentinc/confluent-local:7.7.1
ports:
- "8082:8082"
- "9092:9092"
- "9101:9101"
-
+
redis-server:
- image: "redis:alpine"
+ image: "redis:7-alpine"
command: redis-server
ports:
- "6379:6379"
nats:
- image: "nats:latest"
+ image: "nats:2"
ports:
- "4222:4222"
- "8222:8222"
@@ -128,7 +120,7 @@ services:
- ./docker/oracle:/container-entrypoint-initdb.d
asb-sql:
- image: "mcr.microsoft.com/azure-sql-edge"
+ image: "mcr.microsoft.com/azure-sql-edge:latest"
environment:
- "ACCEPT_EULA=Y"
- "MSSQL_SA_PASSWORD=Strong_Passw0rd#2025"
@@ -161,7 +153,7 @@ services:
- "PROTOCOL=https"
asb-sql-2:
- image: "mcr.microsoft.com/azure-sql-edge"
+ image: "mcr.microsoft.com/azure-sql-edge:latest"
environment:
- "ACCEPT_EULA=Y"
- "MSSQL_SA_PASSWORD=Strong_Passw0rd#2025"
@@ -183,4 +175,4 @@ services:
depends_on:
- asb-sql-2
networks:
- sb-emulator-2:
\ No newline at end of file
+ sb-emulator-2:
diff --git a/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/configuration_specs.cs b/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/configuration_specs.cs
index 233d628f9..316113b9a 100644
--- a/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/configuration_specs.cs
+++ b/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/configuration_specs.cs
@@ -39,16 +39,16 @@ public async Task place_or_not_place_the_middleware_correctly()
// Not proud of this code
var handlers = (HandlerGraph)typeof(WolverineOptions)
- .GetProperty(nameof(HandlerGraph), BindingFlags.NonPublic | BindingFlags.Instance)
- .GetValue(wolverineOptions);
+ .GetProperty(nameof(HandlerGraph), BindingFlags.NonPublic | BindingFlags.Instance)!
+ .GetValue(wolverineOptions)!;
- handlers.ChainFor().Middleware.OfType()
+ handlers.ChainFor()!.Middleware.OfType()
.Any(x => x.HandlerType == typeof(DataAnnotationsValidationExecutor) &&
x.Method.Name == nameof(DataAnnotationsValidationExecutor.Validate))
.ShouldBeTrue();
-
+
// No validators here, but the middleware will always be applied
- handlers.ChainFor().Middleware.OfType()
+ handlers.ChainFor()!.Middleware.OfType()
.Any(x => x.HandlerType == typeof(DataAnnotationsValidationExecutor))
.ShouldBeTrue();
}
@@ -57,17 +57,17 @@ public async Task place_or_not_place_the_middleware_correctly()
public class Command1
{
[Required]
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
[Required]
- public string Color { get; set; }
+ public string Color { get; set; } = null!;
[Range(3, int.MaxValue)]
public int Number { get; set; }
}
public class Command2 : IValidatableObject
{
- public string Name { get; set; }
- public string Color { get; set; }
+ public string Name { get; set; } = null!;
+ public string Color { get; set; } = null!;
public IEnumerable Validate(ValidationContext validationContext)
{
diff --git a/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/end_to_end.cs b/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/end_to_end.cs
index 829abebad..0c5c1c8e3 100644
--- a/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/end_to_end.cs
+++ b/src/Extensions/Wolverine.DataAnnotationsValidation.Tests/end_to_end.cs
@@ -35,7 +35,7 @@ public async Task invoke_sad_path_with_multiple_validators()
var command = new Command1
{
- Name = null, Color = "blue", Number = 4
+ Name = null!, Color = "blue", Number = 4
};
await Should.ThrowAsync(() => host.InvokeAsync(command));
@@ -70,7 +70,7 @@ public async Task invoke_sad_path_with_single_validator()
var command = new Command2
{
- Name = null
+ Name = null!
};
await Should.ThrowAsync(() => host.InvokeAsync(command));
diff --git a/src/Extensions/Wolverine.FluentValidation.Tests/configuration_specs.cs b/src/Extensions/Wolverine.FluentValidation.Tests/configuration_specs.cs
index b495ae20f..b42bb4fd9 100644
--- a/src/Extensions/Wolverine.FluentValidation.Tests/configuration_specs.cs
+++ b/src/Extensions/Wolverine.FluentValidation.Tests/configuration_specs.cs
@@ -27,10 +27,10 @@ public async Task register_validators_in_application_assembly()
var container = host.Services.GetRequiredService();
// No args, this needs to be a singleton
- container.DefaultFor>()
+ container.DefaultFor>()!
.Lifetime.ShouldBe(ServiceLifetime.Singleton);
- container.DefaultFor>()
+ container.DefaultFor>()!
.Lifetime.ShouldBe(ServiceLifetime.Scoped);
}
@@ -65,21 +65,21 @@ public async Task place_or_not_place_the_middleware_correctly()
// Not proud of this code
var handlers = (HandlerGraph)typeof(WolverineOptions)
- .GetProperty(nameof(HandlerGraph), BindingFlags.NonPublic | BindingFlags.Instance)
- .GetValue(wolverineOptions);
+ .GetProperty(nameof(HandlerGraph), BindingFlags.NonPublic | BindingFlags.Instance)!
+ .GetValue(wolverineOptions)!;
- handlers.ChainFor().Middleware.OfType()
+ handlers.ChainFor()!.Middleware.OfType()
.Any(x => x.HandlerType == typeof(FluentValidationExecutor) &&
x.Method.Name == nameof(FluentValidationExecutor.ExecuteMany))
.ShouldBeTrue();
- handlers.ChainFor().Middleware.OfType()
+ handlers.ChainFor()!.Middleware.OfType()
.Any(x => x.HandlerType == typeof(FluentValidationExecutor) &&
x.Method.Name == nameof(FluentValidationExecutor.ExecuteOne))
.ShouldBeTrue();
// No validators here
- handlers.ChainFor().Middleware.OfType()
+ handlers.ChainFor()!.Middleware.OfType()
.Any(x => x.HandlerType == typeof(FluentValidationExecutor))
.ShouldBeFalse();
}
@@ -87,8 +87,8 @@ public async Task place_or_not_place_the_middleware_correctly()
public class Command1
{
- public string Name { get; set; }
- public string Color { get; set; }
+ public string Name { get; set; } = null!;
+ public string Color { get; set; } = null!;
public int Number { get; set; }
}
@@ -133,8 +133,8 @@ public async Task IsUniqueUsername(string userName)
public class Command2
{
- public string Name { get; set; }
- public string Color { get; set; }
+ public string Name { get; set; } = null!;
+ public string Color { get; set; } = null!;
}
public class FancyCommand2Validator : AbstractValidator
diff --git a/src/Extensions/Wolverine.FluentValidation.Tests/end_to_end.cs b/src/Extensions/Wolverine.FluentValidation.Tests/end_to_end.cs
index 71b54610a..ebba5c5ba 100644
--- a/src/Extensions/Wolverine.FluentValidation.Tests/end_to_end.cs
+++ b/src/Extensions/Wolverine.FluentValidation.Tests/end_to_end.cs
@@ -40,7 +40,7 @@ public async Task invoke_sad_path_with_multiple_validators()
var command = new Command1
{
- Name = null, Color = "blue", Number = 4
+ Name = null!, Color = "blue", Number = 4
};
await Should.ThrowAsync(() => host.InvokeAsync(command));
@@ -79,7 +79,7 @@ public async Task invoke_sad_path_with_single_validator()
var command = new Command2
{
- Name = null
+ Name = null!
};
await Should.ThrowAsync(() => host.InvokeAsync(command));
diff --git a/src/Extensions/Wolverine.FluentValidation/Internals/FluentValidationPolicy.cs b/src/Extensions/Wolverine.FluentValidation/Internals/FluentValidationPolicy.cs
index 1c4787cf5..731862d34 100644
--- a/src/Extensions/Wolverine.FluentValidation/Internals/FluentValidationPolicy.cs
+++ b/src/Extensions/Wolverine.FluentValidation/Internals/FluentValidationPolicy.cs
@@ -22,7 +22,7 @@ public void Apply(HandlerChain chain, IServiceContainer container)
var registered = container.RegistrationsFor(validatorInterface);
if (registered.Count() == 1)
{
- var method = typeof(FluentValidationExecutor).GetMethod(nameof(FluentValidationExecutor.ExecuteOne))
+ var method = typeof(FluentValidationExecutor).GetMethod(nameof(FluentValidationExecutor.ExecuteOne))!
.MakeGenericMethod(chain.MessageType);
var methodCall = new MethodCall(typeof(FluentValidationExecutor), method);
@@ -30,7 +30,7 @@ public void Apply(HandlerChain chain, IServiceContainer container)
}
else if (registered.Count() > 1)
{
- var method = typeof(FluentValidationExecutor).GetMethod(nameof(FluentValidationExecutor.ExecuteMany))
+ var method = typeof(FluentValidationExecutor).GetMethod(nameof(FluentValidationExecutor.ExecuteMany))!
.MakeGenericMethod(chain.MessageType);
var methodCall = new MethodCall(typeof(FluentValidationExecutor), method);
diff --git a/src/Extensions/Wolverine.FluentValidation/WolverineFluentValidationExtensions.cs b/src/Extensions/Wolverine.FluentValidation/WolverineFluentValidationExtensions.cs
index 60fcaceec..4ba198e34 100644
--- a/src/Extensions/Wolverine.FluentValidation/WolverineFluentValidationExtensions.cs
+++ b/src/Extensions/Wolverine.FluentValidation/WolverineFluentValidationExtensions.cs
@@ -49,7 +49,7 @@ public static WolverineOptions UseFluentValidation(this WolverineOptions options
{
using var provider = options.Services.BuildServiceProvider();
var jasperFxOptions = provider.GetService>();
- if (jasperFxOptions.Value != null)
+ if (jasperFxOptions?.Value != null)
{
options.ApplicationAssembly = jasperFxOptions.Value.ApplicationAssembly;
}
diff --git a/src/Extensions/Wolverine.MemoryPack.Tests/Messages.cs b/src/Extensions/Wolverine.MemoryPack.Tests/Messages.cs
index 00b00e35e..e35fd2f37 100644
--- a/src/Extensions/Wolverine.MemoryPack.Tests/Messages.cs
+++ b/src/Extensions/Wolverine.MemoryPack.Tests/Messages.cs
@@ -5,7 +5,7 @@ namespace Wolverine.MemoryPack.Tests;
[MemoryPackable]
public partial class MemoryPackMessage
{
- public string Name;
+ public string Name = null!;
}
// fake handler
diff --git a/src/Extensions/Wolverine.MemoryPack.Tests/end_to_end.cs b/src/Extensions/Wolverine.MemoryPack.Tests/end_to_end.cs
index dd35d1e0d..a24dee77e 100644
--- a/src/Extensions/Wolverine.MemoryPack.Tests/end_to_end.cs
+++ b/src/Extensions/Wolverine.MemoryPack.Tests/end_to_end.cs
@@ -10,8 +10,8 @@ namespace Wolverine.MemoryPack.Tests;
public class end_to_end : IAsyncLifetime
{
- private IHost _publishingHost;
- private IHost _receivingHost;
+ private IHost _publishingHost = null!;
+ private IHost _receivingHost = null!;
[Fact]
public async Task end_to_end_message_send_using_memorypack()
diff --git a/src/Extensions/Wolverine.MessagePack.Tests/Messages.cs b/src/Extensions/Wolverine.MessagePack.Tests/Messages.cs
index 535049923..0c3d48e11 100644
--- a/src/Extensions/Wolverine.MessagePack.Tests/Messages.cs
+++ b/src/Extensions/Wolverine.MessagePack.Tests/Messages.cs
@@ -6,13 +6,13 @@ namespace Wolverine.MessagePack.Tests;
public class MessagePackMessage
{
[Key(0)]
- public string Name;
+ public string Name = null!;
}
[MessagePackObject(keyAsPropertyName: true)]
public class MessagePackKeylessMessage
{
- public string Name;
+ public string Name = null!;
}
[MessagePackObject]
diff --git a/src/Extensions/Wolverine.MessagePack.Tests/end_to_end.cs b/src/Extensions/Wolverine.MessagePack.Tests/end_to_end.cs
index 12b26a530..a827e0798 100644
--- a/src/Extensions/Wolverine.MessagePack.Tests/end_to_end.cs
+++ b/src/Extensions/Wolverine.MessagePack.Tests/end_to_end.cs
@@ -11,8 +11,8 @@ namespace Wolverine.MessagePack.Tests;
public class end_to_end : IAsyncLifetime
{
- private IHost _publishingHost;
- private IHost _receivingHost;
+ private IHost _publishingHost = null!;
+ private IHost _receivingHost = null!;
[Fact]
public async Task end_to_end_message_send_using_messagepack()
diff --git a/src/Extensions/Wolverine.Protobuf.Tests/end_to_end.cs b/src/Extensions/Wolverine.Protobuf.Tests/end_to_end.cs
index 16d49ed80..3e2a5dc70 100644
--- a/src/Extensions/Wolverine.Protobuf.Tests/end_to_end.cs
+++ b/src/Extensions/Wolverine.Protobuf.Tests/end_to_end.cs
@@ -11,8 +11,8 @@ namespace Wolverine.Protobuf.Tests;
public class end_to_end : IAsyncLifetime
{
- private IHost _publishingHost;
- private IHost _receivingHost;
+ private IHost _publishingHost = null!;
+ private IHost _receivingHost = null!;
[Fact]
public async Task end_to_end_message_send_using_protobuf()
diff --git a/src/Extensions/Wolverine.Protobuf/Internal/ProtobufMessageSerializer.cs b/src/Extensions/Wolverine.Protobuf/Internal/ProtobufMessageSerializer.cs
index 574cfe637..a8b08e457 100644
--- a/src/Extensions/Wolverine.Protobuf/Internal/ProtobufMessageSerializer.cs
+++ b/src/Extensions/Wolverine.Protobuf/Internal/ProtobufMessageSerializer.cs
@@ -6,6 +6,8 @@ namespace Wolverine.Protobuf.Internal;
internal class ProtobufMessageSerializer(ProtobufSerializerOptions options) : IMessageSerializer
{
+ // ReSharper disable once NotAccessedField.Local
+ private readonly ProtobufSerializerOptions _options = options;
public string ContentType => "binary/protobuf";
public object ReadFromData(Type messageType, Envelope envelope)
diff --git a/src/Http/CrazyStartingWebApp/Program.cs b/src/Http/CrazyStartingWebApp/Program.cs
index 1c483ffe7..7073f717a 100644
--- a/src/Http/CrazyStartingWebApp/Program.cs
+++ b/src/Http/CrazyStartingWebApp/Program.cs
@@ -78,7 +78,7 @@ public Task StartAsync(CancellationToken cancellationToken)
{
hostApplicationLifetime.ApplicationStarted.Register((_, ct) =>
{
- StartClientInLoop(cancellationToken);
+ _ = StartClientInLoop(cancellationToken);
}, null);
return Task.CompletedTask;
}
@@ -88,7 +88,7 @@ private async Task StartClientInLoop(CancellationToken token)
await Task.Delay(2000, token);
var address = server.Features.Get()?.Addresses.First();
- var client = new Client(address);
+ var client = new Client(address!);
while (!token.IsCancellationRequested)
{
var success = await client.CallEndpointsConcurrently();
diff --git a/src/Http/OpenApiDemonstrator/Endpoints.cs b/src/Http/OpenApiDemonstrator/Endpoints.cs
index 8be918d14..fa28d62d2 100644
--- a/src/Http/OpenApiDemonstrator/Endpoints.cs
+++ b/src/Http/OpenApiDemonstrator/Endpoints.cs
@@ -46,6 +46,6 @@ public class Message1;
public class ResponseModel
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public int Age { get; set; }
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Marten/CompiledQueryWriterPolicy.cs b/src/Http/Wolverine.Http.Marten/CompiledQueryWriterPolicy.cs
index deab112d7..927438d12 100644
--- a/src/Http/Wolverine.Http.Marten/CompiledQueryWriterPolicy.cs
+++ b/src/Http/Wolverine.Http.Marten/CompiledQueryWriterPolicy.cs
@@ -37,7 +37,7 @@ public bool TryApply(HttpChain chain)
{
// This call runs the query
var queryCall =
- typeof(MartenQueryMethodCall<,>).CloseAndBuildAs(result, arguments);
+ typeof(MartenQueryMethodCall<,>).CloseAndBuildAs(result!, arguments);
chain.Postprocessors.Add(queryCall);
// This call writes the response directly to the HttpContext as a string
@@ -50,7 +50,7 @@ public bool TryApply(HttpChain chain)
{
var writeJsonCall =
- typeof(MartenWriteJsonToStreamMethodCall<,>).CloseAndBuildAs(result,
+ typeof(MartenWriteJsonToStreamMethodCall<,>).CloseAndBuildAs(result!,
(_responseType, _successStatusCode), arguments);
chain.Postprocessors.Add(writeJsonCall);
}
@@ -59,7 +59,7 @@ public bool TryApply(HttpChain chain)
}
}
-public class MartenQueryMethodCall : MethodCall
+public class MartenQueryMethodCall : MethodCall where TDoc : notnull
{
public MartenQueryMethodCall(Variable resultVariable) : base(typeof(IDocumentSession), FindMethod())
{
@@ -73,7 +73,7 @@ static MethodInfo FindMethod()
}
}
-public class MartenWriteJsonToStreamMethodCall : MethodCall
+public class MartenWriteJsonToStreamMethodCall : MethodCall where TDoc : notnull
{
public MartenWriteJsonToStreamMethodCall(Variable resultVariable, (string responseType, int successStatusCode) options) : base(typeof(QueryableExtensions), FindMethod(resultVariable))
{
diff --git a/src/Http/Wolverine.Http.Marten/WolverineTenantDetectedSessionFactory.cs b/src/Http/Wolverine.Http.Marten/WolverineTenantDetectedSessionFactory.cs
index 87ab94e4e..8d468c110 100644
--- a/src/Http/Wolverine.Http.Marten/WolverineTenantDetectedSessionFactory.cs
+++ b/src/Http/Wolverine.Http.Marten/WolverineTenantDetectedSessionFactory.cs
@@ -75,7 +75,7 @@ public override IQuerySession QuerySession()
var tenantId = _options.TryDetectTenantIdSynchronously(_contextAccessor.HttpContext);
- return _store.QuerySession(tenantId);
+ return _store.QuerySession(tenantId!);
}
public override SessionOptions BuildOptions()
@@ -83,7 +83,7 @@ public override SessionOptions BuildOptions()
var tenantId = _contextAccessor.HttpContext == null ? null : _options.TryDetectTenantIdSynchronously(_contextAccessor.HttpContext);
var options = new SessionOptions
{
- TenantId = tenantId,
+ TenantId = tenantId!,
Tracking = DocumentTracking.None
};
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_1295_aggregate_handler_should_not_try_to_use_query_string.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1295_aggregate_handler_should_not_try_to_use_query_string.cs
index 74ac3b5db..9db094915 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_1295_aggregate_handler_should_not_try_to_use_query_string.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1295_aggregate_handler_should_not_try_to_use_query_string.cs
@@ -87,7 +87,7 @@ public record TestInput(string Id);
public class TestAggregate
{
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
public void Apply(TestEvent _) => Debug.WriteLine("okay");
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_1941_do_not_try_to_parse_IPAddress.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1941_do_not_try_to_parse_IPAddress.cs
index ed11ee6d2..f91ab85ce 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_1941_do_not_try_to_parse_IPAddress.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_1941_do_not_try_to_parse_IPAddress.cs
@@ -62,7 +62,7 @@ public static (IResult, IPAddress?) LoadAsync(HttpContext httpContext)
public class IpRequest
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public int Age { get; set; }
}
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_505_required_attribute_not_working.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_505_required_attribute_not_working.cs
index 94599afeb..8ef85e9cb 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_505_required_attribute_not_working.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_505_required_attribute_not_working.cs
@@ -81,10 +81,10 @@ public Task LoadAsync(Guid breederId, string what, CancellationToken cance
{
if (Breeders.TryGetValue(breederId, out var breeder))
{
- return Task.FromResult(breeder as T);
+ return Task.FromResult((breeder as T)!);
}
- return Task.FromResult(null);
+ return Task.FromResult(null!);
}
}
@@ -99,7 +99,7 @@ public static async Task Before(ChangeVisionCommand c, ClaimsPrincipal
}
public static async Task LoadAsync(ChangeVisionCommand c, AggregateRepository r, CancellationToken ct)
- => await r.LoadAsync(c.BreederId, null, ct);
+ => await r.LoadAsync(c.BreederId, null!, ct);
[Tags("Breeder")]
[ProducesResponseType(204)]
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_582_erroneous_faliure_ack.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_582_erroneous_faliure_ack.cs
index 86b0811fd..bf2533ad8 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_582_erroneous_faliure_ack.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_582_erroneous_faliure_ack.cs
@@ -41,7 +41,7 @@ await host.Scenario(x =>
public class CreateItemCommand
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class ItemCreated
@@ -52,7 +52,7 @@ public class ItemCreated
public class ItemDocument
{
public Guid Id { get; set; }
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class ItemHandler
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_772_Saga_codegen.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_772_Saga_codegen.cs
index f0483e44d..3439d490a 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_772_Saga_codegen.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_772_Saga_codegen.cs
@@ -78,7 +78,7 @@ public Task GetData(Guid messageDataId)
public class RecordData
{
public Guid MessageDataId { get; set; }
- public string Data { get; set; }
+ public string Data { get; set; } = null!;
}
public record BeginProcess(Guid DataId);
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_970_starting_up_in_mediator_only_mode.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_970_starting_up_in_mediator_only_mode.cs
index ce43a9c73..0ffb22cf3 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_970_starting_up_in_mediator_only_mode.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_970_starting_up_in_mediator_only_mode.cs
@@ -74,16 +74,16 @@ public class ProjectOverview
{
public Guid UserId { get; set; }
public Guid Id { get; set; }
- public string Name { get; set; }
- public string Category { get; set; }
+ public string Name { get; set; } = null!;
+ public string Category { get; set; } = null!;
}
public class Project
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
- public string Name { get; set; }
- public string Category { get; set; }
+ public string Name { get; set; } = null!;
+ public string Category { get; set; } = null!;
}
public class GetProjectsHandler(IQuerySession session)
diff --git a/src/Http/Wolverine.Http.Tests/Bugs/Bug_using_fromquery_with_aggregatehandler.cs b/src/Http/Wolverine.Http.Tests/Bugs/Bug_using_fromquery_with_aggregatehandler.cs
index 2629ee760..730c08e60 100644
--- a/src/Http/Wolverine.Http.Tests/Bugs/Bug_using_fromquery_with_aggregatehandler.cs
+++ b/src/Http/Wolverine.Http.Tests/Bugs/Bug_using_fromquery_with_aggregatehandler.cs
@@ -28,7 +28,7 @@ public record FromQueryAggregateHandlerEvent(Guid Id, string Something);
public class FromQueryAggregateHandlerAggregate
{
public Guid Id { get; set; }
- public string Something{get;set;}
+ public string Something{get;set;} = null!;
public void Apply(FromQueryAggregateHandlerEvent e){
this.Id = e.Id;
diff --git a/src/Http/Wolverine.Http.Tests/CodeGeneration/service_location_assertions.cs b/src/Http/Wolverine.Http.Tests/CodeGeneration/service_location_assertions.cs
index 5fc2b8bf2..401863a15 100644
--- a/src/Http/Wolverine.Http.Tests/CodeGeneration/service_location_assertions.cs
+++ b/src/Http/Wolverine.Http.Tests/CodeGeneration/service_location_assertions.cs
@@ -26,7 +26,7 @@ public class service_location_assertions
{
public readonly ServiceDescriptor descriptor1 = new ServiceDescriptor(typeof(IWidget), typeof(AWidget));
public readonly ServiceDescriptor descripter2 = new ServiceDescriptor(typeof(IWidget), "B", typeof(BWidget));
- public readonly HttpChain theChain = new HttpChain(MethodCall.For(x => x.Post(null, null, null, null)), new HttpGraph(new WolverineOptions(), Substitute.For()));
+ public readonly HttpChain theChain = new HttpChain(MethodCall.For(x => x.Post(null!, null!, null!, null!)), new HttpGraph(new WolverineOptions(), Substitute.For()));
public readonly RecordingLogger theLogger = new();
private IServiceProvider servicesWithPolicy(ServiceLocationPolicy policy)
@@ -290,7 +290,7 @@ public string Post(WidgetRequest request, IWidget widget, IThing thing, HttpCont
context.RequestServices.GetRequiredService().ShouldBeSameAs(thing);
- return widget.ToString();
+ return widget.ToString()!;
}
}
@@ -371,7 +371,7 @@ public interface IUserContext
public class UserContext : IUserContext
{
- public string UserId { get; set; }
+ public string UserId { get; set; } = null!;
}
public class UserContextFactory
diff --git a/src/Http/Wolverine.Http.Tests/Marten/document_attribute_usage.cs b/src/Http/Wolverine.Http.Tests/Marten/document_attribute_usage.cs
index 5bbd73933..205941cb3 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/document_attribute_usage.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/document_attribute_usage.cs
@@ -68,7 +68,7 @@ await Host.Scenario(x =>
});
var loaded = await session.LoadAsync(invoice.Id);
- loaded.Paid.ShouldBeTrue();
+ loaded!.Paid.ShouldBeTrue();
}
[Fact]
@@ -86,6 +86,6 @@ await Host.Scenario(x =>
});
var loaded = await session.LoadAsync(invoice.Id);
- loaded.Approved.ShouldBeTrue();
+ loaded!.Approved.ShouldBeTrue();
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/Marten/multi_tenanted_session_factory_without_wolverine.cs b/src/Http/Wolverine.Http.Tests/Marten/multi_tenanted_session_factory_without_wolverine.cs
index b6d59553f..8ea37f0e3 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/multi_tenanted_session_factory_without_wolverine.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/multi_tenanted_session_factory_without_wolverine.cs
@@ -69,12 +69,12 @@ public async Task can_do_the_tenancy_detection()
}
var blueDoc = await host.GetAsJson("/color?tenant=blue");
- blueDoc.Number.ShouldBe(1);
-
+ blueDoc!.Number.ShouldBe(1);
+
var greenDoc = await host.GetAsJson("/color?tenant=green");
- greenDoc.Number.ShouldBe(2);
+ greenDoc!.Number.ShouldBe(2);
}
-
+
[Fact]
public async Task can_do_the_tenancy_detection_with_custom_metadata()
{
@@ -101,7 +101,7 @@ public async Task can_do_the_tenancy_detection_with_custom_metadata()
});
#endregion
-
+
// This is using Alba, which uses WebApplicationFactory under the covers
await using var host = await AlbaHost.For(builder, app =>
{
@@ -121,7 +121,7 @@ public async Task can_do_the_tenancy_detection_with_custom_metadata()
await session.SaveChangesAsync();
}
-
+
// Store the green doc
using (var session = store.LightweightSession("green"))
{
@@ -135,15 +135,15 @@ public async Task can_do_the_tenancy_detection_with_custom_metadata()
}
var blueDoc = await host.GetAsJson("/color?tenant=blue");
- blueDoc.Number.ShouldBe(1);
-
+ blueDoc!.Number.ShouldBe(1);
+
var greenDoc = await host.GetAsJson("/color?tenant=green");
- greenDoc.Number.ShouldBe(2);
+ greenDoc!.Number.ShouldBe(2);
}
}
public class ColorDoc
{
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
public int Number { get; set; }
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/Marten/reacting_to_read_aggregate.cs b/src/Http/Wolverine.Http.Tests/Marten/reacting_to_read_aggregate.cs
index 61134de4e..8e91e0a34 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/reacting_to_read_aggregate.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/reacting_to_read_aggregate.cs
@@ -13,7 +13,7 @@ namespace Wolverine.Http.Tests.Marten;
public class reacting_to_read_aggregate : IAsyncLifetime
{
- private IAlbaHost theHost;
+ private IAlbaHost theHost = null!;
public async Task InitializeAsync()
{
diff --git a/src/Http/Wolverine.Http.Tests/Marten/strong_typed_identifiers.cs b/src/Http/Wolverine.Http.Tests/Marten/strong_typed_identifiers.cs
index e869c4755..738795f7e 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/strong_typed_identifiers.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/strong_typed_identifiers.cs
@@ -79,11 +79,11 @@ await Scenario(x =>
});
var aggregate1 = await session.Events.FetchLatest(stream1Id);
- aggregate1.BCount.ShouldBe(2);
-
+ aggregate1!.BCount.ShouldBe(2);
+
var aggregate2 = await session.Events.FetchLatest(stream2Id);
- aggregate2.BCount.ShouldBe(3);
-
+ aggregate2!.BCount.ShouldBe(3);
+
}
[Fact]
@@ -94,7 +94,7 @@ public async Task batch_query_with_both_read_and_write_aggregate()
using var session = Host.DocumentStore().LightweightSession();
session.Events.StartStream(stream1Id, new AEvent(), new BEvent(), new CEvent(),
new CEvent());
-
+
session.Events.StartStream(stream2Id, new AEvent(), new BEvent(), new BEvent(),
new AEvent(), new DEvent());
await session.SaveChangesAsync();
@@ -107,12 +107,12 @@ await Host.Scenario(x =>
});
var aggregate1 = await session.Events.FetchLatest(stream1Id);
- aggregate1.BCount.ShouldBe(3);
+ aggregate1!.BCount.ShouldBe(3);
aggregate1.ACount.ShouldBe(3);
aggregate1.DCount.ShouldBe(1);
-
+
var aggregate2 = await session.Events.FetchLatest(stream2Id);
- aggregate2.BCount.ShouldBe(2);
+ aggregate2!.BCount.ShouldBe(2);
}
[Fact]
diff --git a/src/Http/Wolverine.Http.Tests/Marten/using_read_aggregate_attribute.cs b/src/Http/Wolverine.Http.Tests/Marten/using_read_aggregate_attribute.cs
index b593d48bf..1df253ffe 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/using_read_aggregate_attribute.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/using_read_aggregate_attribute.cs
@@ -20,9 +20,9 @@ await Scenario(x =>
});
var result = await Host.GetAsJson("/orders/latest/" + id);
- result.Items.Keys.ShouldContain("Socks");
+ result!.Items.Keys.ShouldContain("Socks");
}
-
+
[Fact]
public async Task happy_path_reading_aggregate_and_version_in_url()
{
@@ -35,7 +35,7 @@ await Scenario(x =>
});
var result = await Host.GetAsJson("/orders/V1.0/latest/" + id);
- result.Items.Keys.ShouldContain("Socks");
+ result!.Items.Keys.ShouldContain("Socks");
}
[Fact]
@@ -60,6 +60,6 @@ await Scenario(x =>
});
var result = await Host.GetAsJson("/orders/latest/from-query?id=" + id);
- result.Items.Keys.ShouldContain("Socks");
+ result!.Items.Keys.ShouldContain("Socks");
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/Marten/working_against_multiple_streams.cs b/src/Http/Wolverine.Http.Tests/Marten/working_against_multiple_streams.cs
index fea37486a..892e2c1c1 100644
--- a/src/Http/Wolverine.Http.Tests/Marten/working_against_multiple_streams.cs
+++ b/src/Http/Wolverine.Http.Tests/Marten/working_against_multiple_streams.cs
@@ -24,7 +24,7 @@ private async Task fetchAmount(Guid id)
{
using var session = Host.DocumentStore().LightweightSession();
var account = await session.Events.FetchLatest(id);
- return account.Amount;
+ return account!.Amount;
}
[Fact]
diff --git a/src/Http/Wolverine.Http.Tests/MultiTenancy/multi_tenancy_detection_and_integration.cs b/src/Http/Wolverine.Http.Tests/MultiTenancy/multi_tenancy_detection_and_integration.cs
index 168223844..9778ebce5 100644
--- a/src/Http/Wolverine.Http.Tests/MultiTenancy/multi_tenancy_detection_and_integration.cs
+++ b/src/Http/Wolverine.Http.Tests/MultiTenancy/multi_tenancy_detection_and_integration.cs
@@ -27,7 +27,7 @@ namespace Wolverine.Http.Tests.MultiTenancy;
public class multi_tenancy_detection_and_integration : IAsyncDisposable, IDisposable
{
private readonly ITestOutputHelper _output;
- private IAlbaHost theHost;
+ private IAlbaHost theHost = null!;
public multi_tenancy_detection_and_integration(ITestOutputHelper output)
{
@@ -90,7 +90,7 @@ protected async Task configure(Action configure)
app.MapWolverineEndpoints(configure);
}, securityStub);
- var graph = theHost.Services.GetRequiredService().Endpoints;
+ var graph = theHost.Services.GetRequiredService().Endpoints!;
foreach (var chain in graph.Chains.OrderBy(x => x.Description))
{
_output.WriteLine(chain.Description);
@@ -374,10 +374,10 @@ await configure(opts =>
- var chain = theHost.Services.GetRequiredService().Endpoints
+ var chain = theHost.Services.GetRequiredService().Endpoints!
.ChainFor("POST", "/tenant/{tenant}/formdata");
-
- chain.IsFormData.ShouldBeTrue();
+
+ chain!.IsFormData.ShouldBeTrue();
var formData = new Dictionary { { "value", "blue" } };
var result = await theHost.Scenario(x =>
@@ -415,7 +415,7 @@ public static class TenantedEndpoints
public static string GetTenantIdFromRoute(IMessageBus bus, TenantId tenantId)
{
tenantId.Value.ShouldBe(bus.TenantId);
- return bus.TenantId;
+ return bus.TenantId!;
}
[Authorize]
@@ -423,10 +423,10 @@ public static string GetTenantIdFromRoute(IMessageBus bus, TenantId tenantId)
public static string GetTenantIdFromWhatever(IMessageBus bus, HttpContext httpContext, TenantId tenantId)
{
// IHttpActivityFeature.Activity is set to null after the request, so to access the
- // Activity in the test we capture the Activity into a custom Feature
+ // Activity in the test we capture the Activity into a custom Feature
httpContext.Features.Set(CustomActivityFeature.FromHttpContext(httpContext));
tenantId.Value.ShouldBe(bus.TenantId);
- return bus.TenantId;
+ return bus.TenantId!;
}
[WolverineGet("/todo/{id}")]
@@ -451,21 +451,21 @@ public static IMartenOp Create(CreateTodo command, TenantId tenantId)
public static string GetTenantWithArgs1(IMessageBus bus, TenantId tenantId)
{
tenantId.Value.ShouldBe(bus.TenantId);
- return bus.TenantId;
+ return bus.TenantId!;
}
[WolverineGet("/tenant/context/{tenant}")]
public static string GetTenantWithArgs1(IMessageContext context, TenantId tenantId)
{
tenantId.Value.ShouldBe(context.TenantId);
- return context.TenantId;
+ return context.TenantId!;
}
[WolverineGet("/tenant/both/{tenant}")]
public static string GetTenantWithArgs1(IMessageContext context, IMessageBus bus, TenantId tenantId)
{
bus.TenantId.ShouldBe(context.TenantId);
- return context.TenantId;
+ return context.TenantId!;
}
// in this combination, TenantId needs the [FromServices] attribute, otherwise codegen tries to
@@ -512,9 +512,9 @@ public record CreateTodo(string Id, string Description);
public class TenantTodo : ITenanted
{
- public string Id { get; set; }
- public string Description { get; set; }
- public string TenantId { get; set; }
+ public string Id { get; set; } = null!;
+ public string Description { get; set; } = null!;
+ public string? TenantId { get; set; }
}
// Custom HttpContext Feature used to capture the Activity
diff --git a/src/Http/Wolverine.Http.Tests/Persistence/global_entity_defaults_http.cs b/src/Http/Wolverine.Http.Tests/Persistence/global_entity_defaults_http.cs
index 7d1655ad8..e4e46ccbb 100644
--- a/src/Http/Wolverine.Http.Tests/Persistence/global_entity_defaults_http.cs
+++ b/src/Http/Wolverine.Http.Tests/Persistence/global_entity_defaults_http.cs
@@ -12,7 +12,7 @@ namespace Wolverine.Http.Tests.Persistence;
public class global_entity_defaults_http : IAsyncLifetime
{
- private IAlbaHost theHost;
+ private IAlbaHost theHost = null!;
public async Task InitializeAsync()
{
diff --git a/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_entity_attributes.cs b/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_entity_attributes.cs
index a2d0f4ad9..4293e6216 100644
--- a/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_entity_attributes.cs
+++ b/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_entity_attributes.cs
@@ -16,7 +16,7 @@ namespace Wolverine.Http.Tests.Persistence;
public class reacting_to_entity_attributes : IAsyncLifetime
{
private readonly ITestOutputHelper _output;
- private IAlbaHost theHost;
+ private IAlbaHost theHost = null!;
public reacting_to_entity_attributes(ITestOutputHelper output)
{
@@ -106,9 +106,9 @@ public async Task throw_exception_on_missing()
});
var text = tracked.ReadAsText();
- text.ShouldContain(typeof(RequiredDataMissingException).FullName);
+ text.ShouldContain(typeof(RequiredDataMissingException).FullName!);
}
-
+
[Fact]
public async Task problem_details_400_on_missing_with_custom_message()
{
@@ -147,7 +147,7 @@ public async Task throw_exception_on_missing_with_custom_message()
});
var text = tracked.ReadAsText();
- text.ShouldContain(typeof(RequiredDataMissingException).FullName);
+ text.ShouldContain(typeof(RequiredDataMissingException).FullName!);
text.ShouldContain("Id 'nonexistent' is wrong!");
}
diff --git a/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_required_attribute.cs b/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_required_attribute.cs
index bc14e3913..29567edf8 100644
--- a/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_required_attribute.cs
+++ b/src/Http/Wolverine.Http.Tests/Persistence/reacting_to_required_attribute.cs
@@ -13,7 +13,7 @@
public class reacting_to_required_attribute : IAsyncLifetime
{
private readonly ITestOutputHelper _output;
- private IAlbaHost theHost;
+ private IAlbaHost theHost = null!;
public reacting_to_required_attribute(ITestOutputHelper output)
{
diff --git a/src/Http/Wolverine.Http.Tests/Samples/ExternalHttpServer.cs b/src/Http/Wolverine.Http.Tests/Samples/ExternalHttpServer.cs
index b415312ac..8efa4c9ec 100644
--- a/src/Http/Wolverine.Http.Tests/Samples/ExternalHttpServer.cs
+++ b/src/Http/Wolverine.Http.Tests/Samples/ExternalHttpServer.cs
@@ -62,7 +62,7 @@ public TestCommand1 Handle(TestCommand command)
public record TestCommand1(string message);
-public class TestCommand1Handler(IMessageContext messageBus)
+public class TestCommand1Handler
{
public void Handle(TestCommand1 command)
{
diff --git a/src/Http/Wolverine.Http.Tests/Samples/MultiTenancy.cs b/src/Http/Wolverine.Http.Tests/Samples/MultiTenancy.cs
index 161c61b39..0ce91c8ca 100644
--- a/src/Http/Wolverine.Http.Tests/Samples/MultiTenancy.cs
+++ b/src/Http/Wolverine.Http.Tests/Samples/MultiTenancy.cs
@@ -19,7 +19,7 @@ public static async Task bootstrap(params string[] args)
var connectionString = builder.Configuration.GetConnectionString("postgres");
builder.Services
- .AddMarten(connectionString)
+ .AddMarten(connectionString!)
.IntegrateWithWolverine();
builder.Host.UseWolverine(opts =>
diff --git a/src/Http/Wolverine.Http.Tests/Transport/CloudEventsHttpTransportTests.cs b/src/Http/Wolverine.Http.Tests/Transport/CloudEventsHttpTransportTests.cs
index 35f464841..d01622262 100644
--- a/src/Http/Wolverine.Http.Tests/Transport/CloudEventsHttpTransportTests.cs
+++ b/src/Http/Wolverine.Http.Tests/Transport/CloudEventsHttpTransportTests.cs
@@ -51,7 +51,7 @@ public async Task send_envelope_as_cloud_event()
_handler.LastRequest.ShouldNotBeNull();
_handler.LastRequest.Method.ShouldBe(HttpMethod.Post);
- _handler.LastRequest.Content.Headers.ContentType.MediaType.ShouldBe(HttpTransport.CloudEventsContentType);
+ _handler.LastRequest.Content!.Headers.ContentType!.MediaType.ShouldBe(HttpTransport.CloudEventsContentType);
// Verify the body contains a CloudEvents formatted JSON
var content = Encoding.UTF8.GetString(_handler.LastContent);
@@ -120,7 +120,7 @@ public async Task send_batch_with_cloud_events_uses_envelope_batch_content_type(
_handler.LastRequest.ShouldNotBeNull();
// Note: CloudEvents client uses EnvelopeBatchContentType for batches
- _handler.LastRequest.Content.Headers.ContentType.MediaType.ShouldBe(HttpTransport.EnvelopeBatchContentType);
+ _handler.LastRequest.Content!.Headers.ContentType!.MediaType.ShouldBe(HttpTransport.EnvelopeBatchContentType);
}
[Fact]
@@ -143,13 +143,13 @@ public async Task cloud_events_with_null_options_uses_default()
await _client.SendAsync(uri, envelope, null);
_handler.LastRequest.ShouldNotBeNull();
- _handler.LastRequest.Content.Headers.ContentType.MediaType.ShouldBe(HttpTransport.CloudEventsContentType);
+ _handler.LastRequest.Content!.Headers.ContentType!.MediaType.ShouldBe(HttpTransport.CloudEventsContentType);
}
}
public class TestMessage
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class CloudEventsTestCommand
diff --git a/src/Http/Wolverine.Http.Tests/Transport/HttpEndpointTests.cs b/src/Http/Wolverine.Http.Tests/Transport/HttpEndpointTests.cs
index e36fb0076..1188c08c2 100644
--- a/src/Http/Wolverine.Http.Tests/Transport/HttpEndpointTests.cs
+++ b/src/Http/Wolverine.Http.Tests/Transport/HttpEndpointTests.cs
@@ -25,13 +25,13 @@ public HttpEndpointTests()
private ISender InvokeCreateSender(IWolverineRuntime runtime)
{
var method = typeof(HttpEndpoint).GetMethod("CreateSender", BindingFlags.Instance | BindingFlags.NonPublic);
- return (ISender)method.Invoke(_endpoint, new object[] { runtime });
+ return (ISender)method!.Invoke(_endpoint, new object[] { runtime })!;
}
private bool InvokeSupportsMode(EndpointMode mode)
{
var method = typeof(HttpEndpoint).GetMethod("supportsMode", BindingFlags.Instance | BindingFlags.NonPublic);
- return (bool)method.Invoke(_endpoint, new object[] { mode });
+ return (bool)method!.Invoke(_endpoint, new object[] { mode })!;
}
[Fact]
diff --git a/src/Http/Wolverine.Http.Tests/Transport/WolverineHttpTransportClientTests.cs b/src/Http/Wolverine.Http.Tests/Transport/WolverineHttpTransportClientTests.cs
index 0bed64f1e..dc4a377a9 100644
--- a/src/Http/Wolverine.Http.Tests/Transport/WolverineHttpTransportClientTests.cs
+++ b/src/Http/Wolverine.Http.Tests/Transport/WolverineHttpTransportClientTests.cs
@@ -42,8 +42,8 @@ public async Task send_envelope_async()
_handler.LastRequest.ShouldNotBeNull();
_handler.LastRequest.Method.ShouldBe(HttpMethod.Post);
- _handler.LastRequest.RequestUri.ToString().ShouldBe(uri);
- _handler.LastRequest.Content.Headers.ContentType.MediaType.ShouldBe(HttpTransport.EnvelopeContentType);
+ _handler.LastRequest.RequestUri!.ToString().ShouldBe(uri);
+ _handler.LastRequest.Content!.Headers.ContentType!.MediaType.ShouldBe(HttpTransport.EnvelopeContentType);
var expectedData = EnvelopeSerializer.Serialize(envelope);
_handler.LastContent.ShouldBe(expectedData);
@@ -68,8 +68,8 @@ public async Task send_batch_async()
_handler.LastRequest.ShouldNotBeNull();
_handler.LastRequest.Method.ShouldBe(HttpMethod.Post);
- _handler.LastRequest.RequestUri.ToString().ShouldBe("https://target-url/");
- _handler.LastRequest.Content.Headers.ContentType.MediaType.ShouldBe(HttpTransport.EnvelopeBatchContentType);
+ _handler.LastRequest.RequestUri!.ToString().ShouldBe("https://target-url/");
+ _handler.LastRequest.Content!.Headers.ContentType!.MediaType.ShouldBe(HttpTransport.EnvelopeBatchContentType);
var expectedData = EnvelopeSerializer.Serialize(envelopes);
_handler.LastContent.ShouldBe(expectedData);
@@ -78,8 +78,8 @@ public async Task send_batch_async()
public class MockHttpMessageHandler : HttpMessageHandler
{
- public HttpRequestMessage LastRequest { get; private set; }
- public byte[] LastContent { get; private set; }
+ public HttpRequestMessage LastRequest { get; private set; } = null!;
+ public byte[] LastContent { get; private set; } = null!;
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
diff --git a/src/Http/Wolverine.Http.Tests/asparameters_binding.cs b/src/Http/Wolverine.Http.Tests/asparameters_binding.cs
index 78667cf6e..eb7218254 100644
--- a/src/Http/Wolverine.Http.Tests/asparameters_binding.cs
+++ b/src/Http/Wolverine.Http.Tests/asparameters_binding.cs
@@ -137,8 +137,8 @@ public async Task post_body_services_and_route_arguments()
// First check this for OpenAPI generation
var options = Host.Services.GetRequiredService();
- var chain = options.Endpoints.ChainFor("POST", "/asp2/{id}/{number}");
- chain.RequestType.ShouldBe(typeof(AsParameterBody));
+ var chain = options.Endpoints!.ChainFor("POST", "/asp2/{id}/{number}");
+ chain!.RequestType.ShouldBe(typeof(AsParameterBody));
response.Body.Name.ShouldBe("Jeremy");
response.Body.Direction.ShouldBe(Direction.East);
diff --git a/src/Http/Wolverine.Http.Tests/dataannotations_validation_middleware.cs b/src/Http/Wolverine.Http.Tests/dataannotations_validation_middleware.cs
index d878bd9e5..69d59f36a 100644
--- a/src/Http/Wolverine.Http.Tests/dataannotations_validation_middleware.cs
+++ b/src/Http/Wolverine.Http.Tests/dataannotations_validation_middleware.cs
@@ -45,7 +45,7 @@ public async Task one_validator_happy_path()
[Fact]
public async Task one_validator_sad_path()
{
- var createCustomer = new CreateAccount(null, "123");
+ var createCustomer = new CreateAccount(null!, "123");
var results = await Host.Scenario(x =>
{
diff --git a/src/Http/Wolverine.Http.Tests/endpoint_adds_requesttype_audit_tags_to_activity.cs b/src/Http/Wolverine.Http.Tests/endpoint_adds_requesttype_audit_tags_to_activity.cs
index 79094ae48..b4b616273 100644
--- a/src/Http/Wolverine.Http.Tests/endpoint_adds_requesttype_audit_tags_to_activity.cs
+++ b/src/Http/Wolverine.Http.Tests/endpoint_adds_requesttype_audit_tags_to_activity.cs
@@ -14,7 +14,7 @@ public void finds_audit_members_from_attributes()
{
var chain = HttpChains.ChainFor("POST", "/auditable/empty");
- chain.AuditedMembers.Single()
+ chain!.AuditedMembers.Single()
.MemberName.ShouldBe(nameof(AuditablePostBody.Id));
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/endpoint_discovery_and_construction.cs b/src/Http/Wolverine.Http.Tests/endpoint_discovery_and_construction.cs
index a5398a594..ca6e5b1c8 100644
--- a/src/Http/Wolverine.Http.Tests/endpoint_discovery_and_construction.cs
+++ b/src/Http/Wolverine.Http.Tests/endpoint_discovery_and_construction.cs
@@ -40,14 +40,14 @@ public void discover_csharp_static_bool_endpoint()
public void read_order_from_attribute()
{
var chain = HttpChains.ChainFor("GET", "/fake/hello");
- chain.Endpoint.Order.ShouldBe(55);
+ chain!.Endpoint!.Order.ShouldBe(55);
}
[Fact]
public void read_display_name_from_http_method_attribute()
{
var chain = HttpChains.ChainFor("GET", "/fake/hello");
- chain.Endpoint.DisplayName.ShouldBe("The Hello Route!");
+ chain!.Endpoint!.DisplayName.ShouldBe("The Hello Route!");
}
[Fact]
@@ -55,7 +55,7 @@ public void ability_to_discern_cascaded_messages_in_tuple_return_values()
{
var chain = HttpChains.ChainFor("POST", "/spawn");
- chain.InputType().ShouldBe(typeof(SpawnInput));
+ chain!.InputType().ShouldBe(typeof(SpawnInput));
chain.ResourceType.ShouldBe(typeof(string));
}
diff --git a/src/Http/Wolverine.Http.Tests/fluent_validation_middleware.cs b/src/Http/Wolverine.Http.Tests/fluent_validation_middleware.cs
index b3d33d2e1..d9c982477 100644
--- a/src/Http/Wolverine.Http.Tests/fluent_validation_middleware.cs
+++ b/src/Http/Wolverine.Http.Tests/fluent_validation_middleware.cs
@@ -45,7 +45,7 @@ public async Task one_validator_happy_path()
[Fact]
public async Task one_validator_sad_path()
{
- var createCustomer = new CreateCustomer(null, "Humphrey", "11111");
+ var createCustomer = new CreateCustomer(null!, "Humphrey", "11111");
var results = await Scenario(x =>
{
@@ -58,7 +58,7 @@ public async Task one_validator_sad_path()
// in the request
var problems = results.ReadAsJson();
}
-
+
[Fact]
public async Task one_validator_happy_path_on_complex_query_string_argument()
{
@@ -76,7 +76,7 @@ public async Task one_validator_happy_path_on_complex_query_string_argument()
[Fact]
public async Task one_validator_sad_path_on_complex_query_string_argument()
{
- var createCustomer = new CreateCustomer(null, "Humphrey", "11111");
+ var createCustomer = new CreateCustomer(null!, "Humphrey", "11111");
var results = await Scenario(x =>
{
@@ -96,7 +96,7 @@ public async Task one_validator_sad_path_on_complex_query_string_argument()
[Fact]
public async Task one_validator_sad_path_in_different_assembly()
{
- var createCustomer = new CreateCustomer2(null, "Humphrey", "11111");
+ var createCustomer = new CreateCustomer2(null!, "Humphrey", "11111");
var results = await Scenario(x =>
{
diff --git a/src/Http/Wolverine.Http.Tests/from_form_binding.cs b/src/Http/Wolverine.Http.Tests/from_form_binding.cs
index 9e804b4c1..80d7bea66 100644
--- a/src/Http/Wolverine.Http.Tests/from_form_binding.cs
+++ b/src/Http/Wolverine.Http.Tests/from_form_binding.cs
@@ -94,15 +94,15 @@ public async Task nullable_number_on_setter()
public async Task nullable_bool_on_setter()
{
(await forForm([new("name", "Jones"), new("number", "95")])).NullableFlag.ShouldBeNull();
- (await forForm([new("name", "Jones"), new("number", "95"), new("nullableFlag", "true")])).NullableFlag.Value.ShouldBeTrue();
- (await forForm([new("name", "Jones"), new("number", "95"), new("NullableFlag", "false")])).NullableFlag.Value.ShouldBeFalse();
+ (await forForm([new("name", "Jones"), new("number", "95"), new("nullableFlag", "true")])).NullableFlag!.Value.ShouldBeTrue();
+ (await forForm([new("name", "Jones"), new("number", "95"), new("NullableFlag", "false")])).NullableFlag!.Value.ShouldBeFalse();
}
[Fact]
public async Task nullable_enum_on_setter()
{
(await forForm([new("name", "Jones"), new("number", "95")])).NullableDirection.ShouldBeNull();
- (await forForm([new("name", "Jones"), new("number", "95"), new("nullableDirection", "east")])).NullableDirection.Value.ShouldBe(Direction.East);
+ (await forForm([new("name", "Jones"), new("number", "95"), new("nullableDirection", "east")])).NullableDirection!.Value.ShouldBe(Direction.East);
}
[Fact(Skip = "Alba doesnt support multiple values in form data")]
diff --git a/src/Http/Wolverine.Http.Tests/from_query_binding.cs b/src/Http/Wolverine.Http.Tests/from_query_binding.cs
index ec1d34dd0..53b592a2e 100644
--- a/src/Http/Wolverine.Http.Tests/from_query_binding.cs
+++ b/src/Http/Wolverine.Http.Tests/from_query_binding.cs
@@ -83,15 +83,15 @@ public async Task nullable_number_on_setter()
public async Task nullable_bool_on_setter()
{
(await forQuerystring("name=Jones&number=95")).NullableFlag.ShouldBeNull();
- (await forQuerystring("name=Jones&number=95&nullableFlag=true")).NullableFlag.Value.ShouldBeTrue();
- (await forQuerystring("name=Jones&number=95&NullableFlag=false")).NullableFlag.Value.ShouldBeFalse();
+ (await forQuerystring("name=Jones&number=95&nullableFlag=true")).NullableFlag!.Value.ShouldBeTrue();
+ (await forQuerystring("name=Jones&number=95&NullableFlag=false")).NullableFlag!.Value.ShouldBeFalse();
}
[Fact]
public async Task nullable_enum_on_setter()
{
(await forQuerystring("name=Jones&number=95")).NullableDirection.ShouldBeNull();
- (await forQuerystring("name=Jones&number=95&nullableDirection=east")).NullableDirection.Value.ShouldBe(Direction.East);
+ (await forQuerystring("name=Jones&number=95&nullableDirection=east")).NullableDirection!.Value.ShouldBe(Direction.East);
}
[Fact]
diff --git a/src/Http/Wolverine.Http.Tests/initializing_endpoints_from_method_call.cs b/src/Http/Wolverine.Http.Tests/initializing_endpoints_from_method_call.cs
index f0ab280a4..648d0ad6f 100644
--- a/src/Http/Wolverine.Http.Tests/initializing_endpoints_from_method_call.cs
+++ b/src/Http/Wolverine.Http.Tests/initializing_endpoints_from_method_call.cs
@@ -38,7 +38,7 @@ public void build_pattern_using_http_pattern_with_attribute()
{
var endpoint = HttpChain.ChainFor(x => x.SayHello());
- endpoint.RoutePattern.RawText.ShouldBe("/fake/hello");
+ endpoint!.RoutePattern!.RawText.ShouldBe("/fake/hello");
endpoint.RoutePattern.Parameters.Any().ShouldBeFalse();
}
@@ -92,11 +92,11 @@ public void capturing_metadata_for_resource_type()
metadata.Length.ShouldBeGreaterThanOrEqualTo(2);
var responseBody = metadata.FirstOrDefault(x => x.StatusCode == 200);
- responseBody.Type.ShouldBe(typeof(ArithmeticResults));
+ responseBody!.Type.ShouldBe(typeof(ArithmeticResults));
responseBody.ContentTypes.Single().ShouldBe("application/json");
var noValue = metadata.FirstOrDefault(x => x.StatusCode == 404);
- noValue.ContentTypes.Any().ShouldBeFalse();
+ noValue!.ContentTypes.Any().ShouldBeFalse();
noValue.Type.ShouldBe(typeof(void));
}
@@ -147,28 +147,28 @@ public void pick_up_metadata_from_attribute_on_method()
[Fact]
public void must_use_outbox_when_using_message_bus()
{
- var chain = HttpChain.ChainFor(x => x.Yes(null, null));
+ var chain = HttpChain.ChainFor(x => x.Yes(null!, null!));
chain.RequiresOutbox().ShouldBeTrue();
}
[Fact]
public void does_not_use_outbox_when_not_using_message_bus()
{
- var chain = HttpChain.ChainFor(x => x.No(null));
+ var chain = HttpChain.ChainFor(x => x.No(null!));
chain.RequiresOutbox().ShouldBeFalse();
}
[Fact]
public void default_tenancy_is_null()
{
- var chain = HttpChain.ChainFor(x => x.No(null));
+ var chain = HttpChain.ChainFor(x => x.No(null!));
chain.TenancyMode.ShouldBeNull();
}
[Fact]
public void add_from_route_metadata()
{
- var chain = HttpChain.ChainFor(x => x.Get(null));
+ var chain = HttpChain.ChainFor(x => x.Get(null!));
}
}
diff --git a/src/Http/Wolverine.Http.Tests/open_api_generation.cs b/src/Http/Wolverine.Http.Tests/open_api_generation.cs
index 63d175d97..645cb74a1 100644
--- a/src/Http/Wolverine.Http.Tests/open_api_generation.cs
+++ b/src/Http/Wolverine.Http.Tests/open_api_generation.cs
@@ -39,7 +39,7 @@ public void verify_open_api_expectations(HttpChain chain)
{
var opType = Enum.Parse(chain.HttpMethods.Single(), true);
- var (item, op) = FindOpenApiDocument(opType, chain.RoutePattern.RawText);
+ var (item, op) = FindOpenApiDocument(opType, chain.RoutePattern!.RawText!);
item.ShouldNotBeNull();
op.ShouldNotBeNull();
diff --git a/src/Http/Wolverine.Http.Tests/routename_applies_routenamemetadata_to_route.cs b/src/Http/Wolverine.Http.Tests/routename_applies_routenamemetadata_to_route.cs
index 4b1599383..53f70170a 100644
--- a/src/Http/Wolverine.Http.Tests/routename_applies_routenamemetadata_to_route.cs
+++ b/src/Http/Wolverine.Http.Tests/routename_applies_routenamemetadata_to_route.cs
@@ -13,6 +13,6 @@ public routename_applies_routenamemetadata_to_route(AppFixture fixture) : base(f
public void routename_applies_routenamemetadata()
{
var chain = HttpChains.ChainFor("POST", "/named/route");
- chain.Endpoint.Metadata.Any(m => m is RouteNameMetadata { RouteName: "NamedRoute"}).ShouldBeTrue();
+ chain!.Endpoint!.Metadata.Any(m => m is RouteNameMetadata { RouteName: "NamedRoute"}).ShouldBeTrue();
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/swashbuckle_integration.cs b/src/Http/Wolverine.Http.Tests/swashbuckle_integration.cs
index eb0621b3d..0ceedbb80 100644
--- a/src/Http/Wolverine.Http.Tests/swashbuckle_integration.cs
+++ b/src/Http/Wolverine.Http.Tests/swashbuckle_integration.cs
@@ -27,7 +27,7 @@ public async Task wolverine_stuff_is_in_the_document()
[Fact]
public void ignore_endpoint_methods_that_are_marked_with_ExcludeFromDescription()
{
- HttpChains.Chains.Any(x => x.RoutePattern.RawText == "/ignore").ShouldBeTrue();
+ HttpChains.Chains.Any(x => x.RoutePattern!.RawText == "/ignore").ShouldBeTrue();
var generator = Host.Services.GetRequiredService();
var doc = generator.GetSwagger("v1");
diff --git a/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs b/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs
index 7c7df0e76..93c2f30b8 100644
--- a/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs
+++ b/src/Http/Wolverine.Http.Tests/todo_endpoint_specs.cs
@@ -31,7 +31,7 @@ await Scenario(opts =>
});
var changes = await session.LoadAsync(todo.Id);
- changes.IsComplete.ShouldBeTrue();
+ changes!.IsComplete.ShouldBeTrue();
changes.Name.ShouldBe("Second");
}
@@ -49,7 +49,7 @@ await Scenario(opts =>
});
var changes = await session.LoadAsync(todo.Id);
- changes.IsComplete.ShouldBeTrue();
+ changes!.IsComplete.ShouldBeTrue();
changes.Name.ShouldBe("Second");
}
diff --git a/src/Http/Wolverine.Http.Tests/using_create_response_and_metadata_derived_from_response_type.cs b/src/Http/Wolverine.Http.Tests/using_create_response_and_metadata_derived_from_response_type.cs
index 67a8d56f2..554d3441c 100644
--- a/src/Http/Wolverine.Http.Tests/using_create_response_and_metadata_derived_from_response_type.cs
+++ b/src/Http/Wolverine.Http.Tests/using_create_response_and_metadata_derived_from_response_type.cs
@@ -13,7 +13,7 @@ public using_create_response_and_metadata_derived_from_response_type(AppFixture
[Fact]
public void read_metadata_from_IEndpointMetadataProvider()
{
- var chain = HttpChain.ChainFor(x => x.Create(null));
+ var chain = HttpChain.ChainFor(x => x.Create(null!));
var endpoint = chain.BuildEndpoint(RouteWarmup.Lazy);
diff --git a/src/Http/Wolverine.Http.Tests/using_form_parameters.cs b/src/Http/Wolverine.Http.Tests/using_form_parameters.cs
index ff2d4c550..2aa4989dc 100644
--- a/src/Http/Wolverine.Http.Tests/using_form_parameters.cs
+++ b/src/Http/Wolverine.Http.Tests/using_form_parameters.cs
@@ -535,6 +535,6 @@ public void trouble_shoot_form_matching()
var parameter = method.Method.GetParameters().Single();
var variable = chain.TryFindOrCreateFormValue(parameter);
- variable.Creator.ShouldBeOfType();
+ variable!.Creator.ShouldBeOfType();
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/using_marten.cs b/src/Http/Wolverine.Http.Tests/using_marten.cs
index a32ed0d7a..e2ed47ec7 100644
--- a/src/Http/Wolverine.Http.Tests/using_marten.cs
+++ b/src/Http/Wolverine.Http.Tests/using_marten.cs
@@ -23,7 +23,7 @@ public async Task use_marten_document_session_without_outbox()
var result = await Host.GetAsJson($"/data/{data.Id}");
- result.Name.ShouldBe("foo");
+ result!.Name.ShouldBe("foo");
}
[Fact]
diff --git a/src/Http/Wolverine.Http.Tests/using_policies_and_attributes_to_customize_handling.cs b/src/Http/Wolverine.Http.Tests/using_policies_and_attributes_to_customize_handling.cs
index c7a76f39d..fd3942739 100644
--- a/src/Http/Wolverine.Http.Tests/using_policies_and_attributes_to_customize_handling.cs
+++ b/src/Http/Wolverine.Http.Tests/using_policies_and_attributes_to_customize_handling.cs
@@ -35,9 +35,9 @@ public void attribute_usage_on_handler_level()
endpoints.Any().ShouldBeTrue();
var testEndpoints = endpoints.Select(x => x.Metadata.GetMetadata())
- .Where(x => x != null).Where(x => x.Method.HandlerType == typeof(TestEndpoints));
+ .Where(x => x != null).Where(x => x!.Method.HandlerType == typeof(TestEndpoints));
- foreach (var endpoint in testEndpoints) endpoint.Middleware.OfType().Any().ShouldBeTrue();
+ foreach (var endpoint in testEndpoints) endpoint!.Middleware.OfType().Any().ShouldBeTrue();
}
[Fact]
@@ -49,8 +49,8 @@ public void attribute_usage_on_a_single_method()
endpoints.Any().ShouldBeTrue();
var endpoint = endpoints.Select(x => x.Metadata.GetMetadata())
- .Where(x => x != null).Single(x => x.RoutePattern.RawText == "/data/{id}");
+ .Where(x => x != null).Single(x => x!.RoutePattern!.RawText == "/data/{id}");
- endpoint.Middleware.OfType().Any().ShouldBeTrue();
+ endpoint!.Middleware.OfType().Any().ShouldBeTrue();
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/using_querystring_parameters.cs b/src/Http/Wolverine.Http.Tests/using_querystring_parameters.cs
index 4599ed881..a489c377b 100644
--- a/src/Http/Wolverine.Http.Tests/using_querystring_parameters.cs
+++ b/src/Http/Wolverine.Http.Tests/using_querystring_parameters.cs
@@ -497,6 +497,6 @@ public void trouble_shoot_querystring_matching()
var parameter = method.Method.GetParameters().Single();
var variable = chain.TryFindOrCreateQuerystringValue(parameter);
- variable.Creator.ShouldBeOfType();
+ variable!.Creator.ShouldBeOfType();
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs b/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs
index 489ee9bec..524c731d1 100644
--- a/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs
+++ b/src/Http/Wolverine.Http.Tests/using_storage_actions_and_entity_attribute.cs
@@ -38,10 +38,10 @@ await Host.Scenario(x =>
});
var todo = await Load(command.Id);
-
- todo.Name.ShouldBe("Write docs");
+
+ todo!.Name.ShouldBe("Write docs");
}
-
+
[Fact]
public async Task use_store_as_return_value()
{
@@ -53,8 +53,8 @@ await Host.Scenario(x =>
});
var todo = await Load(command.Id);
-
- todo.Name.ShouldBe("Write docs");
+
+ todo!.Name.ShouldBe("Write docs");
}
[Fact]
@@ -70,9 +70,9 @@ await Host.Scenario(x =>
});
var todo = await Load(command.Id);
- todo.Name.ShouldBe("New name");
+ todo!.Name.ShouldBe("New name");
}
-
+
[Fact]
public async Task use_entity_attribute_with_entity_id()
{
@@ -86,9 +86,9 @@ await Host.Scenario(x =>
});
var todo = await Load(command.Id);
- todo.Name.ShouldBe("New name2");
+ todo!.Name.ShouldBe("New name2");
}
-
+
[Fact]
public async Task use_entity_attribute_with_explicit_id()
{
@@ -100,9 +100,9 @@ await Host.Scenario(x =>
x.Post.Json(new RenameTodo3(command.Id, "New name3")).ToUrl("/api/todo/update3");
x.StatusCodeShouldBe(204);
});
-
+
var todo = await Load(command.Id);
- todo.Name.ShouldBe("New name3");
+ todo!.Name.ShouldBe("New name3");
}
[Fact]
@@ -123,7 +123,7 @@ await Host.Scenario(x =>
x.StatusCodeShouldBe(204);
});
- (await Load(shouldInsert.Id)).Name.ShouldBe("Pick up milk");
+ (await Load(shouldInsert.Id))!.Name.ShouldBe("Pick up milk");
(await Load(shouldDoNothing.Id)).ShouldBeNull();
}
@@ -170,7 +170,7 @@ await Host.Scenario(x =>
x.StatusCodeShouldBe(204);
});
- (await Load(todoId)).IsComplete.ShouldBeTrue();
+ (await Load(todoId))!.IsComplete.ShouldBeTrue();
}
[Fact]
@@ -194,7 +194,7 @@ await Host.Scenario(x =>
x.StatusCodeShouldBe(204);
});
- (await Load(todoId)).IsComplete.ShouldBeTrue();
+ (await Load(todoId))!.IsComplete.ShouldBeTrue();
}
[Fact]
@@ -211,7 +211,7 @@ await Host.Scenario(x =>
x.StatusCodeShouldBe(204);
});
- (await Load(todoId)).IsComplete.ShouldBeTrue();
+ (await Load(todoId))!.IsComplete.ShouldBeTrue();
}
[Fact]
diff --git a/src/Http/Wolverine.Http/CodeGen/AsParametersBindingFrame.cs b/src/Http/Wolverine.Http/CodeGen/AsParametersBindingFrame.cs
index 0568ea492..65ab8b895 100644
--- a/src/Http/Wolverine.Http/CodeGen/AsParametersBindingFrame.cs
+++ b/src/Http/Wolverine.Http/CodeGen/AsParametersBindingFrame.cs
@@ -92,8 +92,8 @@ public AsParametersBindingFrame(Type queryType, HttpChain chain, IServiceContain
{
if (tryCreateFrame(parameter, chain, container, out var variable))
{
- _parameters.Add(variable);
- if (variable.Creator != null)
+ _parameters.Add(variable!);
+ if (variable!.Creator != null)
{
_parameterFrames.Add(variable.Creator);
}
@@ -111,8 +111,8 @@ public AsParametersBindingFrame(Type queryType, HttpChain chain, IServiceContain
}
else
{
- _props.Add(new AssignPropertyFrame(Variable, propertyInfo, variable));
- _dependencies.Add(variable);
+ _props.Add(new AssignPropertyFrame(Variable, propertyInfo, variable!));
+ _dependencies.Add(variable!);
}
}
}
@@ -135,7 +135,7 @@ private bool tryCreateFrame(ParameterInfo parameter, HttpChain chain, IServiceCo
{
_hasForms = true;
var formName = fatt.Name ?? memberName;
- variable = chain.TryFindOrCreateFormValue(memberType, memberName, formName);
+ variable = chain.TryFindOrCreateFormValue(memberType, memberName!, formName);
return true;
}
@@ -143,7 +143,7 @@ private bool tryCreateFrame(ParameterInfo parameter, HttpChain chain, IServiceCo
{
var queryStringName = qatt.Name ?? memberName;
variable =
- chain.TryFindOrCreateQuerystringValue(memberType, queryStringName);
+ chain.TryFindOrCreateQuerystringValue(memberType, queryStringName!);
return true;
}
@@ -151,7 +151,7 @@ private bool tryCreateFrame(ParameterInfo parameter, HttpChain chain, IServiceCo
if (parameter.TryGetAttribute(out var ratt))
{
var routeArgumentName = ratt.Name ?? memberName;
- if (chain.FindRouteVariable(memberType, routeArgumentName, out variable))
+ if (chain.FindRouteVariable(memberType, routeArgumentName!, out variable))
{
return true;
}
@@ -191,12 +191,12 @@ private bool tryCreateFrame(PropertyInfo propertyInfo, HttpChain chain, IService
var memberType = propertyInfo.PropertyType;
var memberName = propertyInfo.Name;
-
+
if (propertyInfo.TryGetAttribute(out var fatt))
{
_hasForms = true;
var formName = fatt.Name ?? memberName;
- variable = chain.TryFindOrCreateFormValue(memberType, memberName, formName);
+ variable = chain.TryFindOrCreateFormValue(memberType, memberName!, formName);
return true;
}
@@ -204,7 +204,7 @@ private bool tryCreateFrame(PropertyInfo propertyInfo, HttpChain chain, IService
{
var queryStringName = qatt.Name ?? memberName;
variable =
- chain.TryFindOrCreateQuerystringValue(memberType, queryStringName);
+ chain.TryFindOrCreateQuerystringValue(memberType, queryStringName!);
return true;
}
@@ -212,7 +212,7 @@ private bool tryCreateFrame(PropertyInfo propertyInfo, HttpChain chain, IService
if (propertyInfo.TryGetAttribute(out var ratt))
{
var routeArgumentName = ratt.Name ?? memberName;
- if (chain.FindRouteVariable(memberType, routeArgumentName, out variable))
+ if (chain.FindRouteVariable(memberType, routeArgumentName!, out variable))
{
return true;
}
diff --git a/src/Http/Wolverine.Http/CodeGen/FormBindingFrame.cs b/src/Http/Wolverine.Http/CodeGen/FormBindingFrame.cs
index ab5f85246..89cfbb3f9 100644
--- a/src/Http/Wolverine.Http/CodeGen/FormBindingFrame.cs
+++ b/src/Http/Wolverine.Http/CodeGen/FormBindingFrame.cs
@@ -97,7 +97,7 @@ public FormBindingFrame(Type queryType, HttpChain chain){
}
var formValueVariable = chain.TryFindOrCreateFormValue(parameter);
- _parameters.Add(formValueVariable);
+ _parameters.Add(formValueVariable!);
}
if (!_constructor.GetParameters().Any())
diff --git a/src/Http/Wolverine.Http/CodeGen/FormHandling.cs b/src/Http/Wolverine.Http/CodeGen/FormHandling.cs
index 91e41d5e9..95fd0de71 100644
--- a/src/Http/Wolverine.Http/CodeGen/FormHandling.cs
+++ b/src/Http/Wolverine.Http/CodeGen/FormHandling.cs
@@ -104,7 +104,7 @@ public void AssignToProperty(string usage)
internal class ParsedArrayFormValue : SyncFrame, IReadHttpFrame
{
- private string _property;
+ private string? _property;
public ParsedArrayFormValue(Type parameterType, string parameterName)
{
@@ -137,14 +137,14 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
}
else
{
- var collectionAlias = typeof(List<>).MakeGenericType(elementType).FullNameInCode();
- var elementAlias = elementType.FullNameInCode();
+ var collectionAlias = typeof(List<>).MakeGenericType(elementType!).FullNameInCode();
+ var elementAlias = elementType!.FullNameInCode();
writer.Write($"var {Variable.Usage}_List = new {collectionAlias}();");
writer.Write($"BLOCK:foreach (var {Variable.Usage}Value in httpContext.Request.Form[\"{Variable.Usage}\"])");
- if (elementType.IsEnum)
+ if (elementType!.IsEnum)
{
writer.Write($"BLOCK:if ({elementAlias}.TryParse<{elementAlias}>({Variable.Usage}Value, out var {Variable.Usage}ValueParsed))");
}
diff --git a/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs b/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs
index bd94c4be8..53b5c917f 100644
--- a/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs
+++ b/src/Http/Wolverine.Http/CodeGen/IReadHttpFrame.cs
@@ -171,7 +171,7 @@ private void writeParsedValue(ISourceWriter writer, GeneratedMethod method)
}
- private string _property;
+ private string? _property;
private readonly bool _isOptional;
private readonly bool _isNullable;
private readonly Type _rawType;
diff --git a/src/Http/Wolverine.Http/CodeGen/JsonHandling.cs b/src/Http/Wolverine.Http/CodeGen/JsonHandling.cs
index c8ec8ce3b..18e0640fc 100644
--- a/src/Http/Wolverine.Http/CodeGen/JsonHandling.cs
+++ b/src/Http/Wolverine.Http/CodeGen/JsonHandling.cs
@@ -46,7 +46,7 @@ internal class ReadJsonBodyWithNewtonsoft : MethodCall
{
private static MethodInfo findMethodForType(Type parameterType)
{
- return typeof(NewtonsoftHttpSerialization).GetMethod(nameof(NewtonsoftHttpSerialization.ReadFromJsonAsync))
+ return typeof(NewtonsoftHttpSerialization).GetMethod(nameof(NewtonsoftHttpSerialization.ReadFromJsonAsync))!
.MakeGenericMethod(parameterType);
}
@@ -127,15 +127,15 @@ public bool TryBuildVariable(HttpChain chain, out Variable variable)
{
// It *could* be used twice, so let's watch out for this!
chain.RequestBodyVariable ??= Usage == JsonUsage.SystemTextJson
- ? new ReadJsonBody(chain.RequestType).Variable
- : new ReadJsonBodyWithNewtonsoft(chain.RequestType).ReturnVariable!;
+ ? new ReadJsonBody(chain.RequestType!).Variable
+ : new ReadJsonBodyWithNewtonsoft(chain.RequestType!).ReturnVariable!;
variable = chain.RequestBodyVariable;
return true;
}
- variable = default;
+ variable = default!;
return false;
}
}
\ No newline at end of file
diff --git a/src/Http/Wolverine.Http/CodeGen/ParsedArrayQueryStringValue.cs b/src/Http/Wolverine.Http/CodeGen/ParsedArrayQueryStringValue.cs
index 9e61797bd..dc3ed912d 100644
--- a/src/Http/Wolverine.Http/CodeGen/ParsedArrayQueryStringValue.cs
+++ b/src/Http/Wolverine.Http/CodeGen/ParsedArrayQueryStringValue.cs
@@ -7,7 +7,7 @@ namespace Wolverine.Http.CodeGen;
internal class ParsedArrayQueryStringValue : SyncFrame, IReadHttpFrame
{
- private string _property;
+ private string? _property;
public ParsedArrayQueryStringValue(Type parameterType, string parameterName)
{
@@ -40,14 +40,14 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
}
else
{
- var collectionAlias = typeof(List<>).MakeGenericType(elementType).FullNameInCode();
- var elementAlias = elementType.FullNameInCode();
+ var collectionAlias = typeof(List<>).MakeGenericType(elementType!).FullNameInCode();
+ var elementAlias = elementType!.FullNameInCode();
writer.Write($"var {Variable.Usage}_List = new {collectionAlias}();");
writer.Write($"BLOCK:foreach (var {Variable.Usage}Value in httpContext.Request.Query[\"{Variable.Usage}\"])");
- if (elementType.IsEnum)
+ if (elementType!.IsEnum)
{
writer.Write($"BLOCK:if ({elementAlias}.TryParse<{elementAlias}>({Variable.Usage}Value, out var {Variable.Usage}ValueParsed))");
}
diff --git a/src/Http/Wolverine.Http/CodeGen/ProblemDetailsContinuationPolicy.cs b/src/Http/Wolverine.Http/CodeGen/ProblemDetailsContinuationPolicy.cs
index 64d5ad587..c4e360085 100644
--- a/src/Http/Wolverine.Http/CodeGen/ProblemDetailsContinuationPolicy.cs
+++ b/src/Http/Wolverine.Http/CodeGen/ProblemDetailsContinuationPolicy.cs
@@ -136,7 +136,7 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
{
writer.WriteComment("Evaluate whether the processing should stop if there are any problems");
writer.Write($"BLOCK:if (!(ReferenceEquals({Details.Usage}, {typeof(WolverineContinue).FullNameInCode()}.{nameof(WolverineContinue.NoProblems)})))");
- writer.Write($"{typeof(ProblemDetailsContinuationPolicy).FullNameInCode()}.{nameof(ProblemDetailsContinuationPolicy.WriteProblems)}({_logger.Usage}, {Details.Usage});");
+ writer.Write($"{typeof(ProblemDetailsContinuationPolicy).FullNameInCode()}.{nameof(ProblemDetailsContinuationPolicy.WriteProblems)}({_logger!.Usage}, {Details.Usage});");
writer.Write("return;");
writer.FinishBlock();
writer.BlankLine();
diff --git a/src/Http/Wolverine.Http/CodeGen/QueryStringBindingFrame.cs b/src/Http/Wolverine.Http/CodeGen/QueryStringBindingFrame.cs
index de3f2180e..c5f60eb2f 100644
--- a/src/Http/Wolverine.Http/CodeGen/QueryStringBindingFrame.cs
+++ b/src/Http/Wolverine.Http/CodeGen/QueryStringBindingFrame.cs
@@ -55,7 +55,7 @@ public QueryStringBindingFrame(Type queryType, HttpChain chain)
foreach (var parameter in _constructor.GetParameters())
{
var queryStringVariable = chain.TryFindOrCreateQuerystringValue(parameter);
- _parameters.Add(queryStringVariable);
+ _parameters.Add(queryStringVariable!);
}
// Here's the limitation, either it's all ctor args, or all settable props
@@ -70,9 +70,9 @@ public QueryStringBindingFrame(Type queryType, HttpChain chain)
}
var queryStringVariable =
- chain.TryFindOrCreateQuerystringValue(propertyInfo.PropertyType, queryStringName);
+ chain.TryFindOrCreateQuerystringValue(propertyInfo.PropertyType, queryStringName!);
- if (queryStringVariable.Creator is IReadHttpFrame frame)
+ if (queryStringVariable?.Creator is IReadHttpFrame frame)
{
frame.AssignToProperty($"{Variable.Usage}.{propertyInfo.Name}");
_props.Add(frame);
diff --git a/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs b/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs
index 3c46a910a..4ddd8a3d7 100644
--- a/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs
+++ b/src/Http/Wolverine.Http/CodeGen/RouteHandling.cs
@@ -73,7 +73,7 @@ public static void TryApplyRouteVariables(HttpChain chain, MethodCall call)
var parameter = call.Method.GetParameters()[i];
if (parameter.ParameterType == typeof(string) || CanParse(parameter.ParameterType))
{
- if (chain.FindRouteVariable(parameter.ParameterType, parameter.Name, out var variable))
+ if (chain.FindRouteVariable(parameter.ParameterType, parameter.Name!, out var variable))
{
call.Arguments[i] = variable;
}
diff --git a/src/Http/Wolverine.Http/DeadLettersEndpointExtensions.cs b/src/Http/Wolverine.Http/DeadLettersEndpointExtensions.cs
index b9ee91966..e60c2c139 100644
--- a/src/Http/Wolverine.Http/DeadLettersEndpointExtensions.cs
+++ b/src/Http/Wolverine.Http/DeadLettersEndpointExtensions.cs
@@ -10,7 +10,7 @@ namespace Wolverine.Http;
public class DeadLetterEnvelopeIdsRequest
{
- public Guid[] Ids { get; set; }
+ public Guid[] Ids { get; set; } = [];
public string? TenantId { get; set; }
}
diff --git a/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs b/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs
index 0d1b3ba00..8f200adfe 100644
--- a/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs
+++ b/src/Http/Wolverine.Http/HttpChain.ApiDescription.cs
@@ -62,12 +62,12 @@ public ApiDescription CreateApiDescription(string httpMethod)
var apiDescription = new ApiDescription
{
HttpMethod = httpMethod,
- GroupName = Endpoint.Metadata.GetMetadata()?.EndpointGroupName,
- RelativePath = Endpoint.RoutePattern.RawText?.TrimStart('/'),
+ GroupName = Endpoint!.Metadata.GetMetadata()?.EndpointGroupName,
+ RelativePath = Endpoint!.RoutePattern.RawText?.TrimStart('/'),
ActionDescriptor = new WolverineActionDescriptor(this)
};
- foreach (var routeParameter in RoutePattern.Parameters)
+ foreach (var routeParameter in RoutePattern!.Parameters)
{
var parameter = buildParameterDescription(routeParameter);
@@ -88,12 +88,12 @@ public ApiDescription CreateApiDescription(string httpMethod)
{
var parameterDescription = new ApiParameterDescription
{
- Name = parameter.Name,
+ Name = parameter.Name!,
ModelMetadata = new EndpointModelMetadata(parameter.ParameterType),
Source = BindingSource.FormFile,
ParameterDescriptor = new ParameterDescriptor
{
- Name = parameter.Name,
+ Name = parameter.Name!,
ParameterType = parameter.ParameterType
},
Type = parameter.ParameterType,
@@ -107,12 +107,12 @@ public ApiDescription CreateApiDescription(string httpMethod)
{
var parameterDescription = new ApiParameterDescription
{
- Name = formMetadata.Name,
+ Name = formMetadata.Name!,
ModelMetadata = new EndpointModelMetadata(typeof(IFormFile)),
Source = BindingSource.Form,
ParameterDescriptor = new ParameterDescriptor
{
- Name = formMetadata.Name,
+ Name = formMetadata.Name!,
ParameterType = typeof(IFormFile)
},
Type = typeof(IFormFile),
@@ -141,22 +141,22 @@ public override void UseForResponse(MethodCall methodCall)
public override bool TryFindVariable(string valueName, ValueSource source, Type valueType, out Variable variable)
{
- if ((source == ValueSource.RouteValue || source == ValueSource.Anything) && FindRouteVariable(valueType, valueName, out variable))
+ if ((source == ValueSource.RouteValue || source == ValueSource.Anything) && FindRouteVariable(valueType, valueName, out variable!))
{
return true;
}
-
- if ((source == ValueSource.FromQueryString || source == ValueSource.Anything) && FindQuerystringVariable(valueType, valueName, out variable))
+
+ if ((source == ValueSource.FromQueryString || source == ValueSource.Anything) && FindQuerystringVariable(valueType, valueName, out variable!))
{
return true;
}
if (HasRequestType)
{
- var requestType = InputType();
+ var requestType = InputType()!;
var member = requestType.GetProperties()
.FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.PropertyType == valueType)
- ?? (MemberInfo)requestType.GetFields()
+ ?? (MemberInfo?)requestType.GetFields()
.FirstOrDefault(x => x.Name.EqualsIgnoreCase(valueName) && x.FieldType == valueType);
if (member != null)
@@ -241,7 +241,7 @@ private void fillRequestType(ApiDescription apiDescription)
apiDescription.ParameterDescriptions.Add(parameterDescription);
- foreach (var metadata in Endpoint.Metadata.OfType())
+ foreach (var metadata in Endpoint!.Metadata.OfType())
{
foreach (var contentType in metadata.ContentTypes)
{
diff --git a/src/Http/Wolverine.Http/HttpChain.Codegen.cs b/src/Http/Wolverine.Http/HttpChain.Codegen.cs
index f888ce05f..68c1fa0be 100644
--- a/src/Http/Wolverine.Http/HttpChain.Codegen.cs
+++ b/src/Http/Wolverine.Http/HttpChain.Codegen.cs
@@ -115,8 +115,8 @@ internal IEnumerable DetermineFrames(GenerationRules rules)
{
if (AuditedMembers.All(x => x.Member != identity))
{
- Audit(identity);
- }
+ Audit(identity!);
+ }
}
if (AuditedMembers.Count != 0)
@@ -186,7 +186,7 @@ private bool requiresFlush(Frame[] actionsOnOtherReturnValues)
private string determineFileName()
{
- var parts = RoutePattern.RawText.Replace("{", "").Replace("*", "").Replace(".", "_").Replace("?", "").Replace("}", "").Split('/').Select(x => x.Split(':').First());
+ var parts = RoutePattern!.RawText!.Replace("{", "").Replace("*", "").Replace(".", "_").Replace("?", "").Replace("}", "").Split('/').Select(x => x.Split(':').First());
char[] invalidPathChars = Path.GetInvalidPathChars();
var fileName = _httpMethods.Select(x => x.ToUpper()).Concat(parts).Join("_").Replace('-', '_').Replace("__", "_");
diff --git a/src/Http/Wolverine.Http/HttpChain.cs b/src/Http/Wolverine.Http/HttpChain.cs
index 51edd5229..8f8d27183 100644
--- a/src/Http/Wolverine.Http/HttpChain.cs
+++ b/src/Http/Wolverine.Http/HttpChain.cs
@@ -331,13 +331,13 @@ public override Frame[] AddStopConditionIfNull(Variable data, Variable? identity
case OnMissing.ProblemDetailsWith400:
Metadata.Produces(400, contentType: "application/problem+json");
- return [new WriteProblemDetailsIfNull(data, identity, message, 400)];
+ return [new WriteProblemDetailsIfNull(data, identity!, message, 400)];
case OnMissing.ProblemDetailsWith404:
Metadata.Produces(404, contentType: "application/problem+json");
- return [new WriteProblemDetailsIfNull(data, identity, message, 404)];
-
+ return [new WriteProblemDetailsIfNull(data, identity!, message, 404)];
+
default:
- return [new ThrowRequiredDataMissingExceptionFrame(data, identity, message)];
+ return [new ThrowRequiredDataMissingExceptionFrame(data, identity!, message)];
}
}
@@ -351,7 +351,7 @@ public OptionsDescription ToDescription()
var description = new OptionsDescription(this);
description.AddValue(nameof(HttpMethods), HttpMethods.ToArray());
- description.AddValue("Route", RoutePattern.RawText);
+ description.AddValue("Route", RoutePattern?.RawText ?? string.Empty);
if (Tags.Any())
{
@@ -420,7 +420,7 @@ private void applyMetadata()
key = att.Name;
}
- return TryFindOrCreateFormValue(parameterType, parameterName, key);
+ return TryFindOrCreateFormValue(parameterType, parameterName!, key);
}
public HttpElementVariable? TryFindOrCreateFormValue(Type parameterType, string parameterName, string? key = null){
@@ -452,7 +452,7 @@ private void applyMetadata()
}
}
- if (parameterType.IsArray && RouteParameterStrategy.CanParse(parameterType.GetElementType()))
+ if (parameterType.IsArray && RouteParameterStrategy.CanParse(parameterType.GetElementType()!))
{
variable = new ParsedArrayFormValue(parameterType, parameterName).Variable;
variable.Name = key;
@@ -510,7 +510,7 @@ public bool FindQuerystringVariable(Type variableType, string routeOrParameterNa
key = att.Name;
}
- return TryFindOrCreateQuerystringValue(parameterType, parameterName, key);
+ return TryFindOrCreateQuerystringValue(parameterType, parameterName!, key);
}
public HttpElementVariable? TryFindOrCreateQuerystringValue(Type parameterType, string parameterName, string? key = null)
@@ -551,7 +551,7 @@ public bool FindQuerystringVariable(Type variableType, string routeOrParameterNa
}
}
- if (parameterType.IsArray && RouteParameterStrategy.CanParse(parameterType.GetElementType()))
+ if (parameterType.IsArray && RouteParameterStrategy.CanParse(parameterType.GetElementType()!))
{
variable = new ParsedArrayQueryStringValue(parameterType, key).Variable;
variable.Name = key;
@@ -585,7 +585,7 @@ public bool FindQuerystringVariable(Type variableType, string routeOrParameterNa
public bool FindRouteVariable(ParameterInfo parameter, [NotNullWhen(true)]out Variable? variable)
{
var existing = _routeVariables.FirstOrDefault(x =>
- x.VariableType == parameter.ParameterType && x.Usage.EqualsIgnoreCase(parameter.Name));
+ x.VariableType == parameter.ParameterType && x.Usage.EqualsIgnoreCase(parameter.Name!));
if (existing is not null)
{
@@ -610,7 +610,7 @@ public bool FindRouteVariable(ParameterInfo parameter, [NotNullWhen(true)]out Va
var inner = parameter.ParameterType.GetInnerTypeFromNullable();
if (RouteParameterStrategy.CanParse(inner))
{
- variable = new ReadHttpFrame(BindingSource.RouteValue, parameter.ParameterType, parameter.Name, isOptional).Variable;
+ variable = new ReadHttpFrame(BindingSource.RouteValue, parameter.ParameterType, parameter.Name!, isOptional).Variable;
_routeVariables.Add(variable);
return true;
}
@@ -618,7 +618,7 @@ public bool FindRouteVariable(ParameterInfo parameter, [NotNullWhen(true)]out Va
if (RouteParameterStrategy.CanParse(parameter.ParameterType))
{
- variable = new ReadHttpFrame(BindingSource.RouteValue, parameter.ParameterType, parameter.Name, isOptional).Variable;
+ variable = new ReadHttpFrame(BindingSource.RouteValue, parameter.ParameterType, parameter.Name!, isOptional).Variable;
_routeVariables.Add(variable);
return true;
}
@@ -668,9 +668,9 @@ public HttpElementVariable GetOrCreateHeaderVariable(IFromHeaderMetadata metadat
if (existing != null) return existing;
- var frame = new ReadHttpFrame(BindingSource.Header, parameter.ParameterType, parameter.Name)
+ var frame = new ReadHttpFrame(BindingSource.Header, parameter.ParameterType, parameter.Name!)
{
- Key = metadata.Name ?? parameter.Name
+ Key = metadata.Name ?? parameter.Name!
};
_headerVariables.Add(frame.Variable);
diff --git a/src/Http/Wolverine.Http/HttpGraph.cs b/src/Http/Wolverine.Http/HttpGraph.cs
index a8bf667d1..1e497c3a2 100644
--- a/src/Http/Wolverine.Http/HttpGraph.cs
+++ b/src/Http/Wolverine.Http/HttpGraph.cs
@@ -78,7 +78,7 @@ public OptionsDescription ToDescription()
foreach (var chain in _chains)
{
var chainDescription = OptionsDescription.For(chain);
- chainDescription.Title = chain.RoutePattern.RawText;
+ chainDescription.Title = (chain.RoutePattern?.RawText)!;
list.Rows.Add(chainDescription);
}
@@ -92,7 +92,7 @@ public void DiscoverEndpoints(WolverineHttpOptions wolverineHttpOptions)
var calls = source.FindActions();
logger.LogInformation("Found {Count} Wolverine HTTP endpoints in assemblies {Assemblies}", calls.Length,
- _options.Assemblies.Select(x => x.GetName().Name).Join(", "));
+ _options.Assemblies.Select(x => x.GetName().Name!).Join(", "));
if (calls.Length == 0)
{
logger.LogWarning(
diff --git a/src/Http/Wolverine.Http/IHttpAware.cs b/src/Http/Wolverine.Http/IHttpAware.cs
index 38b679d2c..616f1232c 100644
--- a/src/Http/Wolverine.Http/IHttpAware.cs
+++ b/src/Http/Wolverine.Http/IHttpAware.cs
@@ -48,7 +48,7 @@ public void Apply(IReadOnlyList chains, GenerationRules rules, IServi
internal class ApplyHttpAware : SyncFrame
{
private readonly Variable _target;
- private Variable _httpContext;
+ private Variable? _httpContext;
public ApplyHttpAware(Variable target)
{
@@ -65,7 +65,7 @@ public override IEnumerable FindVariables(IMethodVariables chain)
public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
{
writer.WriteComment("This response type customizes the HTTP response");
- writer.Write($"{nameof(HttpHandler.ApplyHttpAware)}({_target.Usage}, {_httpContext.Usage});");
+ writer.Write($"{nameof(HttpHandler.ApplyHttpAware)}({_target.Usage}, {_httpContext!.Usage});");
Next?.GenerateCode(method, writer);
}
}
diff --git a/src/Http/Wolverine.Http/NewtonsoftHttpSerialization.cs b/src/Http/Wolverine.Http/NewtonsoftHttpSerialization.cs
index db27fc87a..0d3dacefb 100644
--- a/src/Http/Wolverine.Http/NewtonsoftHttpSerialization.cs
+++ b/src/Http/Wolverine.Http/NewtonsoftHttpSerialization.cs
@@ -78,7 +78,7 @@ public async Task ReadFromJsonAsync(HttpContext context)
jsonReader.ArrayPool = _jsonCharPool;
jsonReader.CloseInput = false;
- return (T)_serializer.Deserialize(jsonReader, targetType);
+ return (T)_serializer.Deserialize(jsonReader, targetType)!;
}
internal class JsonArrayPool : IArrayPool
diff --git a/src/Http/Wolverine.Http/Policies/SetStatusCodeAndReturnIfEntityIsNullFrame.cs b/src/Http/Wolverine.Http/Policies/SetStatusCodeAndReturnIfEntityIsNullFrame.cs
index 433e1842c..2c01ce271 100644
--- a/src/Http/Wolverine.Http/Policies/SetStatusCodeAndReturnIfEntityIsNullFrame.cs
+++ b/src/Http/Wolverine.Http/Policies/SetStatusCodeAndReturnIfEntityIsNullFrame.cs
@@ -10,7 +10,7 @@ namespace Wolverine.Http.Policies;
internal class SetStatusCodeAndReturnIfEntityIsNullFrame : SyncFrame
{
private readonly Type _entityType;
- private Variable _httpResponse;
+ private Variable? _httpResponse;
private Variable? _entity;
public SetStatusCodeAndReturnIfEntityIsNullFrame(Type entityType)
@@ -33,8 +33,8 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
if (problemDetailsVariable != null)
writer.WriteComment($"Take no action if {problemDetailsVariable.Inner.Usage}.Status == 404");
writer.Write(
- $"BLOCK:if ({_entity.Usage} == null{(problemDetailsVariable == null ? "" : $" && {problemDetailsVariable.Inner.Usage}.Status != 404")})");
- writer.Write($"{_httpResponse.Usage}.{nameof(HttpResponse.StatusCode)} = 404;");
+ $"BLOCK:if ({_entity!.Usage} == null{(problemDetailsVariable == null ? "" : $" && {problemDetailsVariable.Inner.Usage}.Status != 404")})");
+ writer.Write($"{_httpResponse!.Usage}.{nameof(HttpResponse.StatusCode)} = 404;");
if (method.AsyncMode == AsyncMode.ReturnCompletedTask)
writer.Write($"return {typeof(Task).FullNameInCode()}.{nameof(Task.CompletedTask)};");
else
diff --git a/src/Http/Wolverine.Http/Policies/WriteProblemDetailsIfNull.cs b/src/Http/Wolverine.Http/Policies/WriteProblemDetailsIfNull.cs
index 36b1015f4..1f6b79330 100644
--- a/src/Http/Wolverine.Http/Policies/WriteProblemDetailsIfNull.cs
+++ b/src/Http/Wolverine.Http/Policies/WriteProblemDetailsIfNull.cs
@@ -7,7 +7,7 @@ namespace Wolverine.Http.Policies;
internal class WriteProblemDetailsIfNull : AsyncFrame
{
- private Variable _httpContext;
+ private Variable? _httpContext;
public WriteProblemDetailsIfNull(Variable entity, Variable identity, string message, int statusCode = 400)
{
@@ -32,12 +32,12 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
if (Message.Contains("{0}"))
{
- writer.Write($"await {nameof(HttpHandler.WriteProblems)}({StatusCode}, string.Format(\"{Message}\", {Identity.Usage}), {_httpContext.Usage}, {Identity.Usage});");
+ writer.Write($"await {nameof(HttpHandler.WriteProblems)}({StatusCode}, string.Format(\"{Message}\", {Identity.Usage}), {_httpContext!.Usage}, {Identity.Usage});");
}
else
{
var constant = Constant.For(Message);
- writer.Write($"await {nameof(HttpHandler.WriteProblems)}({StatusCode}, {constant.Usage}, {_httpContext.Usage}, {Identity.Usage});");
+ writer.Write($"await {nameof(HttpHandler.WriteProblems)}({StatusCode}, {constant.Usage}, {_httpContext!.Usage}, {Identity.Usage});");
}
writer.Write("return;");
diff --git a/src/Http/Wolverine.Http/Runtime/MultiTenancy/DetectTenantIdFrame.cs b/src/Http/Wolverine.Http/Runtime/MultiTenancy/DetectTenantIdFrame.cs
index 11482664b..180f1489b 100644
--- a/src/Http/Wolverine.Http/Runtime/MultiTenancy/DetectTenantIdFrame.cs
+++ b/src/Http/Wolverine.Http/Runtime/MultiTenancy/DetectTenantIdFrame.cs
@@ -10,7 +10,7 @@ internal class DetectTenantIdFrame : AsyncFrame
{
private readonly TenantIdDetection _options;
private readonly HttpChain _chain;
- private Variable _httpContext;
+ private Variable? _httpContext;
public DetectTenantIdFrame(TenantIdDetection options, HttpChain chain)
{
@@ -37,7 +37,7 @@ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
writer.WriteComment($"{i + 1}. {_options.Strategies[i]}");
}
- writer.Write($"var {TenantId.Usage} = await {nameof(HttpHandler.TryDetectTenantId)}({_httpContext.Usage});");
+ writer.Write($"var {TenantId.Usage} = await {nameof(HttpHandler.TryDetectTenantId)}({_httpContext!.Usage});");
if (_options.ShouldAssertTenantIdExists(_chain))
{
diff --git a/src/Http/Wolverine.Http/Transport/HttpEndpoint.cs b/src/Http/Wolverine.Http/Transport/HttpEndpoint.cs
index 54667ebd2..0e8a72985 100644
--- a/src/Http/Wolverine.Http/Transport/HttpEndpoint.cs
+++ b/src/Http/Wolverine.Http/Transport/HttpEndpoint.cs
@@ -14,7 +14,7 @@ public HttpEndpoint(Uri uri, EndpointRole role) : base(uri, role)
}
internal bool SupportsNativeScheduledSend { get; set; }
- public string OutboundUri { get; set; }
+ public string OutboundUri { get; set; } = string.Empty;
public override ValueTask BuildListenerAsync(IWolverineRuntime runtime, IReceiver receiver)
{
diff --git a/src/Http/Wolverine.Http/Transport/HttpTransportExecutor.cs b/src/Http/Wolverine.Http/Transport/HttpTransportExecutor.cs
index a2c74f51b..a06477cdf 100644
--- a/src/Http/Wolverine.Http/Transport/HttpTransportExecutor.cs
+++ b/src/Http/Wolverine.Http/Transport/HttpTransportExecutor.cs
@@ -99,7 +99,7 @@ public async Task InvokeAsync(HttpContext httpContext, JsonSerializerOp
envelope.Destination = $"http://localhost{httpContext.Request.Path}".ToUri();
envelope.DoNotCascadeResponse = true;
- envelope.Serializer = _runtime.Options.FindSerializer(envelope.ContentType);
+ envelope.Serializer = _runtime.Options.FindSerializer(envelope.ContentType!);
var deserializeResult = await _runtime.Pipeline.TryDeserializeEnvelope(envelope);
@@ -132,11 +132,11 @@ public async Task InvokeAsync(HttpContext httpContext, JsonSerializerOp
}
- IExecutor executor = default;
+ IExecutor? executor = default;
try
{
- executor = _runtime.FindInvoker(envelope.MessageType) as Executor;
+ executor = _runtime.FindInvoker(envelope.MessageType!) as Executor;
}
catch (Exception e)
{
@@ -170,7 +170,7 @@ public async Task InvokeAsync(HttpContext httpContext, JsonSerializerOp
response.ContentType = response.Serializer.ContentType;
}
- response.Data = response.Serializer.WriteMessage(response.Message);
+ response.Data = response.Serializer.WriteMessage(response.Message!);
httpContext.Response.ContentType = "binary/wolverine-envelope";
var responseData = EnvelopeSerializer.Serialize(response);
diff --git a/src/Http/Wolverine.Http/Transport/HttpTransportExtensions.cs b/src/Http/Wolverine.Http/Transport/HttpTransportExtensions.cs
index a2e466f8d..61bcf30df 100644
--- a/src/Http/Wolverine.Http/Transport/HttpTransportExtensions.cs
+++ b/src/Http/Wolverine.Http/Transport/HttpTransportExtensions.cs
@@ -43,7 +43,7 @@ public static HttpTransportSubscriberConfiguration ToHttpEndpoint(
string url,
bool supportsNativeScheduledSend = false,
bool useCloudEvents = false,
- JsonSerializerOptions options = null)
+ JsonSerializerOptions? options = null)
{
var transports =
publishing.As().Parent.Transports;
@@ -52,7 +52,7 @@ public static HttpTransportSubscriberConfiguration ToHttpEndpoint(
var endpoint = transport.EndpointFor(url);
if (useCloudEvents)
{
- endpoint.SerializerOptions = options;
+ endpoint.SerializerOptions = options!;
}
// This is necessary unfortunately to hook up the subscription rules
diff --git a/src/Http/Wolverine.Http/Transport/WolverineHttpTransportClient.cs b/src/Http/Wolverine.Http/Transport/WolverineHttpTransportClient.cs
index ccf978736..eac524cd6 100644
--- a/src/Http/Wolverine.Http/Transport/WolverineHttpTransportClient.cs
+++ b/src/Http/Wolverine.Http/Transport/WolverineHttpTransportClient.cs
@@ -16,7 +16,7 @@ public async Task SendBatchAsync(string uri, OutgoingMessageBatch batch)
await client.PostAsync(client.BaseAddress, content);
}
- public async Task SendAsync(string uri, Envelope envelope, JsonSerializerOptions options = null)
+ public async Task SendAsync(string uri, Envelope envelope, JsonSerializerOptions? options = null)
{
var client = clientFactory.CreateClient(uri);
var content = new ByteArrayContent(EnvelopeSerializer.Serialize(envelope));
@@ -35,7 +35,7 @@ public async Task SendBatchAsync(string uri, OutgoingMessageBatch batch)
await client.PostAsync(client.BaseAddress, content);
}
- public async Task SendAsync(string uri, Envelope envelope, JsonSerializerOptions options = null)
+ public async Task SendAsync(string uri, Envelope envelope, JsonSerializerOptions? options = null)
{
var client = clientFactory.CreateClient(uri);
var ce = new CloudEventsEnvelope(envelope);
diff --git a/src/Http/Wolverine.Http/WolverineHttpOptions.cs b/src/Http/Wolverine.Http/WolverineHttpOptions.cs
index 696d70261..e14ec4cd3 100644
--- a/src/Http/Wolverine.Http/WolverineHttpOptions.cs
+++ b/src/Http/Wolverine.Http/WolverineHttpOptions.cs
@@ -215,7 +215,7 @@ public void SourceServiceFromHttpContext()
public void UseNewtonsoftJsonForSerialization(Action? configure = null)
{
configure?.Invoke(NewtonsoftSerializerSettings);
- Endpoints.UseNewtonsoftJson();
+ Endpoints!.UseNewtonsoftJson();
}
diff --git a/src/Http/WolverineWebApi/Accounts/AccountCode.cs b/src/Http/WolverineWebApi/Accounts/AccountCode.cs
index 5e116a0c3..fc46af880 100644
--- a/src/Http/WolverineWebApi/Accounts/AccountCode.cs
+++ b/src/Http/WolverineWebApi/Accounts/AccountCode.cs
@@ -45,7 +45,7 @@ public static void Handle(
[WriteAggregate(nameof(TransferMoney.ToId))] IEventStream toAccount)
{
// Would already 404 if either referenced account does not exist
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
toAccount.AppendOne(new Debited(command.Amount));
@@ -66,7 +66,7 @@ public static void Handle(
[WriteAggregate(nameof(TransferMoney.ToId))] IEventStream toAccount)
{
// Would already 404 if either referenced account does not exist
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
toAccount.AppendOne(new Debited(command.Amount));
@@ -87,7 +87,7 @@ public static void Handle(
[WriteAggregate(nameof(TransferMoney.ToId))] IEventStream toAccount)
{
// Would already 404 if either referenced account does not exist
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
toAccount.AppendOne(new Debited(command.Amount));
@@ -104,9 +104,9 @@ public static void Before(Account fromAccount, Account toAccount)
To = toAccount;
}
- public static Account To { get; set; }
+ public static Account To { get; set; } = null!;
- public static Account From { get; set; }
+ public static Account From { get; set; } = null!;
[WolverinePost("/accounts/transfer4")]
public static void Handle(
@@ -117,7 +117,7 @@ public static void Handle(
[WriteAggregate(nameof(TransferMoney.ToId))] IEventStream toAccount)
{
// Would already 404 if either referenced account does not exist
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
toAccount.AppendOne(new Debited(command.Amount));
@@ -133,9 +133,9 @@ public static void Before(Account fromAccount, Account toAccount)
To = toAccount;
}
- public static Account To { get; set; }
+ public static Account To { get; set; } = null!;
- public static Account From { get; set; }
+ public static Account From { get; set; } = null!;
[WolverinePost("/accounts/transfer5")]
public static void Handle(
@@ -145,7 +145,7 @@ public static void Handle(
[Aggregate(nameof(TransferMoney.ToId))] IEventStream toAccount)
{
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
toAccount.AppendOne(new Debited(command.Amount));
@@ -161,9 +161,9 @@ public static void Before(Account fromAccount, Account toAccount)
To = toAccount;
}
- public static Account To { get; set; }
+ public static Account To { get; set; } = null!;
- public static Account From { get; set; }
+ public static Account From { get; set; } = null!;
[WolverinePost("/accounts/transfer6")]
public static void Handle(
@@ -173,7 +173,7 @@ public static void Handle(
[ReadAggregate(nameof(TransferMoney.ToId))] Account toAccount)
{
- if (fromAccount.Aggregate.Amount >= command.Amount)
+ if (fromAccount.Aggregate!.Amount >= command.Amount)
{
fromAccount.AppendOne(new Withdrawn(command.Amount));
}
diff --git a/src/Http/WolverineWebApi/Bugs/SomeEndpoint.cs b/src/Http/WolverineWebApi/Bugs/SomeEndpoint.cs
index 950c71f49..fe4aabd1e 100644
--- a/src/Http/WolverineWebApi/Bugs/SomeEndpoint.cs
+++ b/src/Http/WolverineWebApi/Bugs/SomeEndpoint.cs
@@ -27,5 +27,5 @@ public class SomeEndpoint
public class SomeDocument
{
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
}
\ No newline at end of file
diff --git a/src/Http/WolverineWebApi/CreateEndpoint.cs b/src/Http/WolverineWebApi/CreateEndpoint.cs
index 34ca9be78..4097a482e 100644
--- a/src/Http/WolverineWebApi/CreateEndpoint.cs
+++ b/src/Http/WolverineWebApi/CreateEndpoint.cs
@@ -26,5 +26,5 @@ public record IssueCreated(Guid Id) : CreationResponse($"/issue/{Id}");
public class Issue
{
public Guid Id { get; set; }
- public string Title { get; set; }
+ public string Title { get; set; } = null!;
}
\ No newline at end of file
diff --git a/src/Http/WolverineWebApi/EFCore.cs b/src/Http/WolverineWebApi/EFCore.cs
index 5d86cb64d..2cc6e95f5 100644
--- a/src/Http/WolverineWebApi/EFCore.cs
+++ b/src/Http/WolverineWebApi/EFCore.cs
@@ -25,13 +25,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
public class Item
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public Guid Id { get; set; }
}
public class CreateItemCommand
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class ItemCreated
diff --git a/src/Http/WolverineWebApi/Forms/FormEndpoints.cs b/src/Http/WolverineWebApi/Forms/FormEndpoints.cs
index 73a82e8ee..3a9d662b4 100644
--- a/src/Http/WolverineWebApi/Forms/FormEndpoints.cs
+++ b/src/Http/WolverineWebApi/Forms/FormEndpoints.cs
@@ -115,13 +115,13 @@ public static string PostWithFiles([FromForm] FormWithFiles form)
public class FormWithFile
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public IFormFile? File { get; set; }
}
public class FormWithFiles
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public IFormFileCollection? Files { get; set; }
}
@@ -143,10 +143,10 @@ public class AsParametersQuery{
public Direction EnumNotUsed{get;set;}
[FromQuery]
- public string StringFromQuery { get; set; }
+ public string StringFromQuery { get; set; } = null!;
[FromForm]
- public string StringFromForm { get; set; }
- public string StringNotUsed { get; set; }
+ public string StringFromForm { get; set; } = null!;
+ public string StringNotUsed { get; set; } = null!;
[FromQuery]
public int IntegerFromQuery { get; set; }
[FromForm]
@@ -164,7 +164,7 @@ public class AsParametersQuery{
public bool BooleanNotUsed { get; set; }
[FromHeader(Name = "x-string")]
- public string StringHeader { get; set; }
+ public string StringHeader { get; set; } = null!;
[FromHeader(Name = "x-number")] public int NumberHeader { get; set; } = 5;
@@ -177,7 +177,7 @@ public class AsParametersQuery{
public class AsParameterBody
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public Direction Direction { get; set; }
public int Distance { get; set; }
}
@@ -186,13 +186,13 @@ public class AsParametersQuery2
{
// We do a check inside of an HTTP endpoint that this works correctly
[FromServices, JsonIgnore]
- public IDocumentStore Store { get; set; }
-
+ public IDocumentStore Store { get; set; } = null!;
+
[FromBody]
- public AsParameterBody Body { get; set; }
-
+ public AsParameterBody Body { get; set; } = null!;
+
[FromRoute]
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
[FromRoute]
public int Number { get; set; }
diff --git a/src/Http/WolverineWebApi/HeaderUsingEndpoint.cs b/src/Http/WolverineWebApi/HeaderUsingEndpoint.cs
index fc1d81b3e..268ded097 100644
--- a/src/Http/WolverineWebApi/HeaderUsingEndpoint.cs
+++ b/src/Http/WolverineWebApi/HeaderUsingEndpoint.cs
@@ -9,7 +9,7 @@ namespace WolverineWebApi;
public class HeaderUsingEndpoint
{
// For testing
- public static string Day;
+ public static string Day = null!;
#region sample_pushing_header_values_into_endpoint_methods
@@ -18,7 +18,7 @@ public class HeaderUsingEndpoint
public static void Before([FromHeader(Name = "x-day")] string? day)
{
Debug.WriteLine($"Day header is {day}");
- Day = day; // This is for testing
+ Day = day!; // This is for testing
}
[WolverineGet("/headers/simple")]
@@ -60,7 +60,7 @@ public class HeaderMiddlewareAttribute : ModifyHttpChainAttribute
{
public override void Modify(HttpChain chain, GenerationRules rules)
{
- chain.Middleware.Add(MethodCall.For(x => x.Before(default)));
+ chain.Middleware.Add(MethodCall.For(x => x.Before(default!)));
}
}
diff --git a/src/Http/WolverineWebApi/HttpContextEndpoints.cs b/src/Http/WolverineWebApi/HttpContextEndpoints.cs
index 57b5e51ba..40848741c 100644
--- a/src/Http/WolverineWebApi/HttpContextEndpoints.cs
+++ b/src/Http/WolverineWebApi/HttpContextEndpoints.cs
@@ -6,7 +6,7 @@ namespace WolverineWebApi;
public class HttpContextEndpoints
{
- public static ClaimsPrincipal User { get; set; }
+ public static ClaimsPrincipal User { get; set; } = null!;
[WolverineGet("/http/context")]
public void UseHttpContext(HttpContext context)
diff --git a/src/Http/WolverineWebApi/Marten/Orders.cs b/src/Http/WolverineWebApi/Marten/Orders.cs
index 1f133586f..c73280707 100644
--- a/src/Http/WolverineWebApi/Marten/Orders.cs
+++ b/src/Http/WolverineWebApi/Marten/Orders.cs
@@ -33,7 +33,7 @@ public record ItemReady(string Name);
public class Item
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public bool Ready { get; set; }
}
diff --git a/src/Http/WolverineWebApi/Marten/StrongTypedIdentifiers.cs b/src/Http/WolverineWebApi/Marten/StrongTypedIdentifiers.cs
index 81989a57e..6cd1b2691 100644
--- a/src/Http/WolverineWebApi/Marten/StrongTypedIdentifiers.cs
+++ b/src/Http/WolverineWebApi/Marten/StrongTypedIdentifiers.cs
@@ -11,8 +11,8 @@ public static class StrongLetterHandler
#region sample_using_strong_typed_id_as_route_argument
[WolverineGet("/sti/aggregate/longhand/{id}")]
- public static ValueTask Handle2(LetterId id, IDocumentSession session) =>
- session.Events.FetchLatest(id.Value);
+ public static async ValueTask Handle2(LetterId id, IDocumentSession session) =>
+ (await session.Events.FetchLatest(id.Value))!;
// This is an equivalent to the endpoint above
[WolverineGet("/sti/aggregate/{id}")]
diff --git a/src/Http/WolverineWebApi/Marten/Toys.cs b/src/Http/WolverineWebApi/Marten/Toys.cs
index 0e4b90c86..82bdad4d9 100644
--- a/src/Http/WolverineWebApi/Marten/Toys.cs
+++ b/src/Http/WolverineWebApi/Marten/Toys.cs
@@ -10,7 +10,7 @@ namespace WolverineWebApi.Marten;
public class Toy
{
public ToyId Id { get; set; }
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public static class ToyEndpoints
diff --git a/src/Http/WolverineWebApi/MessageHandlers.cs b/src/Http/WolverineWebApi/MessageHandlers.cs
index d1475b1c1..bb4e6552e 100644
--- a/src/Http/WolverineWebApi/MessageHandlers.cs
+++ b/src/Http/WolverineWebApi/MessageHandlers.cs
@@ -26,7 +26,7 @@ public CustomResponse()
{
}
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public static class MessageHandler
diff --git a/src/Http/WolverineWebApi/MiddlewareEndpoints.cs b/src/Http/WolverineWebApi/MiddlewareEndpoints.cs
index 0a91247fd..feced1342 100644
--- a/src/Http/WolverineWebApi/MiddlewareEndpoints.cs
+++ b/src/Http/WolverineWebApi/MiddlewareEndpoints.cs
@@ -38,7 +38,7 @@ public static void Configure(HttpChain chain)
chain.Middleware.Add(MethodCall.For(x => x.Before()));
// Call this method after the normal endpoint
- chain.Postprocessors.Add(MethodCall.For(x => x.Finally(null, null)));
+ chain.Postprocessors.Add(MethodCall.For(x => x.Finally(null!, null!)));
}
[WolverineGet("/timed")]
diff --git a/src/Http/WolverineWebApi/QuerystringEndpoints.cs b/src/Http/WolverineWebApi/QuerystringEndpoints.cs
index 7f340df01..5c021f670 100644
--- a/src/Http/WolverineWebApi/QuerystringEndpoints.cs
+++ b/src/Http/WolverineWebApi/QuerystringEndpoints.cs
@@ -118,11 +118,11 @@ public record AliasedIntArrayQuery([FromQuery(Name = "n")] int[] Numbers);
public class BigQuery
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
public int Number { get; set; }
public Direction Direction { get; set; }
- public string[] Values { get; set; }
- public int[] Numbers { get; set; }
+ public string[] Values { get; set; } = null!;
+ public int[] Numbers { get; set; } = null!;
public bool Flag { get; set; }
@@ -137,15 +137,15 @@ public class BigQuery
public List ListValues { get; set; } = new();
public List EnumListValues { get; set; } = new();
- public List IntList { get; set; }
+ public List IntList { get; set; } = null!;
[FromQuery(Name = "v")]
[FromForm(Name = "v")]
- public string[] AliasedValues { get; set; }
+ public string[] AliasedValues { get; set; } = null!;
[FromQuery(Name = "n")]
[FromForm(Name = "n")]
- public int[] AliasedNumbers { get; set; }
+ public int[] AliasedNumbers { get; set; } = null!;
[FromQuery(Name = "d")]
[FromForm(Name = "d")]
diff --git a/src/Http/WolverineWebApi/Samples/TodoController.cs b/src/Http/WolverineWebApi/Samples/TodoController.cs
index 8541d021e..3e354a2dd 100644
--- a/src/Http/WolverineWebApi/Samples/TodoController.cs
+++ b/src/Http/WolverineWebApi/Samples/TodoController.cs
@@ -144,7 +144,7 @@ public static StoreDoc Put(
// but note the [Required] attribute
[Required] Todo? todo)
{
- todo.Name = request.Name;
+ todo!.Name = request.Name;
todo.IsComplete = request.IsComplete;
return MartenOps.Store(todo);
@@ -182,7 +182,7 @@ public static class UpdateEndpointWithValidation
public static IResult Validate([Required] Todo? todo)
{
- return todo.IsComplete
+ return todo!.IsComplete
? Results.ValidationProblem([new("IsComplere", ["Completed Todo cannot be updated"])])
: WolverineContinue.Result();
}
@@ -199,7 +199,7 @@ public static StoreDoc Put(
// but note the [Required] attribute
[Required] Todo? todo)
{
- todo.Name = request.Name;
+ todo!.Name = request.Name;
todo.IsComplete = request.IsComplete;
return MartenOps.Store(todo);
@@ -220,7 +220,7 @@ public static StoreDoc Put(
// but note the [Required] attribute
[Required] Todo? todo)
{
- todo.Name = request.Name;
+ todo!.Name = request.Name;
todo.IsComplete = request.IsComplete;
return MartenOps.Store(todo);
@@ -248,7 +248,7 @@ public static StoreDoc Put(
// but note the [Required] attribute
[Required] Todo? todo)
{
- todo.Name = request.Name;
+ todo!.Name = request.Name;
todo.IsComplete = request.IsComplete;
return MartenOps.Store(todo);
diff --git a/src/Http/WolverineWebApi/ServiceEndpoints.cs b/src/Http/WolverineWebApi/ServiceEndpoints.cs
index d16c6912b..4b70eaa80 100644
--- a/src/Http/WolverineWebApi/ServiceEndpoints.cs
+++ b/src/Http/WolverineWebApi/ServiceEndpoints.cs
@@ -40,7 +40,7 @@ public void Handle(Data data)
public class Data
{
public Guid Id { get; set; }
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class Recorder
diff --git a/src/Http/WolverineWebApi/SwaggerEndpoints.cs b/src/Http/WolverineWebApi/SwaggerEndpoints.cs
index d56d15234..c07c177f2 100644
--- a/src/Http/WolverineWebApi/SwaggerEndpoints.cs
+++ b/src/Http/WolverineWebApi/SwaggerEndpoints.cs
@@ -25,5 +25,5 @@ public record CreateUserProfile(string Name);
public class UserProfile
{
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
}
\ No newline at end of file
diff --git a/src/Http/WolverineWebApi/Things/Code.cs b/src/Http/WolverineWebApi/Things/Code.cs
index 029cdbb5e..93913b7a1 100644
--- a/src/Http/WolverineWebApi/Things/Code.cs
+++ b/src/Http/WolverineWebApi/Things/Code.cs
@@ -15,8 +15,8 @@ namespace WolverineWebApi.Things;
public class Thing
{
- public string Id { get; set; }
- public string Title { get; set; }
+ public string Id { get; set; } = null!;
+ public string Title { get; set; } = null!;
}
public class ThingProjection : SingleStreamProjection
diff --git a/src/Http/WolverineWebApi/Todos/Todo2.cs b/src/Http/WolverineWebApi/Todos/Todo2.cs
index e74716786..fd8c0c4aa 100644
--- a/src/Http/WolverineWebApi/Todos/Todo2.cs
+++ b/src/Http/WolverineWebApi/Todos/Todo2.cs
@@ -10,7 +10,7 @@ namespace WolverineWebApi.Todos;
[DocumentAlias("test_todo")]
public class Todo2
{
- public string Id { get; set; }
+ public string Id { get; set; } = null!;
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
diff --git a/src/Http/WolverineWebApi/WebSockets/BroadcastHub.cs b/src/Http/WolverineWebApi/WebSockets/BroadcastHub.cs
index d7111393e..d70a5bf24 100644
--- a/src/Http/WolverineWebApi/WebSockets/BroadcastHub.cs
+++ b/src/Http/WolverineWebApi/WebSockets/BroadcastHub.cs
@@ -96,7 +96,9 @@ public void Apply(IReadOnlyList chains, GenerationRules rules, IServiceC
{
messages.UseReturnAction(v =>
{
+#pragma warning disable CS4014
var call = MethodCall.For(x => x.PostMany(null!));
+#pragma warning restore CS4014
call.Arguments[0] = messages;
return call;
diff --git a/src/Persistence/CosmosDbTests/AppFixture.cs b/src/Persistence/CosmosDbTests/AppFixture.cs
index 3df787909..5a1fb2d8d 100644
--- a/src/Persistence/CosmosDbTests/AppFixture.cs
+++ b/src/Persistence/CosmosDbTests/AppFixture.cs
@@ -1,4 +1,6 @@
using System.Net;
+using DotNet.Testcontainers.Builders;
+using DotNet.Testcontainers.Containers;
using Microsoft.Azure.Cosmos;
using Wolverine;
using Wolverine.CosmosDb;
@@ -9,17 +11,51 @@ namespace CosmosDbTests;
public class AppFixture : IAsyncLifetime
{
- // CosmosDB Linux emulator defaults
- public const string ConnectionString =
- "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
-
+ public const string AccountKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
public const string DatabaseName = "wolverine_tests";
+ // Static container shared across all AppFixture instances
+ private static IContainer? _sharedContainer;
+ private static string _sharedConnectionString = null!;
+ private static readonly SemaphoreSlim _lock = new(1, 1);
+
+ public string ConnectionString => _sharedConnectionString;
+
public CosmosClient Client { get; private set; } = null!;
public Container Container { get; private set; } = null!;
+ private static async Task EnsureContainerStarted()
+ {
+ await _lock.WaitAsync();
+ try
+ {
+ if (_sharedContainer != null) return;
+
+ _sharedContainer = new ContainerBuilder()
+ .WithImage("mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview")
+ .WithPortBinding(8081, true)
+ .WithPortBinding(1234, true)
+ .WithEnvironment("PROTOCOL", "https")
+ .WithWaitStrategy(Wait.ForUnixContainer()
+ .UntilMessageIsLogged("Gateway=OK"))
+ .Build();
+
+ await _sharedContainer.StartAsync();
+
+ var host = _sharedContainer.Hostname;
+ var port = _sharedContainer.GetMappedPublicPort(8081);
+ _sharedConnectionString = $"AccountEndpoint=https://{host}:{port}/;AccountKey={AccountKey}";
+ }
+ finally
+ {
+ _lock.Release();
+ }
+ }
+
public async Task InitializeAsync()
{
+ await EnsureContainerStarted();
+
var clientOptions = new CosmosClientOptions
{
HttpClientFactory = () =>
@@ -65,6 +101,7 @@ public async Task InitializeAsync()
public async Task DisposeAsync()
{
Client?.Dispose();
+ // Container is shared - don't dispose it here; process exit handles cleanup
}
public CosmosDbMessageStore BuildMessageStore()
diff --git a/src/Persistence/CosmosDbTests/CosmosDbTests.csproj b/src/Persistence/CosmosDbTests/CosmosDbTests.csproj
index f7a5b580d..b1735aff4 100644
--- a/src/Persistence/CosmosDbTests/CosmosDbTests.csproj
+++ b/src/Persistence/CosmosDbTests/CosmosDbTests.csproj
@@ -16,6 +16,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/Persistence/CosmosDbTests/end_to_end.cs b/src/Persistence/CosmosDbTests/end_to_end.cs
index c4d4dc114..0e1c5830e 100644
--- a/src/Persistence/CosmosDbTests/end_to_end.cs
+++ b/src/Persistence/CosmosDbTests/end_to_end.cs
@@ -10,6 +10,7 @@
namespace CosmosDbTests;
[Collection("cosmosdb")]
+[Trait("Category", "Flaky")]
public class end_to_end
{
private readonly AppFixture _fixture;
diff --git a/src/Persistence/CosmosDbTests/using_storage_return_types_and_entity_attributes.cs b/src/Persistence/CosmosDbTests/using_storage_return_types_and_entity_attributes.cs
index 4671e8c00..82e4dab45 100644
--- a/src/Persistence/CosmosDbTests/using_storage_return_types_and_entity_attributes.cs
+++ b/src/Persistence/CosmosDbTests/using_storage_return_types_and_entity_attributes.cs
@@ -10,6 +10,7 @@
namespace CosmosDbTests;
[Collection("cosmosdb")]
+[Trait("Category", "Flaky")]
public class using_storage_return_types_and_entity_attributes
{
private readonly AppFixture _fixture;
diff --git a/src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj b/src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj
index 4c606c150..ea174a298 100644
--- a/src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj
+++ b/src/Persistence/EfCoreTests.MultiTenancy/EfCoreTests.MultiTenancy.csproj
@@ -4,6 +4,7 @@
false
true
net9.0
+ $(NoWarn);CS0436
diff --git a/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyCompliance.cs b/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyCompliance.cs
index 9e285b6b8..11c30bd27 100644
--- a/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyCompliance.cs
+++ b/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyCompliance.cs
@@ -29,12 +29,12 @@ public enum DatabaseEngine
[Collection("multi-tenancy")]
public abstract class MultiTenancyCompliance : IAsyncLifetime, IWolverineExtension
{
- protected IDbContextBuilder theBuilder;
+ protected IDbContextBuilder theBuilder = null!;
private readonly DatabaseEngine _engine;
- protected IAlbaHost theHost;
- protected string tenant1ConnectionString;
- protected string tenant2ConnectionString;
- protected string tenant3ConnectionString;
+ protected IAlbaHost theHost = null!;
+ protected string tenant1ConnectionString = null!;
+ protected string tenant2ConnectionString = null!;
+ protected string tenant3ConnectionString = null!;
protected MultiTenancyCompliance(DatabaseEngine engine)
{
@@ -164,16 +164,16 @@ public async Task end_to_end_with_commands()
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- (await blueDbContext.Items.FindAsync(blueId)).Name.ShouldBe("Blue!");
+ (await blueDbContext.Items.FindAsync(blueId))!.Name.ShouldBe("Blue!");
(await greenDbContext.Items.FindAsync(blueId)).ShouldBeNull();
(await redDbContext.Items.FindAsync(blueId)).ShouldBeNull();
(await blueDbContext.Items.FindAsync(redId)).ShouldBeNull();
(await greenDbContext.Items.FindAsync(redId)).ShouldBeNull();
- (await redDbContext.Items.FindAsync(redId)).Name.ShouldBe("Red!");
+ (await redDbContext.Items.FindAsync(redId))!.Name.ShouldBe("Red!");
(await blueDbContext.Items.FindAsync(greenId)).ShouldBeNull();
- (await greenDbContext.Items.FindAsync(greenId)).Name.ShouldBe("Green!");
+ (await greenDbContext.Items.FindAsync(greenId))!.Name.ShouldBe("Green!");
(await redDbContext.Items.FindAsync(greenId)).ShouldBeNull();
}
@@ -191,7 +191,7 @@ public async Task end_to_end_with_default_database()
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- (await defaultDbContext.FindAsync- (defaultId)).Name.ShouldBe("The Default!");
+ (await defaultDbContext.FindAsync
- (defaultId))!.Name.ShouldBe("The Default!");
}
catch (DefaultTenantUsageDisabledException)
{
@@ -214,7 +214,7 @@ public async Task end_to_end_with_cascading_messages()
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- var blue = await blueDbContext.Items.FindAsync(blueId);
+ var blue = (await blueDbContext.Items.FindAsync(blueId))!;
blue.Name.ShouldBe("Blue!");
blue.Approved.ShouldBeTrue();
(await greenDbContext.Items.FindAsync(blueId)).ShouldBeNull();
@@ -222,12 +222,12 @@ public async Task end_to_end_with_cascading_messages()
(await blueDbContext.Items.FindAsync(redId)).ShouldBeNull();
(await greenDbContext.Items.FindAsync(redId)).ShouldBeNull();
- var red = await redDbContext.Items.FindAsync(redId);
+ var red = (await redDbContext.Items.FindAsync(redId))!;
red.Name.ShouldBe("Red!");
red.Approved.ShouldBeTrue();
(await blueDbContext.Items.FindAsync(greenId)).ShouldBeNull();
- var green = await greenDbContext.Items.FindAsync(greenId);
+ var green = (await greenDbContext.Items.FindAsync(greenId))!;
green.Name.ShouldBe("Green!");
green.Approved.ShouldBeTrue();
(await redDbContext.Items.FindAsync(greenId)).ShouldBeNull();
@@ -254,7 +254,7 @@ await theHost.Scenario(x =>
(await redDbContext.FindAsync
- (command.Id)).ShouldBeNull();
(await greenDbContext.FindAsync
- (command.Id)).ShouldBeNull();
- (await blueDbContext.FindAsync
- (command.Id)).Name.ShouldBe(command.Name);
+ (await blueDbContext.FindAsync
- (command.Id))!.Name.ShouldBe(command.Name);
}
[Fact]
@@ -277,7 +277,7 @@ await theHost.Scenario(x =>
(await redDbContext.FindAsync
- (command.Id)).ShouldBeNull();
(await greenDbContext.FindAsync
- (command.Id)).ShouldBeNull();
- (await defaultDbContext.FindAsync
- (command.Id)).Name.ShouldBe(command.Name);
+ (await defaultDbContext.FindAsync
- (command.Id))!.Name.ShouldBe(command.Name);
}
[Fact]
@@ -373,13 +373,13 @@ await theHost.Scenario(x =>
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- (await blueDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
- (await redDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
-
+ (await blueDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+ (await redDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+
// Only approved this one
- (await greenDbContext.FindAsync
- (command.Id)).Approved.ShouldBeTrue();
+ (await greenDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeTrue();
}
-
+
[Fact]
public async Task http_post_with_direct_reference_in_middleware()
{
@@ -403,13 +403,13 @@ await theHost.Scenario(x =>
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- (await blueDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
- (await redDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
-
+ (await blueDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+ (await redDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+
// Only approved this one
- (await greenDbContext.FindAsync
- (command.Id)).Approved.ShouldBeTrue();
+ (await greenDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeTrue();
}
-
+
[Fact]
public async Task http_post_with_by_entity_attribute_and_storage_action()
{
@@ -433,13 +433,13 @@ await theHost.Scenario(x =>
var greenDbContext = await theBuilder.BuildAsync("green", CancellationToken.None);
var redDbContext = await theBuilder.BuildAsync("red", CancellationToken.None);
- (await blueDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
- (await redDbContext.FindAsync
- (command.Id)).Approved.ShouldBeFalse();
-
+ (await blueDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+ (await redDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeFalse();
+
// Only approved this one
- (await greenDbContext.FindAsync
- (command.Id)).Approved.ShouldBeTrue();
+ (await greenDbContext.FindAsync
- (command.Id))!.Approved.ShouldBeTrue();
}
-
+
[Fact]
public async Task use_sagas()
{
@@ -494,7 +494,7 @@ await theHost.ExecuteAndWaitAsync(async _ =>
var dbContext = await builder.BuildAsync("blue", CancellationToken.None);
var item2 = await dbContext.Items.FindAsync(id);
- item2.Approved.ShouldBeTrue();
+ item2!.Approved.ShouldBeTrue();
}
}
\ No newline at end of file
diff --git a/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyDocumentationSamples.cs b/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyDocumentationSamples.cs
index 6aa2e6309..d30fd89fe 100644
--- a/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyDocumentationSamples.cs
+++ b/src/Persistence/EfCoreTests.MultiTenancy/MultiTenancyDocumentationSamples.cs
@@ -31,15 +31,15 @@ public async Task static_postgresql()
{
// First, you do have to have a "main" PostgreSQL database for messaging persistence
// that will store information about running nodes, agents, and non-tenanted operations
- opts.PersistMessagesWithPostgresql(configuration.GetConnectionString("main"))
+ opts.PersistMessagesWithPostgresql(configuration.GetConnectionString("main")!)
// Add known tenants at bootstrapping time
.RegisterStaticTenants(tenants =>
{
// Add connection strings for the expected tenant ids
- tenants.Register("tenant1", configuration.GetConnectionString("tenant1"));
- tenants.Register("tenant2", configuration.GetConnectionString("tenant2"));
- tenants.Register("tenant3", configuration.GetConnectionString("tenant3"));
+ tenants.Register("tenant1", configuration.GetConnectionString("tenant1")!);
+ tenants.Register("tenant2", configuration.GetConnectionString("tenant2")!);
+ tenants.Register("tenant3", configuration.GetConnectionString("tenant3")!);
});
opts.Services.AddDbContextWithWolverineManagedMultiTenancy((builder, connectionString, _) =>
@@ -63,15 +63,15 @@ public async Task static_sqlserver()
{
// First, you do have to have a "main" PostgreSQL database for messaging persistence
// that will store information about running nodes, agents, and non-tenanted operations
- opts.PersistMessagesWithSqlServer(configuration.GetConnectionString("main"))
+ opts.PersistMessagesWithSqlServer(configuration.GetConnectionString("main")!)
// Add known tenants at bootstrapping time
.RegisterStaticTenants(tenants =>
{
// Add connection strings for the expected tenant ids
- tenants.Register("tenant1", configuration.GetConnectionString("tenant1"));
- tenants.Register("tenant2", configuration.GetConnectionString("tenant2"));
- tenants.Register("tenant3", configuration.GetConnectionString("tenant3"));
+ tenants.Register("tenant1", configuration.GetConnectionString("tenant1")!);
+ tenants.Register("tenant2", configuration.GetConnectionString("tenant2")!);
+ tenants.Register("tenant3", configuration.GetConnectionString("tenant3")!);
});
// Just to show that you *can* use more than one DbContext
@@ -101,7 +101,7 @@ public void dynamic_multi_tenancy_with_postgresql()
{
// You need a main database no matter what that will hold information about the Wolverine system itself
// and..
- opts.PersistMessagesWithPostgresql(configuration.GetConnectionString("wolverine"))
+ opts.PersistMessagesWithPostgresql(configuration.GetConnectionString("wolverine")!)
// ...also a table holding the tenant id to connection string information
.UseMasterTableTenancy(seed =>
@@ -109,9 +109,9 @@ public void dynamic_multi_tenancy_with_postgresql()
// These registrations are 100% just to seed data for local development
// Maybe you want to omit this during production?
// Or do something programmatic by looping through data in the IConfiguration?
- seed.Register("tenant1", configuration.GetConnectionString("tenant1"));
- seed.Register("tenant2", configuration.GetConnectionString("tenant2"));
- seed.Register("tenant3", configuration.GetConnectionString("tenant3"));
+ seed.Register("tenant1", configuration.GetConnectionString("tenant1")!);
+ seed.Register("tenant2", configuration.GetConnectionString("tenant2")!);
+ seed.Register("tenant3", configuration.GetConnectionString("tenant3")!);
});
});
@@ -130,7 +130,7 @@ public void dynamic_multi_tenancy_with_sqlserver()
{
// You need a main database no matter what that will hold information about the Wolverine system itself
// and..
- opts.PersistMessagesWithSqlServer(configuration.GetConnectionString("wolverine"))
+ opts.PersistMessagesWithSqlServer(configuration.GetConnectionString("wolverine")!)
// ...also a table holding the tenant id to connection string information
.UseMasterTableTenancy(seed =>
@@ -138,9 +138,9 @@ public void dynamic_multi_tenancy_with_sqlserver()
// These registrations are 100% just to seed data for local development
// Maybe you want to omit this during production?
// Or do something programmatic by looping through data in the IConfiguration?
- seed.Register("tenant1", configuration.GetConnectionString("tenant1"));
- seed.Register("tenant2", configuration.GetConnectionString("tenant2"));
- seed.Register("tenant3", configuration.GetConnectionString("tenant3"));
+ seed.Register("tenant1", configuration.GetConnectionString("tenant1")!);
+ seed.Register("tenant2", configuration.GetConnectionString("tenant2")!);
+ seed.Register("tenant3", configuration.GetConnectionString("tenant3")!);
});
});
diff --git a/src/Persistence/EfCoreTests/Bug_252_codegen_issue.cs b/src/Persistence/EfCoreTests/Bug_252_codegen_issue.cs
index a3c78d9ba..1d4e148b0 100644
--- a/src/Persistence/EfCoreTests/Bug_252_codegen_issue.cs
+++ b/src/Persistence/EfCoreTests/Bug_252_codegen_issue.cs
@@ -95,9 +95,9 @@ public async Task bug_256_message_bus_should_be_in_outbox_transaction()
opt.Policies.AutoApplyTransactions();
}).StartAsync();
- var chain = host.Services.GetRequiredService().HandlerFor().As().Chain;
-
- var lines = chain.SourceCode.ReadLines();
+ var chain = host.Services.GetRequiredService().HandlerFor()!.As()!.Chain!;
+
+ var lines = chain.SourceCode!.ReadLines()!;
// Just proving that the code generation did NOT opt to use a nested container
// for creating the handler
diff --git a/src/Persistence/EfCoreTests/Bugs/XUnitLogger.cs b/src/Persistence/EfCoreTests/Bugs/XUnitLogger.cs
index c7b6cfce3..2c0df9550 100644
--- a/src/Persistence/EfCoreTests/Bugs/XUnitLogger.cs
+++ b/src/Persistence/EfCoreTests/Bugs/XUnitLogger.cs
@@ -26,13 +26,13 @@ public bool IsEnabled(LogLevel logLevel)
return logLevel != LogLevel.None;
}
- public IDisposable BeginScope(TState state)
+ public IDisposable BeginScope(TState state) where TState : notnull
{
return new Disposable();
}
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception,
- Func formatter)
+ public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
+ Func formatter)
{
if (exception is DivideByZeroException)
{
diff --git a/src/Persistence/EfCoreTests/DomainEvents/configuration_of_domain_events_scrapers.cs b/src/Persistence/EfCoreTests/DomainEvents/configuration_of_domain_events_scrapers.cs
index c94024108..e05d796b3 100644
--- a/src/Persistence/EfCoreTests/DomainEvents/configuration_of_domain_events_scrapers.cs
+++ b/src/Persistence/EfCoreTests/DomainEvents/configuration_of_domain_events_scrapers.cs
@@ -25,7 +25,7 @@ namespace EfCoreTests.DomainEvents;
[Collection("sqlserver")]
public class configuration_of_domain_events_scrapers : IAsyncDisposable
{
- private IHost theHost;
+ private IHost theHost = null!;
public configuration_of_domain_events_scrapers()
{
@@ -82,7 +82,7 @@ public async Task publish_domain_events_with_DomainEvents()
scope.ServiceProvider.GetRequiredService().ShouldNotBeNull();
var container = theHost.Services.GetRequiredService();
- container.DefaultFor().Lifetime.ShouldBe(ServiceLifetime.Scoped);
+ container.DefaultFor()!.Lifetime.ShouldBe(ServiceLifetime.Scoped);
scope.ServiceProvider.GetServices().Single().ShouldBeOfType();
}
diff --git a/src/Persistence/EfCoreTests/EfCoreCompilationScenarios.cs b/src/Persistence/EfCoreTests/EfCoreCompilationScenarios.cs
index d575e6c09..662525644 100644
--- a/src/Persistence/EfCoreTests/EfCoreCompilationScenarios.cs
+++ b/src/Persistence/EfCoreTests/EfCoreCompilationScenarios.cs
@@ -63,7 +63,7 @@ public async Task ef_context_is_singleton_and_options_are_singleton()
public class CreateItem
{
- public string Name { get; set; }
+ public string Name { get; set; } = null!;
}
public class CreateItemHandler
diff --git a/src/Persistence/EfCoreTests/Migrations/with_one_postgresql_context.cs b/src/Persistence/EfCoreTests/Migrations/with_one_postgresql_context.cs
index ca97e85f3..b259d198e 100644
--- a/src/Persistence/EfCoreTests/Migrations/with_one_postgresql_context.cs
+++ b/src/Persistence/EfCoreTests/Migrations/with_one_postgresql_context.cs
@@ -21,7 +21,7 @@ namespace EfCoreTests.Migrations;
[Collection("postgresql")]
public class with_one_postgresql_context : IAsyncLifetime
{
- private IHost _host;
+ private IHost _host = null!;
public async Task InitializeAsync()
{
diff --git a/src/Persistence/EfCoreTests/Migrations/with_one_sqlserver_context.cs b/src/Persistence/EfCoreTests/Migrations/with_one_sqlserver_context.cs
index 35c82022b..1a8d1a8e4 100644
--- a/src/Persistence/EfCoreTests/Migrations/with_one_sqlserver_context.cs
+++ b/src/Persistence/EfCoreTests/Migrations/with_one_sqlserver_context.cs
@@ -22,7 +22,7 @@ namespace EfCoreTests.Migrations;
[Collection("sqlserver")]
public class with_one_sqlserver_context : IAsyncLifetime
{
- private IHost _host;
+ private IHost _host = null!;
public async Task InitializeAsync()
{
@@ -109,9 +109,9 @@ public class Blog
public int BlogId { get; set; }
[Column("url")]
- public string Url { get; set; }
+ public string Url { get; set; } = null!;
// Navigation property for related posts
- public List Posts { get; set; }
+ public List Posts { get; set; } = null!;
}
public class Post
@@ -120,15 +120,15 @@ public class Post
public int PostId { get; set; }
[Column("title")]
- public string Title { get; set; }
-
+ public string Title { get; set; } = null!;
+
[Column("content")]
- public string Content { get; set; }
+ public string Content { get; set; } = null!;
// Foreign key to the Blog
[Column("blog_id")]
public int BlogId { get; set; }
// Navigation property for the related blog
- public Blog Blog { get; set; }
+ public Blog Blog { get; set; } = null!;
}
public class BloggingContext : DbContext
diff --git a/src/Persistence/EfCoreTests/Optimistic_concurrency_with_ef_core.cs b/src/Persistence/EfCoreTests/Optimistic_concurrency_with_ef_core.cs
index 3a239de4e..17da6f3cc 100644
--- a/src/Persistence/EfCoreTests/Optimistic_concurrency_with_ef_core.cs
+++ b/src/Persistence/EfCoreTests/Optimistic_concurrency_with_ef_core.cs
@@ -20,6 +20,7 @@
namespace EfCoreTests;
[Collection("sqlserver")]
+[Trait("Category", "Flaky")]
public class Optimistic_concurrency_with_ef_core
{
private readonly ITestOutputHelper _output;
@@ -61,7 +62,7 @@ await dbContext.ConcurrencyTestSagas.AddAsync(new()
});
await dbContext.SaveChangesAsync();
- Should.ThrowAsync(() => host.InvokeMessageAndWaitAsync(new UpdateConcurrencyTestSaga(Guid.NewGuid(), "updated value")));
+ await Should.ThrowAsync(() => host.InvokeMessageAndWaitAsync(new UpdateConcurrencyTestSaga(Guid.NewGuid(), "updated value")));
}
}
@@ -86,7 +87,7 @@ public record UpdateConcurrencyTestSaga(Guid Id, string NewValue);
public class ConcurrencyTestSaga : Saga
{
public Guid Id { get; set; }
- public string Value { get; set; }
+ public string Value { get; set; } = null!;
public void Handle(UpdateConcurrencyTestSaga order, OptConcurrencyDbContext ctx)
{
// Fake 999 updates of the saga while this event is being handled
diff --git a/src/Persistence/EfCoreTests/OutboxedMessageHandler.cs b/src/Persistence/EfCoreTests/OutboxedMessageHandler.cs
index 7d1c7b02e..78e362eb6 100644
--- a/src/Persistence/EfCoreTests/OutboxedMessageHandler.cs
+++ b/src/Persistence/EfCoreTests/OutboxedMessageHandler.cs
@@ -9,7 +9,7 @@ public record OutboxedMessage
public class OutboxedMessageHandler
{
- private static TaskCompletionSource _source;
+ private static TaskCompletionSource _source = null!;
public static Task WaitForNextMessage()
{
diff --git a/src/Persistence/EfCoreTests/Sagas/EfCoreSagaHost.cs b/src/Persistence/EfCoreTests/Sagas/EfCoreSagaHost.cs
index 7d4b1c217..e4ce81e4f 100644
--- a/src/Persistence/EfCoreTests/Sagas/EfCoreSagaHost.cs
+++ b/src/Persistence/EfCoreTests/Sagas/EfCoreSagaHost.cs
@@ -14,7 +14,7 @@ namespace EfCoreTests.Sagas;
public class EfCoreSagaHost : ISagaHost
{
- private IHost _host;
+ private IHost _host = null!;
public IHost BuildHost()
{
@@ -42,7 +42,7 @@ public async Task LoadState(Guid id) where T : Saga
using var scope = _host.Services.CreateScope();
var session = scope.ServiceProvider.GetRequiredService();
- return await session.FindAsync(id);
+ return (await session.FindAsync(id))!;
}
public async Task LoadState(int id) where T : Saga
@@ -50,7 +50,7 @@ public async Task LoadState(int id) where T : Saga
using var scope = _host.Services.CreateScope();
var session = scope.ServiceProvider.GetRequiredService();
- return await session.FindAsync(id);
+ return (await session.FindAsync(id))!;
}
public async Task LoadState(long id) where T : Saga
@@ -58,7 +58,7 @@ public async Task LoadState(long id) where T : Saga
using var scope = _host.Services.CreateScope();
var session = scope.ServiceProvider.GetRequiredService();
- return await session.FindAsync(id);
+ return (await session.FindAsync(id))!;
}
public async Task LoadState(string id) where T : Saga
@@ -66,7 +66,7 @@ public async Task LoadState(string id) where T : Saga
using var scope = _host.Services.CreateScope();
var session = scope.ServiceProvider.GetRequiredService();
- return await session.FindAsync(id);
+ return (await session.FindAsync(id))!;
}
}
\ No newline at end of file
diff --git a/src/Persistence/EfCoreTests/SampleUsageWithAutoApplyTransactions.cs b/src/Persistence/EfCoreTests/SampleUsageWithAutoApplyTransactions.cs
index 9eb62a175..2ba69b9b2 100644
--- a/src/Persistence/EfCoreTests/SampleUsageWithAutoApplyTransactions.cs
+++ b/src/Persistence/EfCoreTests/SampleUsageWithAutoApplyTransactions.cs
@@ -41,7 +41,7 @@ public static async Task quickstart()
var builder = Host.CreateApplicationBuilder();
- var connectionString = builder.Configuration.GetConnectionString("sqlserver");
+ var connectionString = builder.Configuration.GetConnectionString("sqlserver")!;
// Register a DbContext or multiple DbContext types as normal
builder.Services.AddDbContext(
@@ -75,7 +75,7 @@ public static async Task quickstart2()
var builder = Host.CreateApplicationBuilder();
- var connectionString = builder.Configuration.GetConnectionString("sqlserver");
+ var connectionString = builder.Configuration.GetConnectionString("sqlserver")!;
builder.UseWolverine(opts =>
{
diff --git a/src/Persistence/EfCoreTests/eager_idempotency_with_non_wolverine_mapped_db_context.cs b/src/Persistence/EfCoreTests/eager_idempotency_with_non_wolverine_mapped_db_context.cs
index 516c7bc7a..aec1480e7 100644
--- a/src/Persistence/EfCoreTests/eager_idempotency_with_non_wolverine_mapped_db_context.cs
+++ b/src/Persistence/EfCoreTests/eager_idempotency_with_non_wolverine_mapped_db_context.cs
@@ -48,7 +48,7 @@ public async Task happy_path_eager_idempotency()
await dbContext.Database.CurrentTransaction!.CommitAsync();
var persisted = (await runtime.Storage.Admin.AllIncomingAsync()).Single(x => x.Id == envelope.Id);
- persisted.Data.Length.ShouldBe(0);
+ persisted.Data!.Length.ShouldBe(0);
persisted.Destination.ShouldBe(envelope.Destination);
persisted.MessageType.ShouldBe(envelope.MessageType);
persisted.Status.ShouldBe(EnvelopeStatus.Handled);
diff --git a/src/Persistence/EfCoreTests/end_to_end_efcore_persistence.cs b/src/Persistence/EfCoreTests/end_to_end_efcore_persistence.cs
index 99b9da626..e273b527f 100644
--- a/src/Persistence/EfCoreTests/end_to_end_efcore_persistence.cs
+++ b/src/Persistence/EfCoreTests/end_to_end_efcore_persistence.cs
@@ -111,7 +111,7 @@ private async Task
- loadItem(Guid id)
var context = nested.ServiceProvider.GetRequiredService();
var item = await context.Items.FindAsync(id);
- return item;
+ return item!;
}
private async Task saveItem(Item item)
@@ -128,8 +128,8 @@ public void service_registrations()
{
var container = Host.Services.GetRequiredService