From a734a56ca6597dacbea5c62311de2ddaca68cb95 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 07:38:16 +0300 Subject: [PATCH 01/14] fix indentation error in dev-ci file --- .github/workflows/dev-ci.yml | 70 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index fe28b2f..4ce87a1 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -8,42 +8,42 @@ on: workflow_dispatch: jobs: -unit-tests: - name: Unit Tests - runs-on: ubuntu-latest + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 + steps: + - name: Checkout + uses: actions/checkout@v6 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 - - name: Build test image - uses: docker/build-push-action@v7 - with: - context: . - file: Docker/Dockerfile.test - push: false - load: true - tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha,scope=test-image - cache-to: type=gha,mode=max,scope=test-image - - name: Run unit tests - run: | - mkdir -p ${{ github.workspace }}/test-results/unit - docker run --rm \ - -v ${{ github.workspace }}/test-results/unit:/app/test-results \ - socialmedia-test:${{ github.sha }} \ - --no-build \ - --filter "Category=Unit" \ - --logger "trx;LogFileName=unit-results.trx" \ - --results-directory /app/test-results + - name: Build test image + uses: docker/build-push-action@v7 + with: + context: . + file: Docker/Dockerfile.test + push: false + load: true + tags: socialmedia-test:${{ github.sha }} + cache-from: type=gha,scope=test-image + cache-to: type=gha,mode=max,scope=test-image + - name: Run unit tests + run: | + mkdir -p ${{ github.workspace }}/test-results/unit + docker run --rm \ + -v ${{ github.workspace }}/test-results/unit:/app/test-results \ + socialmedia-test:${{ github.sha }} \ + --no-build \ + --filter "Category=Unit" \ + --logger "trx;LogFileName=unit-results.trx" \ + --results-directory /app/test-results - - name: Publish unit test results - uses: dorny/test-reporter@v3 - if: always() - with: - name: Unit Test Results - path: test-results/unit/*.trx - reporter: dotnet-trx + - name: Publish unit test results + uses: dorny/test-reporter@v3 + if: always() + with: + name: Unit Test Results + path: test-results/unit/*.trx + reporter: dotnet-trx From 63dfd3b645b62ef33dd807dc8c8d5baef1f2529d Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 07:51:40 +0300 Subject: [PATCH 02/14] remove Ryuk from caching as testcontainers manages it --- .github/workflows/main-ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 77ed615..59cfb52 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -80,22 +80,19 @@ jobs: uses: actions/cache@v5 with: path: /tmp/docker-images - key: docker-images-${{ runner.os }}-mssql-2022-ryuk-0.14.0 + key: docker-images-${{ runner.os }}-mssql-2022-latest - name: Load cached images if: steps.cache-docker.outputs.cache-hit == 'true' run: | docker load < /tmp/docker-images/mssql.tar - docker load < /tmp/docker-images/ryuk.tar - name: Pull and save images if: steps.cache-docker.outputs.cache-hit != 'true' run: | docker pull mcr.microsoft.com/mssql/server:2022-latest - docker pull testcontainersofficial/ryuk:0.14.0 mkdir -p /tmp/docker-images docker save mcr.microsoft.com/mssql/server:2022-latest > /tmp/docker-images/mssql.tar - docker save testcontainersofficial/ryuk:0.14.0 > /tmp/docker-images/ryuk.tar - name: Run integration tests env: From 7656690c959a4f6dcc622afb7f9b00df66061882 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 08:15:52 +0300 Subject: [PATCH 03/14] remove the images cache steps --- .github/workflows/main-ci.yml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 59cfb52..e95b0c2 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -75,28 +75,7 @@ jobs: cache-from: type=gha,scope=test-image cache-to: type=gha,mode=max,scope=test-image - - name: Cache Testcontainers Docker images - id: cache-docker - uses: actions/cache@v5 - with: - path: /tmp/docker-images - key: docker-images-${{ runner.os }}-mssql-2022-latest - - - name: Load cached images - if: steps.cache-docker.outputs.cache-hit == 'true' - run: | - docker load < /tmp/docker-images/mssql.tar - - - name: Pull and save images - if: steps.cache-docker.outputs.cache-hit != 'true' - run: | - docker pull mcr.microsoft.com/mssql/server:2022-latest - mkdir -p /tmp/docker-images - docker save mcr.microsoft.com/mssql/server:2022-latest > /tmp/docker-images/mssql.tar - - name: Run integration tests - env: - TESTCONTAINERS_RYUK_DISABLED: "false" run: | mkdir -p ${{ github.workspace }}/test-results/integration docker run --rm \ From ff7cd21dca0f41aa4ef87eae686a4445065fb3b6 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 08:30:25 +0300 Subject: [PATCH 04/14] Update integration test configuration to use in-memory connection string at startup --- .../IntegrationTestWebAppFactory.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs index 7659e6b..abfbdc0 100644 --- a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs +++ b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -34,18 +35,28 @@ public class IntegrationTestWebAppFactory : WebApplicationFactory, IAsy protected override void ConfigureWebHost(IWebHostBuilder builder) { base.ConfigureWebHost(builder); + var testConnectionString = _msSqlContainer.GetConnectionString(); + + builder.ConfigureAppConfiguration((_, configurationBuilder) => + { + configurationBuilder.AddInMemoryCollection(new Dictionary + { + ["ConnectionStrings:sqlserverConnectionString"] = testConnectionString + }); + }); + builder.ConfigureTestServices(services => { services.RemoveAll(typeof(DbContextOptions)); services.AddDbContext(options => { - options.UseSqlServer(_msSqlContainer.GetConnectionString()); + options.UseSqlServer(testConnectionString); }); services.RemoveAll(typeof(IHostedService)); services.RemoveAll(typeof(ISqlConnectionFactory)); - services.AddSingleton(new SqlConnectionFactory(_msSqlContainer.GetConnectionString())); + services.AddSingleton(new SqlConnectionFactory(testConnectionString)); }); } From a2528184b17900392b880db56f3e65c8cded0b02 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 08:57:37 +0300 Subject: [PATCH 05/14] Refactor caching configuration in CI workflows and Dockerfile --- .github/workflows/dev-ci.yml | 4 ++-- .github/workflows/main-ci.yml | 8 ++++---- Docker/Dockerfile.test | 9 +++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index 4ce87a1..4b6a401 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -27,8 +27,8 @@ jobs: push: false load: true tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha,scope=test-image - cache-to: type=gha,mode=max,scope=test-image + cache-from: type=gha + cache-to: type=gha,mode=max - name: Run unit tests run: | mkdir -p ${{ github.workspace }}/test-results/unit diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index e95b0c2..d939572 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -31,8 +31,8 @@ jobs: push: false load: true tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha,scope=test-image - cache-to: type=gha,mode=max,scope=test-image + cache-from: type=gha + cache-to: type=gha,mode=max - name: Run unit tests run: | mkdir -p ${{ github.workspace }}/test-results/unit @@ -72,8 +72,8 @@ jobs: push: false load: true tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha,scope=test-image - cache-to: type=gha,mode=max,scope=test-image + cache-from: type=gha + cache-to: type=gha,mode=max - name: Run integration tests run: | diff --git a/Docker/Dockerfile.test b/Docker/Dockerfile.test index 6fef0a1..d4870fe 100644 --- a/Docker/Dockerfile.test +++ b/Docker/Dockerfile.test @@ -1,4 +1,5 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build + WORKDIR /app ENV NUGET_PACKAGES=/root/.nuget/packages @@ -13,14 +14,14 @@ COPY ./tests/SocialMedia.Application.UnitTests/*.csproj ./tests/SocialMedia.Ap COPY ./tests/SocialMedia.IntegrationTests/*.csproj ./tests/SocialMedia.IntegrationTests/ COPY ./SocialMedia.slnx . -RUN --mount=type=cache,id=nuget-http,target=/root/.local/share/NuGet/http-cache \ - --mount=type=cache,id=nuget-global,target=$NUGET_PACKAGES \ +RUN --mount=type=cache,target=/root/.local/share/NuGet/http-cache \ + --mount=type=cache,target=$NUGET_PACKAGES \ dotnet restore ./SocialMedia.slnx COPY . . -RUN --mount=type=cache,id=nuget-http,target=/root/.local/share/NuGet/http-cache \ - --mount=type=cache,id=nuget-global,target=$NUGET_PACKAGES \ +RUN --mount=type=cache,target=/root/.local/share/NuGet/http-cache \ + --mount=type=cache,target=$NUGET_PACKAGES \ dotnet build ./SocialMedia.slnx \ --no-restore \ -c Debug From 179e1db9312e66f5e78db41fe8a6a6c9ddbf800c Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 09:09:24 +0300 Subject: [PATCH 06/14] Set SQL connection string environment variable in integration test factory --- .../Infrastructure/IntegrationTestWebAppFactory.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs index abfbdc0..8744c21 100644 --- a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs +++ b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs @@ -26,11 +26,12 @@ namespace SocialMedia.IntegrationTests.Infrastructure; public class IntegrationTestWebAppFactory : WebApplicationFactory, IAsyncLifetime { + private const string SqlConnectionStringEnvKey = "ConnectionStrings__sqlserverConnectionString"; private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2022-latest") .WithCleanUp(true) .Build(); public HttpClient HttpClient { get; private set; } = null!; - private SqlConnection _dbConnection; + private SqlConnection _dbConnection = null!; private Respawner _respawner = null!; protected override void ConfigureWebHost(IWebHostBuilder builder) { @@ -63,6 +64,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) public async ValueTask InitializeAsync() { await _msSqlContainer.StartAsync(); + Environment.SetEnvironmentVariable(SqlConnectionStringEnvKey, _msSqlContainer.GetConnectionString()); HttpClient = CreateClient(); _dbConnection = new SqlConnection(_msSqlContainer.GetConnectionString()); await _dbConnection.OpenAsync(); @@ -88,5 +90,6 @@ public override async ValueTask DisposeAsync() await _dbConnection.DisposeAsync(); await base.DisposeAsync(); await _msSqlContainer.DisposeAsync(); + Environment.SetEnvironmentVariable(SqlConnectionStringEnvKey, null); } } From 7643fcd01a1a84cdda136fcb2fce160c87c0decc Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 09:11:59 +0300 Subject: [PATCH 07/14] Update Dockerfiles to remove --no-restore flag and set build configuration to Release --- Docker/Dockerfile.prod | 1 - Docker/Dockerfile.test | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Docker/Dockerfile.prod b/Docker/Dockerfile.prod index ed30be8..c6b765f 100644 --- a/Docker/Dockerfile.prod +++ b/Docker/Dockerfile.prod @@ -25,7 +25,6 @@ COPY . . RUN --mount=type=cache,id=nuget-http,target=/root/.local/share/NuGet/http-cache \ --mount=type=cache,id=nuget-global,target=$NUGET_PACKAGES \ dotnet build ./SocialMedia.slnx \ - --no-restore \ -c Release diff --git a/Docker/Dockerfile.test b/Docker/Dockerfile.test index d4870fe..d744f60 100644 --- a/Docker/Dockerfile.test +++ b/Docker/Dockerfile.test @@ -23,8 +23,7 @@ COPY . . RUN --mount=type=cache,target=/root/.local/share/NuGet/http-cache \ --mount=type=cache,target=$NUGET_PACKAGES \ dotnet build ./SocialMedia.slnx \ - --no-restore \ - -c Debug + -c Release ENTRYPOINT ["dotnet", "test"] CMD ["--no-build"] \ No newline at end of file From 2361abac7db2217a30090d6340583fa83b50e7d4 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 09:20:52 +0300 Subject: [PATCH 08/14] Refactor Dockerfile.test to streamline cache usage and revert build configuration to Debug --- Docker/Dockerfile.test | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Docker/Dockerfile.test b/Docker/Dockerfile.test index d744f60..7b3be78 100644 --- a/Docker/Dockerfile.test +++ b/Docker/Dockerfile.test @@ -14,16 +14,14 @@ COPY ./tests/SocialMedia.Application.UnitTests/*.csproj ./tests/SocialMedia.Ap COPY ./tests/SocialMedia.IntegrationTests/*.csproj ./tests/SocialMedia.IntegrationTests/ COPY ./SocialMedia.slnx . -RUN --mount=type=cache,target=/root/.local/share/NuGet/http-cache \ - --mount=type=cache,target=$NUGET_PACKAGES \ +RUN --mount=type=cache,target=$NUGET_PACKAGES \ dotnet restore ./SocialMedia.slnx COPY . . -RUN --mount=type=cache,target=/root/.local/share/NuGet/http-cache \ - --mount=type=cache,target=$NUGET_PACKAGES \ +RUN --mount=type=cache,target=$NUGET_PACKAGES \ dotnet build ./SocialMedia.slnx \ - -c Release + -c Debug ENTRYPOINT ["dotnet", "test"] CMD ["--no-build"] \ No newline at end of file From c1eb46727b5dc7ab10fabfabd2cabf49bfde99e0 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 09:33:23 +0300 Subject: [PATCH 09/14] Add appsettings.Testing.json for integration tests and update configuration to use it --- .../IntegrationTestWebAppFactory.cs | 5 +- .../appsettings.Testing.json | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 tests/SocialMedia.IntegrationTests/appsettings.Testing.json diff --git a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs index 8744c21..ee8cbed 100644 --- a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs +++ b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs @@ -40,10 +40,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) builder.ConfigureAppConfiguration((_, configurationBuilder) => { - configurationBuilder.AddInMemoryCollection(new Dictionary - { - ["ConnectionStrings:sqlserverConnectionString"] = testConnectionString - }); + configurationBuilder.AddJsonFile("appsettings.Testing.json", optional: false); }); builder.ConfigureTestServices(services => diff --git a/tests/SocialMedia.IntegrationTests/appsettings.Testing.json b/tests/SocialMedia.IntegrationTests/appsettings.Testing.json new file mode 100644 index 0000000..3de8abe --- /dev/null +++ b/tests/SocialMedia.IntegrationTests/appsettings.Testing.json @@ -0,0 +1,59 @@ +{ + "Serilog": { + "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.Seq"], + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "System": "Warning" + } + }, + "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext} - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "Seq", + "Args": { + "serverUrl": "http://social-seq:5341" + } + } + ] + }, + "ConnectionStrings": { + "sqlServerConnectionString": "Data Source=;Initial Catalog=SocialMedia;User ID=sa;Password=;Connect Timeout=30;Trust Server Certificate=True;Authentication=SqlPassword;" + }, + "jwt": { + "Issuer": "SocialMedia.WebApi", + "Audience": "SocialMedia.Frontend", + "Lifetime": 60, + "RefreshTokenLifetime": 120, + "SigningKey": "your-secure-signing-key" + }, + "email": { + "Smtp": "smtp.gmail.com", + "Port": 587, + "Username": "your-email@gmail.com", + "Password": "your-app-password", + "From": "your-email@gmail.com", + "BaseUrl": "https://localhost:5000", + "EmailVerificationPath": "/api/auth/verify-email?token={token}", + "PasswordResetPath": "/api/auth/reset-password?token={token}" + }, + "supabase": { + "Url": "https://test-supabase-url.supabase.co", + "Key": "test-supabase-key" + }, + "durations": { + "EmailVerificationTokenExpiryMinutes": 30, + "PasswordResetTokenExpiryMinutes": 30 + }, + "FileUpload": { + "Provider": "Server" + } +} From baa851aa8ecc65c951cea7ae42c137e3bf5bd008 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 09:42:34 +0300 Subject: [PATCH 10/14] Add appsettings.Testing.json to project file for integration tests --- .../SocialMedia.IntegrationTests.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj b/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj index ff6358d..726f8de 100644 --- a/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj +++ b/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj @@ -26,4 +26,10 @@ + + + Always + + + From b7df4939f6fe57ec07a1362dd9349de77e160376 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 11:13:15 +0300 Subject: [PATCH 11/14] Add appsettings.Testing.json for integration tests and update configuration --- Docker/Dockerfile.test | 1 + src/SocialMedia.WebApi/SocialMedia.WebApi.csproj | 6 ++++-- .../SocialMedia.WebApi}/appsettings.Testing.json | 2 +- .../Infrastructure/IntegrationTestWebAppFactory.cs | 12 +++--------- .../SocialMedia.IntegrationTests.csproj | 6 ------ 5 files changed, 9 insertions(+), 18 deletions(-) rename {tests/SocialMedia.IntegrationTests => src/SocialMedia.WebApi}/appsettings.Testing.json (93%) diff --git a/Docker/Dockerfile.test b/Docker/Dockerfile.test index 7b3be78..fa933e9 100644 --- a/Docker/Dockerfile.test +++ b/Docker/Dockerfile.test @@ -3,6 +3,7 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app ENV NUGET_PACKAGES=/root/.nuget/packages +ENV ASPNETCORE_ENVIRONMENT=Testing COPY Directory.Packages.props . COPY Directory.Build.props . diff --git a/src/SocialMedia.WebApi/SocialMedia.WebApi.csproj b/src/SocialMedia.WebApi/SocialMedia.WebApi.csproj index 9307c6f..ed77b38 100644 --- a/src/SocialMedia.WebApi/SocialMedia.WebApi.csproj +++ b/src/SocialMedia.WebApi/SocialMedia.WebApi.csproj @@ -28,8 +28,10 @@ - - + + + + diff --git a/tests/SocialMedia.IntegrationTests/appsettings.Testing.json b/src/SocialMedia.WebApi/appsettings.Testing.json similarity index 93% rename from tests/SocialMedia.IntegrationTests/appsettings.Testing.json rename to src/SocialMedia.WebApi/appsettings.Testing.json index 3de8abe..a4c2594 100644 --- a/tests/SocialMedia.IntegrationTests/appsettings.Testing.json +++ b/src/SocialMedia.WebApi/appsettings.Testing.json @@ -33,7 +33,7 @@ "Audience": "SocialMedia.Frontend", "Lifetime": 60, "RefreshTokenLifetime": 120, - "SigningKey": "your-secure-signing-key" + "SigningKey": "your-secure-signing-key-for-jwt-tokensaklhg" }, "email": { "Smtp": "smtp.gmail.com", diff --git a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs index ee8cbed..3eb3e96 100644 --- a/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs +++ b/tests/SocialMedia.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs @@ -26,7 +26,6 @@ namespace SocialMedia.IntegrationTests.Infrastructure; public class IntegrationTestWebAppFactory : WebApplicationFactory, IAsyncLifetime { - private const string SqlConnectionStringEnvKey = "ConnectionStrings__sqlserverConnectionString"; private readonly MsSqlContainer _msSqlContainer = new MsSqlBuilder("mcr.microsoft.com/mssql/server:2022-latest") .WithCleanUp(true) .Build(); @@ -38,11 +37,6 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) base.ConfigureWebHost(builder); var testConnectionString = _msSqlContainer.GetConnectionString(); - builder.ConfigureAppConfiguration((_, configurationBuilder) => - { - configurationBuilder.AddJsonFile("appsettings.Testing.json", optional: false); - }); - builder.ConfigureTestServices(services => { services.RemoveAll(typeof(DbContextOptions)); @@ -61,9 +55,10 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) public async ValueTask InitializeAsync() { await _msSqlContainer.StartAsync(); - Environment.SetEnvironmentVariable(SqlConnectionStringEnvKey, _msSqlContainer.GetConnectionString()); + var testConnectionString = _msSqlContainer.GetConnectionString(); + HttpClient = CreateClient(); - _dbConnection = new SqlConnection(_msSqlContainer.GetConnectionString()); + _dbConnection = new SqlConnection(testConnectionString); await _dbConnection.OpenAsync(); _respawner = await Respawner.CreateAsync(_dbConnection, new RespawnerOptions { @@ -87,6 +82,5 @@ public override async ValueTask DisposeAsync() await _dbConnection.DisposeAsync(); await base.DisposeAsync(); await _msSqlContainer.DisposeAsync(); - Environment.SetEnvironmentVariable(SqlConnectionStringEnvKey, null); } } diff --git a/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj b/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj index 726f8de..ff6358d 100644 --- a/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj +++ b/tests/SocialMedia.IntegrationTests/SocialMedia.IntegrationTests.csproj @@ -26,10 +26,4 @@ - - - Always - - - From 97fc804efd6e4740f22fb3910924aa1fd237ba69 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 11:29:05 +0300 Subject: [PATCH 12/14] Refactor CI workflows to use .NET setup and streamline unit test execution --- .github/workflows/dev-ci.yml | 78 ++++++++++++++++++----------------- .github/workflows/main-ci.yml | 38 +++++++++-------- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index 4b6a401..0250454 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -9,41 +9,43 @@ on: jobs: unit-tests: - name: Unit Tests - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build test image - uses: docker/build-push-action@v7 - with: - context: . - file: Docker/Dockerfile.test - push: false - load: true - tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha - cache-to: type=gha,mode=max - - name: Run unit tests - run: | - mkdir -p ${{ github.workspace }}/test-results/unit - docker run --rm \ - -v ${{ github.workspace }}/test-results/unit:/app/test-results \ - socialmedia-test:${{ github.sha }} \ - --no-build \ - --filter "Category=Unit" \ - --logger "trx;LogFileName=unit-results.trx" \ - --results-directory /app/test-results - - - name: Publish unit test results - uses: dorny/test-reporter@v3 - if: always() - with: - name: Unit Test Results - path: test-results/unit/*.trx - reporter: dotnet-trx + name: Unit Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + - name: Cache NuGet packages + uses: actions/cache@v5 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore --configuration Release + + - name: Run unit tests + run: | + dotnet test --no-build --configuration Release \ + --filter "Category=Unit" \ + --logger "trx;LogFileName=test-results.trx" \ + --results-directory test-results/unit + + - name: Publish unit test results + uses: dorny/test-reporter@v3 + if: always() + with: + name: Unit Test Results + path: test-results/unit/*.trx + reporter: dotnet-trx diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index d939572..7bb3b2c 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -20,29 +20,31 @@ jobs: - name: Checkout uses: actions/checkout@v6 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x - - name: Build test image - uses: docker/build-push-action@v7 + - name: Cache NuGet packages + uses: actions/cache@v5 with: - context: . - file: Docker/Dockerfile.test - push: false - load: true - tags: socialmedia-test:${{ github.sha }} - cache-from: type=gha - cache-to: type=gha,mode=max + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore --configuration Release + - name: Run unit tests run: | - mkdir -p ${{ github.workspace }}/test-results/unit - docker run --rm \ - -v ${{ github.workspace }}/test-results/unit:/app/test-results \ - socialmedia-test:${{ github.sha }} \ - --no-build \ + dotnet test --no-build --configuration Release \ --filter "Category=Unit" \ - --logger "trx;LogFileName=unit-results.trx" \ - --results-directory /app/test-results + --logger "trx;LogFileName=test-results.trx" \ + --results-directory test-results/unit - name: Publish unit test results uses: dorny/test-reporter@v3 From 59b09d85e8bf702eb83ec6cb1039a52e7da79135 Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 11:32:19 +0300 Subject: [PATCH 13/14] fix indentation in dev-ci --- .github/workflows/dev-ci.yml | 80 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index 0250454..52af5fe 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -9,43 +9,43 @@ on: jobs: unit-tests: - name: Unit Tests - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Setup .NET - uses: actions/setup-dotnet@v5 - with: - dotnet-version: 10.0.x - - - name: Cache NuGet packages - uses: actions/cache@v5 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} - restore-keys: | - ${{ runner.os }}-nuget- - - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --no-restore --configuration Release - - - name: Run unit tests - run: | - dotnet test --no-build --configuration Release \ - --filter "Category=Unit" \ - --logger "trx;LogFileName=test-results.trx" \ - --results-directory test-results/unit - - - name: Publish unit test results - uses: dorny/test-reporter@v3 - if: always() - with: - name: Unit Test Results - path: test-results/unit/*.trx - reporter: dotnet-trx + name: Unit Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: 10.0.x + + - name: Cache NuGet packages + uses: actions/cache@v5 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} + restore-keys: | + ${{ runner.os }}-nuget- + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore --configuration Release + + - name: Run unit tests + run: | + dotnet test --no-build --configuration Release \ + --filter "Category=Unit" \ + --logger "trx;LogFileName=test-results.trx" \ + --results-directory test-results/unit + + - name: Publish unit test results + uses: dorny/test-reporter@v3 + if: always() + with: + name: Unit Test Results + path: test-results/unit/*.trx + reporter: dotnet-trx From 6c17b219b06f781a280e9b73c1a14a242c1df67f Mon Sep 17 00:00:00 2001 From: Mostafa Atef Date: Mon, 27 Apr 2026 12:43:55 +0300 Subject: [PATCH 14/14] Add deploy workflow for building and pushing Docker image --- .github/workflows/deploy.yml | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..c307f2f --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,49 @@ +name: Deploy + +on: + push: + branches: [main] + workflow_dispatch: + +env: + IMAGE_NAME: ${{ secrets.DOCKERHUB_USERNAME }}/socialmedia-webapi + +jobs: + build-and-push: + name: Build and Push Docker Image + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags & labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix=sha-,format=short + + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + file: Dockerfile.prod + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max