Skip to content

Commit

Permalink
More concurrency stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
sei-bstein committed Sep 10, 2024
1 parent dffffa6 commit daad59b
Show file tree
Hide file tree
Showing 31 changed files with 334 additions and 347 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public static HttpClient CreateHttpClientWithActingUser(this GameboardTestContex
.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });
}

public static HttpClient CreateHttpClientWithActingUser(this WebApplicationFactory<Program> webAppFactory, Action<TestAuthenticationUser>? userBuilder = null)
{
return webAppFactory
.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });
}

public static HttpClient CreateHttpClientWithAuthRole(this GameboardTestContext testContext, UserRole role)
=> CreateHttpClientWithActingUser(testContext, u => u.Role = role);

Expand All @@ -77,11 +83,15 @@ public static HttpClient CreateHttpClientWithGraderConfig(this GameboardTestCont

public static async Task WithDataState(this GameboardTestContext context, Action<IDataStateBuilder> builderAction)
{
using var dbContext = context.GetDbContext();
// get a context and prep the db
using var dbContext = context.GetValidationDbContext();
await dbContext.Database.MigrateAsync();

// seed requested data state
var builderInstance = new DataStateBuilder(dbContext);
builderAction.Invoke(builderInstance);

// save and go
await dbContext.SaveChangesAsync();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Testcontainers.PostgreSql;

namespace Gameboard.Api.Tests.Integration.Fixtures;
Expand All @@ -17,41 +18,49 @@ public class GameboardTestContext : WebApplicationFactory<Program>, IAsyncLifeti

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Test");
builder
.UseEnvironment("Test")
.ConfigureServices(services =>
{
if (_container is null)
throw new GbAutomatedTestSetupException("Couldn't initialize the test context - the database contianer hasn't been resolved.");
builder.ConfigureServices(services =>
{
if (_container is null)
throw new GbAutomatedTestSetupException("Couldn't initialize the test context - the database contianer hasn't been resolved.");
// Add DB context with connection to the container
services
.AddDbContext<GameboardDbContext, GameboardDbContextPostgreSQL>((serviceProvider, options) =>
{
options.UseNpgsql(_container.GetConnectionString());
options.UseGameboardEfConfig(serviceProvider);
}, ServiceLifetime.Transient);
// Add DB context with connection to the container
services
.AddDbContext<GameboardDbContext, GameboardDbContextPostgreSQL>(builder =>
{
builder.EnableDetailedErrors();
builder.EnableSensitiveDataLogging();
builder.UseNpgsql(_container.GetConnectionString());
}, ServiceLifetime.Transient);
services
// add user claims transformation that lets them all through
.ReplaceService<IClaimsTransformation, TestClaimsTransformation>(allowMultipleReplace: true)
services
// add user claims transformation that lets them all through
.ReplaceService<IClaimsTransformation, TestClaimsTransformation>(allowMultipleReplace: true)
// add a stand-in for external services
.ReplaceService<IExternalGameHostService, TestExternalGameHostService>()
.ReplaceService<IGameEngineService, TestGameEngineService>()
// add a stand-in for external services
.ReplaceService<IExternalGameHostService, TestExternalGameHostService>()
.ReplaceService<IGameEngineService, TestGameEngineService>()
// dummy authorization service that lets everything through
.ReplaceService<IAuthorizationService, TestAuthorizationService>()
// dummy authorization service that lets everything through
.ReplaceService<IAuthorizationService, TestAuthorizationService>()
// add defaults for services that are sometimes replaced in .ConfigureTestServices
.AddScoped<ITestGameEngineStateChangeService, TestGameEngineStateChangeService>()
.AddScoped<ITestGradingResultService>(_ => new TestGradingResultService(new TestGradingResultServiceConfiguration()));
});
}

// add defaults for services that are sometimes replaced in .ConfigureTestServices
.AddScoped<ITestGameEngineStateChangeService, TestGameEngineStateChangeService>()
.AddScoped<ITestGradingResultService>(_ => new TestGradingResultService(new TestGradingResultServiceConfiguration()));
});
public async Task ValidateStoreStateAsync(Func<GameboardDbContext, Task> validationAction)
{
using var scope = Services.CreateAsyncScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<GameboardDbContext>();
await validationAction.Invoke(dbContext);
}

public GameboardDbContext GetDbContext()
=> Services.GetRequiredService<GameboardDbContext>();
public GameboardDbContext GetValidationDbContext()
{
return this.Services.GetRequiredService<GameboardDbContext>();
}

public async Task InitializeAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ await _testContext

// then there should be no challenges assigned to a spec with the given gameId
var count = await _testContext
.GetDbContext()
.GetValidationDbContext()
.ChallengeBonuses
.AsNoTracking()
.Include(b => b.ChallengeSpec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ChallengeBonusControllerManualTests(GameboardTestContext testContex
public async Task AddManual_WithChallenge_Succeeds(string challengeId, string userId, string description, double pointsValue, IFixture fixture)
{
// given
var dbContext = _testContext.GetDbContext();
var dbContext = _testContext.GetValidationDbContext();
var bonuses = await dbContext.ManualBonuses.ToArrayAsync();

await _testContext.WithDataState(state =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@

namespace Gameboard.Api.Tests.Integration;

public class ChallengeControllerGradeAutoBonusTests : IClassFixture<GameboardTestContext>
public class ChallengeControllerGradeAutoBonusTests(GameboardTestContext testContext) : IClassFixture<GameboardTestContext>
{
private readonly GameboardTestContext _testContext;

public ChallengeControllerGradeAutoBonusTests(GameboardTestContext testContext)
{
_testContext = testContext;
}
private readonly GameboardTestContext _testContext = testContext;

[Theory, GbIntegrationAutoData]
public async Task Grade_WithSingleUnawardedSolveRankBonus_AwardsBonus
Expand Down Expand Up @@ -78,18 +73,20 @@ await _testContext

// tricky to validate this - the endpoint is pinned to returning a challenge state, which doesn't include bonuses yet.
// have to go to the DB to minimize false positives
var awardedBonus = await _testContext
.GetDbContext()
.AwardedChallengeBonuses
.Include(b => b.ChallengeBonus)
.Include(b => b.Challenge)
.AsNoTracking()
.FirstOrDefaultAsync(b => b.ChallengeId == challengeId);
await _testContext.ValidateStoreStateAsync(async db =>
{
var awardedBonus = await db
.AwardedChallengeBonuses
.Include(b => b.ChallengeBonus)
.Include(b => b.Challenge)
.AsNoTracking()
.FirstOrDefaultAsync(b => b.ChallengeId == challengeId);
// then
awardedBonus.ShouldNotBeNull();
awardedBonus.ChallengeBonus.PointValue.ShouldBe(bonusPoints);
awardedBonus.Challenge.Score.ShouldBe(baseScore);
// then
awardedBonus.ShouldNotBeNull();
awardedBonus.ChallengeBonus.PointValue.ShouldBe(bonusPoints);
awardedBonus.Challenge.Score.ShouldBe(baseScore);
});
}

[Theory, GbIntegrationAutoData]
Expand Down Expand Up @@ -121,15 +118,15 @@ await _testContext
spec.Id = challengeSpecId;
spec.GameId = gameId;
spec.Points = fullSolveScore;
spec.Bonuses = new List<Data.ChallengeBonus>
{
spec.Bonuses =
[
new ChallengeBonusCompleteSolveRank
{
Id = bonusId,
PointValue = bonus,
SolveRank = 1
}
};
];
}).ToCollection();
g.Challenges = state.Build<Data.Challenge>(fixture, c =>
Expand Down Expand Up @@ -160,7 +157,7 @@ await _testContext
// tricky to validate this - the endpoint is pinned to returning a challenge state, which doesn't include bonuses yet.
// have to go to the DB to minimize false positives
var awardedBonus = await _testContext
.GetDbContext()
.GetValidationDbContext()
.AwardedChallengeBonuses
.Include(b => b.ChallengeBonus)
.AsNoTracking()
Expand Down Expand Up @@ -201,8 +198,8 @@ await _testContext
spec.Id = challengeSpecId;
spec.GameId = gameId;
spec.Points = baseScore;
spec.Bonuses = new List<Data.ChallengeBonus>
{
spec.Bonuses =
[
state.Build<ChallengeBonusCompleteSolveRank>(fixture, cb =>
{
cb.Id = awardedBonusId;
Expand All @@ -214,12 +211,12 @@ await _testContext
cb.PointValue = unawardedBonusPoints;
cb.SolveRank = 2;
})
};
];
}).ToCollection();
// 2 teams, one with the first bonus already awarded
g.Players = new List<Data.Player>()
{
g.Players =
[
state.Build<Data.Player>(fixture, p =>
{
p.TeamId = awardedTeamId;
Expand All @@ -231,7 +228,7 @@ await _testContext
c.Points = baseScore;
c.Score = baseScore;
c.SpecId = challengeSpecId;
c.AwardedBonuses = state.Build<Data.AwardedChallengeBonus>(fixture, b => b.ChallengeBonusId = awardedBonusId).ToCollection();
c.AwardedBonuses = state.Build<AwardedChallengeBonus>(fixture, b => b.ChallengeBonusId = awardedBonusId).ToCollection();
c.TeamId = awardedTeamId;
}).ToCollection();
}),
Expand All @@ -252,7 +249,7 @@ await _testContext
c.TeamId = unawardedTeamId;
}).ToCollection();
})
};
];
});
});

Expand All @@ -263,11 +260,11 @@ await _testContext
await _testContext
.CreateHttpClientWithGraderConfig(baseScore, graderKey)
.PutAsync("/api/challenge/grade", submission.ToJsonBody())
.DeserializeResponseAs<Api.Challenge>();
.DeserializeResponseAs<Challenge>();

// tricky to validate this - the endpoint is pinned to returning a challenge state, which doesn't include bonuses yet.
// have to go to the DB to minimize false positives
var dbContext = _testContext.GetDbContext();
var dbContext = _testContext.GetValidationDbContext();
var awardedBonus = await dbContext
.AwardedChallengeBonuses
.Include(b => b.ChallengeBonus)
Expand Down
Loading

0 comments on commit daad59b

Please sign in to comment.