feat(postit): migrate editable profile data and admin profile flow
This commit is contained in:
parent
f8c2a01ef4
commit
af1e572f32
38 changed files with 6573 additions and 19 deletions
|
|
@ -66,7 +66,14 @@ public sealed class ApiWebServerFixture : WebHostFixture
|
|||
builder.Services.Configure<GoogleAuthSettings>(_ => { });
|
||||
builder.Services.AddTransient<IBillingService, BillingService>();
|
||||
builder.Services.AddTransient<IYavscMessageSender, NoopMessageSender>();
|
||||
builder.Services.AddAuthorization();
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("AdministratorOnly", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireClaim(Yavsc.Constants.RoleClaimType, Yavsc.Constants.AdminGroupName);
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddAuthentication("Bearer")
|
||||
.AddJwtBearer("Bearer", options =>
|
||||
|
|
|
|||
124
src/test/Yavsc.Api.Tests/ResourceUsageApiControllerTests.cs
Normal file
124
src/test/Yavsc.Api.Tests/ResourceUsageApiControllerTests.cs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Yavsc.Abstract.Resources;
|
||||
using Yavsc.Api.Test.Fixtures;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Tests.Shared;
|
||||
|
||||
namespace Yavsc.Api.Test;
|
||||
|
||||
[Collection("Yavsc Api")]
|
||||
public sealed class ResourceUsageApiControllerTests : IClassFixture<ApiWebServerFixture>
|
||||
{
|
||||
private readonly ApiWebServerFixture _fixture;
|
||||
|
||||
public ResourceUsageApiControllerTests(ApiWebServerFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
private static HttpClient NewClient(ApiWebServerFixture fixture, string subject = "alice", string scope = "api", IEnumerable<Claim>? extraClaims = null)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
|
||||
};
|
||||
|
||||
var http = new HttpClient(handler)
|
||||
{
|
||||
BaseAddress = new Uri(fixture.BaseAddress)
|
||||
};
|
||||
|
||||
http.DefaultRequestHeaders.Authorization =
|
||||
new AuthenticationHeaderValue("Bearer", TestTokenIssuer.Issue(subject, scope, extraClaims: extraClaims));
|
||||
|
||||
return http;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCurrentUserUsage_persists_snapshot_in_database()
|
||||
{
|
||||
using var http = NewClient(_fixture, "alice");
|
||||
|
||||
var response = await http.GetAsync("/api/v1/resource-usage/me", TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var summary = await response.Content.ReadFromJsonAsync<ResourceUsageSummary>(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(summary);
|
||||
Assert.Equal("alice", summary!.UserId);
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<Yavsc.Models.ApplicationDbContext>();
|
||||
Assert.Contains(db.ResourceUsageRecords, r => r.UserId == "alice");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecordAsync_persists_cpu_and_storage_usage()
|
||||
{
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<Yavsc.Models.ApplicationDbContext>();
|
||||
|
||||
await ResourceUsageTracker.RecordAsync(
|
||||
db,
|
||||
"alice",
|
||||
"alice",
|
||||
cpuSeconds: 1.5m,
|
||||
storageBytes: 2 * 1024 * 1024,
|
||||
actorUserId: "alice");
|
||||
|
||||
var record = await db.ResourceUsageRecords
|
||||
.SingleAsync(r => r.UserId == "alice");
|
||||
|
||||
Assert.True(record.CpuSeconds >= 1.5m);
|
||||
Assert.True(record.StorageMb >= 2m / 1024m / 1024m);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecordAsync_persists_api_and_bandwidth_usage()
|
||||
{
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<Yavsc.Models.ApplicationDbContext>();
|
||||
|
||||
await ResourceUsageTracker.RecordAsync(
|
||||
db,
|
||||
"telemetry-user",
|
||||
"telemetry-user",
|
||||
apiCalls: 2m,
|
||||
bandwidthMb: 3.5m,
|
||||
actorUserId: "telemetry-user");
|
||||
|
||||
var record = await db.ResourceUsageRecords
|
||||
.SingleAsync(r => r.UserId == "telemetry-user");
|
||||
|
||||
Assert.True(record.ApiCalls >= 2m);
|
||||
Assert.True(record.BandwidthMb >= 3.5m);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAdminOverview_returns_latest_usage_snapshot_for_each_user()
|
||||
{
|
||||
using var http = NewClient(_fixture, "alice");
|
||||
var first = await http.GetAsync("/api/v1/resource-usage/me", TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, first.StatusCode);
|
||||
|
||||
using var adminHttp = NewClient(
|
||||
_fixture,
|
||||
"admin-user",
|
||||
"api",
|
||||
new[]
|
||||
{
|
||||
new Claim(Yavsc.Constants.RoleClaimType, Yavsc.Constants.AdminGroupName)
|
||||
});
|
||||
|
||||
var response = await adminHttp.GetAsync("/api/v1/resource-usage/admin", TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<List<ResourceUsageSummary>>(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(payload);
|
||||
Assert.Contains(payload!, item => item.UserId == "alice");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue