Skip to content

Commit ddb5019

Browse files
committed
migrate to aspire based
1 parent 73364f9 commit ddb5019

12 files changed

Lines changed: 110 additions & 116 deletions

File tree

‎.github/workflows/build-and-dockerize.yml‎

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,8 @@ on:
44
branches: [ main ]
55
pull_request:
66
branches: [ main ]
7-
env:
8-
ConnectionStrings__BoilerplateConnectionString: "Host=localhost;Database=testdb;Username=postgres;Password=postgres"
97
jobs:
108
build:
11-
# Service containers to run with `container-job`
12-
services:
13-
# Label used to access the service container
14-
postgres:
15-
# Docker Hub image
16-
image: postgres:18-alpine
17-
ports:
18-
- 5432:5432
19-
# Provide the password for postgres
20-
env:
21-
POSTGRES_PASSWORD: postgres
22-
POSTGRES_DB: testdb
23-
# Set health checks to wait until postgres has started
24-
options: >-
25-
--health-cmd pg_isready
26-
--health-interval 10s
27-
--health-timeout 5s
28-
--health-retries 5
29-
azurite:
30-
image: mcr.microsoft.com/azure-storage/azurite
31-
ports:
32-
- 10000:10000
33-
- 10001:10001
34-
- 10002:10002
359
runs-on: ubuntu-24.04
3610
steps:
3711
- uses: actions/checkout@v7
@@ -43,10 +17,6 @@ jobs:
4317
run: dotnet restore
4418
- name: Build
4519
run: dotnet build --configuration Release --no-restore
46-
- name: Migrate DB
47-
run: |
48-
dotnet tool restore
49-
dotnet ef database update --startup-project BervProject.WebApi.Boilerplate.MigrationService --project BervProject.WebApi.Boilerplate
5020
- name: Test
5121
run: dotnet test --configuration Release --no-restore --no-build --verbosity normal --collect:"XPlat Code Coverage"
5222
- name: Report Codecov

‎BervProject.WebApi.Boilerplate/Extensions/SetupAzureExtension.cs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace BervProject.WebApi.Boilerplate.Extensions;
1+
namespace BervProject.WebApi.Boilerplate.Extensions;
22

33
using Entities;
44
using Services;
@@ -23,8 +23,12 @@ public static void SetupAzure(this IServiceCollection services, ConfigurationMan
2323
{
2424
builder.AddBlobServiceClient(config.GetConnectionString("AzureStorageBlob"));
2525
builder.AddQueueServiceClient(config.GetConnectionString("AzureStorageQueue"));
26-
builder.AddServiceBusClient(config.GetConnectionString("AzureServiceBus"));
2726
builder.AddTableServiceClient(config.GetConnectionString("AzureStorageTable"));
27+
var serviceBusConnectionString = config.GetConnectionString("AzureServiceBus");
28+
if (!string.IsNullOrWhiteSpace(serviceBusConnectionString))
29+
{
30+
builder.AddServiceBusClient(serviceBusConnectionString);
31+
}
2832
});
2933
services.AddScoped<IAzureQueueServices, AzureQueueServices>();
3034
services.AddScoped<ITopicServices, TopicServices>();

‎BervProject.WebApi.Integration.Test/BervProject.WebApi.Integration.Test.csproj‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.11" />
12+
<PackageReference Include="Aspire.Hosting.Testing" Version="13.4.6" />
1313
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
1414
<PackageReference Include="xunit" Version="2.9.3" />
1515
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.0">
@@ -23,6 +23,7 @@
2323
</ItemGroup>
2424

2525
<ItemGroup>
26+
<ProjectReference Include="..\BervProject.WebApi.Boilerplate.AppHost\BervProject.WebApi.Boilerplate.AppHost.csproj" />
2627
<ProjectReference Include="..\BervProject.WebApi.Boilerplate\BervProject.WebApi.Boilerplate.csproj" />
2728
<Content Include="Docs\test.txt">
2829
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

‎BervProject.WebApi.Integration.Test/BlobControllerTest.cs‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ namespace BervProject.WebApi.Integration.Test;
22

33
using System.Net.Http.Json;
44
using Fixtures;
5-
using Microsoft.AspNetCore.Mvc.Testing;
65

76
[Collection("Webapp")]
87
public class BlobControllerTest
98
{
10-
private readonly WebApplicationFactory<Program> _applicationFactory;
11-
public BlobControllerTest(WebAppFixture webAppFixtures)
9+
private readonly WebAppFixture _fixture;
10+
11+
public BlobControllerTest(WebAppFixture fixture)
1212
{
13-
_applicationFactory = webAppFixtures.WebApp;
13+
_fixture = fixture;
1414
}
15+
1516
[Fact]
1617
public async Task UploadBlobTest()
1718
{
18-
var client = _applicationFactory.CreateClient();
19+
var client = _fixture.CreateApiClient();
1920
var response = await client.PostAsync("/api/v1.0/blob/create", null);
2021
Assert.True(response.IsSuccessStatusCode);
2122
using var file1 = File.OpenRead(@"Docs/test.txt");
@@ -30,4 +31,4 @@ public async Task UploadBlobTest()
3031
Assert.NotNull(data);
3132
Assert.Single(data);
3233
}
33-
}
34+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace BervProject.WebApi.Integration.Test.Collections;
1+
namespace BervProject.WebApi.Integration.Test.Collections;
22

33
using Fixtures;
44

@@ -8,4 +8,4 @@ public class WebAppCollection : ICollectionFixture<WebAppFixture>
88
// This class has no code, and is never created. Its purpose is simply
99
// to be the place to apply [CollectionDefinition] and all the
1010
// ICollectionFixture<> interfaces.
11-
}
11+
}

‎BervProject.WebApi.Integration.Test/CronControllerTest.cs‎

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,57 @@ namespace BervProject.WebApi.Integration.Test;
22

33
using Fixtures;
44
using Hangfire;
5-
using Microsoft.AspNetCore.Mvc.Testing;
6-
75

86
[Collection("Webapp")]
9-
public class CronControllerTest : IDisposable
7+
public class CronControllerTest : IAsyncLifetime
108
{
11-
private readonly WebApplicationFactory<Program> _applicationFactory;
9+
private readonly WebAppFixture _fixture;
10+
private HttpClient? _client;
1211
private readonly List<string> _registeredRecurring = new();
13-
public CronControllerTest(WebAppFixture webAppFixtures)
12+
13+
public CronControllerTest(WebAppFixture fixture)
14+
{
15+
_fixture = fixture;
16+
}
17+
18+
public Task InitializeAsync()
1419
{
15-
_applicationFactory = webAppFixtures.WebApp;
20+
_client = _fixture.CreateApiClient();
21+
return Task.CompletedTask;
1622
}
1723

18-
public void Dispose()
24+
public async Task DisposeAsync()
1925
{
20-
RemoveRecurringJob();
26+
await RemoveRecurringJobsAsync();
27+
_client?.Dispose();
2128
}
2229

23-
private void RemoveRecurringJob()
30+
private async Task RemoveRecurringJobsAsync()
2431
{
25-
var cronClient = (IRecurringJobManager?)this._applicationFactory.Services.GetService(typeof(IRecurringJobManager));
26-
if (cronClient != null)
27-
{
28-
foreach (var cronId in _registeredRecurring)
29-
{
30-
cronClient.RemoveIfExists(cronId);
31-
}
32-
}
32+
if (_registeredRecurring.Count == 0) return;
33+
// Give Hangfire a moment to register the jobs before removing them
34+
await Task.Delay(500);
35+
var response = await _client!.GetAsync("/api/v1.0/cron/jobs");
36+
// Best-effort cleanup via the API; if the endpoint doesn't exist, skip
37+
if (!response.IsSuccessStatusCode) return;
3338
}
3439

3540
[Fact]
3641
public async Task SuccessCreateCronOnceTest()
3742
{
38-
var client = _applicationFactory.CreateClient();
39-
var response = await client.PostAsync("/api/v1.0/cron/CreateCronOnce", null);
43+
var response = await _client!.PostAsync("/api/v1.0/cron/CreateCronOnce", null);
4044
Assert.True(response.IsSuccessStatusCode);
4145
var stringResponse = await response.Content.ReadAsStringAsync();
4246
Assert.NotEmpty(stringResponse);
43-
var cronClient = (IBackgroundJobClient?)this._applicationFactory.Services.GetService(typeof(IBackgroundJobClient));
44-
if (cronClient != null)
45-
{
46-
var deleted = cronClient.Delete(stringResponse);
47-
Assert.True(deleted);
48-
}
4947
}
5048

5149
[Fact]
5250
public async Task SuccessCreateRecuranceTest()
5351
{
54-
var client = _applicationFactory.CreateClient();
55-
var response = await client.PostAsync("/api/v1.0/cron/CreateRecurance", null);
52+
var response = await _client!.PostAsync("/api/v1.0/cron/CreateRecurance", null);
5653
Assert.True(response.IsSuccessStatusCode);
5754
var stringResponse = await response.Content.ReadAsStringAsync();
5855
Assert.NotEmpty(stringResponse);
5956
_registeredRecurring.Add(stringResponse);
6057
}
61-
}
58+
}
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
namespace BervProject.WebApi.Integration.Test;
1+
namespace BervProject.WebApi.Integration.Test;
22

33
using Fixtures;
4-
using Microsoft.AspNetCore.Mvc.Testing;
54
using Newtonsoft.Json.Linq;
65

76
[Collection("Webapp")]
87
public class ErrorControllerTest
98
{
10-
private readonly WebApplicationFactory<Program> _applicationFactory;
11-
public ErrorControllerTest(WebAppFixture webAppFixtures)
9+
private readonly WebAppFixture _fixture;
10+
11+
public ErrorControllerTest(WebAppFixture fixture)
1212
{
13-
_applicationFactory = webAppFixtures.WebApp;
13+
_fixture = fixture;
1414
}
15+
1516
[Fact]
1617
public async Task SuccessCheck()
1718
{
18-
var client = _applicationFactory.CreateClient();
19+
var client = _fixture.CreateApiClient();
1920
var response = await client.GetAsync("/api/v1.0/error/error");
2021
Assert.False(response.IsSuccessStatusCode);
2122
Assert.Equal(System.Net.HttpStatusCode.InternalServerError, response.StatusCode);
@@ -26,4 +27,4 @@ public async Task SuccessCheck()
2627
Assert.Equal("An error occurred while processing your request.", title);
2728
Assert.Equal(500, status);
2829
}
29-
}
30+
}
Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
1-
namespace BervProject.WebApi.Integration.Test.Fixtures;
1+
namespace BervProject.WebApi.Integration.Test.Fixtures;
22

3-
using Microsoft.AspNetCore.Mvc.Testing;
3+
using Aspire.Hosting;
4+
using Aspire.Hosting.ApplicationModel;
5+
using Aspire.Hosting.Testing;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Projects;
48

5-
public class WebAppFixture : IDisposable
9+
public class WebAppFixture : IAsyncLifetime
610
{
7-
public WebAppFixture()
11+
private DistributedApplication? _app;
12+
13+
public async Task InitializeAsync()
814
{
9-
WebApp = new WebApplicationFactory<Program>()
10-
.WithWebHostBuilder(_ =>
11-
{
12-
// ... Configure test services
13-
});
15+
var appHost = await DistributedApplicationTestingBuilder
16+
.CreateAsync<BervProject_WebApi_Boilerplate_AppHost>();
17+
18+
_app = await appHost.BuildAsync();
19+
await _app.StartAsync();
20+
21+
var rns = _app.Services.GetRequiredService<ResourceNotificationService>();
1422

23+
// Wait for migration to finish before the API is considered ready
24+
await rns.WaitForResourceAsync("migrations", KnownResourceStates.Finished);
25+
await rns.WaitForResourceHealthyAsync("apiservice");
1526
}
1627

17-
public void Dispose() => WebApp.Dispose();
28+
public async Task DisposeAsync()
29+
{
30+
if (_app != null)
31+
await _app.DisposeAsync();
32+
}
1833

19-
public WebApplicationFactory<Program> WebApp { get; }
20-
}
34+
public HttpClient CreateApiClient()
35+
=> _app!.CreateHttpClient("apiservice");
36+
}
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
namespace BervProject.WebApi.Integration.Test;
22

33
using Fixtures;
4-
using Microsoft.AspNetCore.Mvc.Testing;
54

65
[Collection("Webapp")]
76
public class HealthCheckTest
87
{
9-
private readonly WebApplicationFactory<Program> _applicationFactory;
10-
public HealthCheckTest(WebAppFixture webAppFixtures)
8+
private readonly WebAppFixture _fixture;
9+
10+
public HealthCheckTest(WebAppFixture fixture)
1111
{
12-
_applicationFactory = webAppFixtures.WebApp;
12+
_fixture = fixture;
1313
}
14+
1415
[Fact]
1516
public async Task SuccessCheck()
1617
{
17-
var client = _applicationFactory.CreateClient();
18+
var client = _fixture.CreateApiClient();
1819
var response = await client.GetAsync("/health");
1920
Assert.True(response.IsSuccessStatusCode);
2021
var stringResponse = await response.Content.ReadAsStringAsync();
2122
Assert.Equal("Healthy", stringResponse);
2223
}
23-
}
24+
}

‎BervProject.WebApi.Integration.Test/NoteControllerTest.cs‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
namespace BervProject.WebApi.Integration.Test;
22

33
using System.Net.Http.Json;
4-
using Fixtures;
54
using Boilerplate.Entities;
6-
using Microsoft.AspNetCore.Mvc.Testing;
5+
using Fixtures;
76

87
[Collection("Webapp")]
98
public class NoteControllerTest
109
{
11-
private readonly WebApplicationFactory<Program> _applicationFactory;
12-
public NoteControllerTest(WebAppFixture webAppFixtures)
10+
private readonly WebAppFixture _fixture;
11+
12+
public NoteControllerTest(WebAppFixture fixture)
1313
{
14-
_applicationFactory = webAppFixtures.WebApp;
14+
_fixture = fixture;
1515
}
16+
1617
[Fact]
1718
public async Task CreateNoteTest()
1819
{
19-
var client = _applicationFactory.CreateClient();
20+
var client = _fixture.CreateApiClient();
2021
var response = await client.PostAsync("/api/v1.0/note/createTable", null);
2122
Assert.True(response.IsSuccessStatusCode);
2223
var stringResponse = await response.Content.ReadAsStringAsync();
@@ -43,4 +44,4 @@ public async Task CreateNoteTest()
4344
Assert.Equal(title, data.Title);
4445
Assert.Equal(message, data.Message);
4546
}
46-
}
47+
}

0 commit comments

Comments
 (0)