fixes the tests
All checks were successful
Dotnet build and test / build (pull_request) Successful in 7m35s
All checks were successful
Dotnet build and test / build (pull_request) Successful in 7m35s
This commit is contained in:
parent
1c2e1760b0
commit
e689dbfe35
11 changed files with 79 additions and 55 deletions
|
|
@ -8,11 +8,12 @@ using Microsoft.IdentityModel.Tokens;
|
|||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Tests.Shared;
|
||||
using Yavsc.Blogs.Tests.Fixtures;
|
||||
|
||||
namespace Yavsc.Blogs.Tests;
|
||||
|
||||
[Collection("JwtClaimMapping")]
|
||||
public sealed class BlogApiMappedClaimsTests :
|
||||
public sealed class BlogApiMappedClaimsTests :
|
||||
IClassFixture<MappedClaimsBlogsWebServerFixture>,
|
||||
IBackendFixture
|
||||
{
|
||||
|
|
@ -85,7 +86,10 @@ IBackendFixture
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var response = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft, TestContext.Current.CancellationToken);
|
||||
var response = await http.PostAsJsonAsync(
|
||||
_fixture.BlogSpotUrl(),
|
||||
draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
|
||||
var created = await response.Content.ReadFromJsonAsync<BlogPost>(TestContext.Current.CancellationToken);
|
||||
|
|
@ -99,7 +103,7 @@ IBackendFixture
|
|||
ResetDatabase();
|
||||
using var http = NewClient(subject: "mapped-owner");
|
||||
|
||||
var createdResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), new BlogPost
|
||||
var createdResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), new BlogPost
|
||||
{
|
||||
Id = 0,
|
||||
Title = "Billet à modifier",
|
||||
|
|
@ -113,7 +117,7 @@ IBackendFixture
|
|||
var created = await createdResponse.Content.ReadFromJsonAsync<BlogPost>(TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(created);
|
||||
|
||||
var updateResponse = await http.PutAsJsonAsync($"/api/v1/blog/{created!.Id}", new BlogPost
|
||||
var updateResponse = await http.PutAsJsonAsync(_fixture.BlogSpotUrl() + $"/{created!.Id}", new BlogPost
|
||||
{
|
||||
Id = created.Id,
|
||||
Title = "Billet modifié",
|
||||
|
|
@ -132,7 +136,7 @@ IBackendFixture
|
|||
ResetDatabase();
|
||||
using var ownerHttp = NewClient(subject: "mapped-owner");
|
||||
|
||||
var createdResponse = await ownerHttp.PostAsJsonAsync(_fixture.BlogUrl(), new BlogPost
|
||||
var createdResponse = await ownerHttp.PostAsJsonAsync(_fixture.BlogSpotUrl(), new BlogPost
|
||||
{
|
||||
Id = 0,
|
||||
Title = "Billet protégé",
|
||||
|
|
@ -147,7 +151,7 @@ IBackendFixture
|
|||
Assert.NotNull(created);
|
||||
|
||||
using var otherHttp = NewClient(subject: "mapped-other");
|
||||
var updateResponse = await otherHttp.PutAsJsonAsync($"/api/v1/blog/{created!.Id}", new BlogPost
|
||||
var updateResponse = await otherHttp.PutAsJsonAsync(_fixture.BlogSpotUrl() + $"/{created!.Id}", new BlogPost
|
||||
{
|
||||
Id = created.Id,
|
||||
Title = "Tentative de modification",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Yavsc.Models;
|
|||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Tests.Shared;
|
||||
using Yavsc.Blogs.Tests.Fixtures;
|
||||
|
||||
namespace Yavsc.Blogs.Tests;
|
||||
|
||||
|
|
@ -46,7 +47,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
_fixture.SeedUser("tester");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Build an authenticated client: a real
|
||||
/// <c>Authorization: Bearer <jwt></c> header where the JWT
|
||||
/// is signed by <see cref="TestTokenIssuer"/> and carries
|
||||
|
|
@ -94,7 +95,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
using var http = NewClient();
|
||||
|
||||
var response = await http.GetAsync(
|
||||
_fixture.BlogUrl(),
|
||||
_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
|
@ -127,7 +128,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, postResponse.StatusCode);
|
||||
|
||||
|
|
@ -140,7 +141,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
Assert.Equal(draft.Title, created.Title);
|
||||
|
||||
// The list should now contain exactly one entry.
|
||||
var listResponse = await http.GetAsync(_fixture.BlogUrl(),
|
||||
var listResponse = await http.GetAsync(_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
|
||||
|
||||
|
|
@ -168,7 +169,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, postResponse.StatusCode);
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
Assert.NotNull(created);
|
||||
Assert.Equal("tester", created!.AuthorId);
|
||||
|
||||
var listResponse = await http.GetAsync(_fixture.BlogUrl(),
|
||||
var listResponse = await http.GetAsync(_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
|
||||
|
||||
|
|
@ -206,7 +207,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, postResponse.StatusCode);
|
||||
|
||||
|
|
@ -255,7 +256,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
// the framework returns 401. This is the proof that the
|
||||
// production policy is wired in the test host and not
|
||||
// short-circuited by a test-only auth bypass.
|
||||
var response = await http.GetAsync(_fixture.BlogUrl(),
|
||||
var response = await http.GetAsync(_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
}
|
||||
|
|
@ -283,7 +284,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Created, postResponse.StatusCode);
|
||||
|
||||
|
|
@ -302,13 +303,13 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateCreated = created.DateCreated,
|
||||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
var putResponse = await http.PutAsJsonAsync(_fixture.BlogUrl()+$"/{created.Id}",
|
||||
var putResponse = await http.PutAsJsonAsync(_fixture.BlogSpotUrl()+$"/{created.Id}",
|
||||
update,
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.NoContent, putResponse.StatusCode);
|
||||
|
||||
// The list should now reflect the new title.
|
||||
var listResponse = await http.GetAsync(_fixture.BlogUrl(),
|
||||
var listResponse = await http.GetAsync(_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, listResponse.StatusCode);
|
||||
using var doc = JsonDocument.Parse(
|
||||
|
|
@ -336,19 +337,19 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateCreated = DateTime.UtcNow,
|
||||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var postResponse = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
var created = (await postResponse.Content.ReadFromJsonAsync<BlogPost>(
|
||||
TestContext.Current.CancellationToken
|
||||
))!;
|
||||
|
||||
var deleteResponse = await http.DeleteAsync(_fixture.BlogUrl()+$"/{created.Id}",
|
||||
var deleteResponse = await http.DeleteAsync(_fixture.BlogSpotUrl()+$"/{created.Id}",
|
||||
TestContext.Current.CancellationToken
|
||||
);
|
||||
Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode);
|
||||
|
||||
// The list should now be empty.
|
||||
var listResponse = await http.GetAsync(_fixture.BlogUrl(),
|
||||
var listResponse = await http.GetAsync(_fixture.BlogSpotUrl(),
|
||||
TestContext.Current.CancellationToken);
|
||||
String response = await listResponse.Content.ReadAsStringAsync(
|
||||
TestContext.Current.CancellationToken
|
||||
|
|
@ -391,7 +392,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var response = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var response = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
// Dump the body on failure so the test name + the response
|
||||
|
|
@ -436,7 +437,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
|||
DateModified = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var response = await http.PostAsJsonAsync(_fixture.BlogUrl(), draft,
|
||||
var response = await http.PostAsJsonAsync(_fixture.BlogSpotUrl(), draft,
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
if (response.StatusCode != HttpStatusCode.BadRequest)
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
namespace Yavsc.Blogs.Tests.Fixtures;
|
||||
|
||||
|
||||
public static class BlogHelpers
|
||||
{
|
||||
public static string BlogUrl(this IBackendFixture fixture)
|
||||
=> $"{fixture.Addresses.First(a => a.StartsWith("https://"))}/{Constants.APIPrefix}/{Constants.BlogSpotPath}";
|
||||
|
||||
public static string BlogAclUrl(this IBackendFixture fixture)
|
||||
=> $"{fixture.Addresses.First(a => a.StartsWith("https://"))}/{Constants.APIPrefix}/{Constants.BlogAclPath}";
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ namespace Yavsc.Blogs.Tests;
|
|||
/// This is the closest in-process reproduction of the production
|
||||
/// authentication surface for the blog API.
|
||||
/// </summary>
|
||||
public sealed class MappedClaimsBlogsWebServerFixture : IDisposable
|
||||
public sealed class MappedClaimsBlogsWebServerFixture : IDisposable, IBackendFixture
|
||||
{
|
||||
private readonly InMemoryDatabaseRoot _inMemoryRoot = new();
|
||||
private readonly Dictionary<string, string> _savedInboundMap;
|
||||
|
|
@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Tests.Shared;
|
||||
using Yavsc.Blogs.Tests.Fixtures;
|
||||
|
||||
namespace Yavsc.Blogs.Tests;
|
||||
|
||||
|
|
@ -71,12 +72,6 @@ public sealed class PublishEndpointTests : IClassFixture<BlogsWebServerFixture>
|
|||
return post.Id;
|
||||
}
|
||||
|
||||
private string PublishUrl(long id)
|
||||
=> $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/api/v1/blog/{id}/publish";
|
||||
|
||||
private string BlogsUrl
|
||||
=> _fixture.Addresses.First(a => a.StartsWith("https://")) + "/api/v1/blog";
|
||||
|
||||
private HttpClient NewClient(string subject)
|
||||
{
|
||||
var handler = new HttpClientHandler
|
||||
|
|
@ -100,12 +95,13 @@ public sealed class PublishEndpointTests : IClassFixture<BlogsWebServerFixture>
|
|||
var postId = SeedPost("alice");
|
||||
|
||||
using var http = NewClient("alice");
|
||||
var put = await http.PutAsJsonAsync(PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
var put = await http.PutAsJsonAsync(_fixture.PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.NoContent, put.StatusCode);
|
||||
|
||||
var get = await http.GetAsync($"{BlogsUrl}/{postId}", TestContext.Current.CancellationToken);
|
||||
var get = await http.GetAsync(_fixture.BlogSpotUrl() + $"/{postId}", TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, get.StatusCode);
|
||||
using var doc = JsonDocument.Parse(await get.Content.ReadAsStringAsync(TestContext.Current.CancellationToken));
|
||||
Assert.Equal($"post-by-alice", doc.RootElement.GetProperty("title").GetString());
|
||||
Assert.True(doc.RootElement.GetProperty("isPublished").GetBoolean());
|
||||
}
|
||||
|
||||
|
|
@ -116,11 +112,12 @@ public sealed class PublishEndpointTests : IClassFixture<BlogsWebServerFixture>
|
|||
var postId = SeedPost("alice");
|
||||
|
||||
using var http = NewClient("alice");
|
||||
await http.PutAsJsonAsync(PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
var put = await http.PutAsJsonAsync(PublishUrl(postId), new { publish = false }, TestContext.Current.CancellationToken);
|
||||
await http.PutAsJsonAsync(_fixture.PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
var put = await http.PutAsJsonAsync(_fixture.PublishUrl(postId), new { publish = false }, TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.NoContent, put.StatusCode);
|
||||
|
||||
var get = await http.GetAsync($"{BlogsUrl}/{postId}", TestContext.Current.CancellationToken);
|
||||
var get = await http.GetAsync(_fixture.BlogSpotUrl() + $"/{postId}", TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.OK, get.StatusCode);
|
||||
using var doc = JsonDocument.Parse(await get.Content.ReadAsStringAsync(TestContext.Current.CancellationToken));
|
||||
Assert.False(doc.RootElement.GetProperty("isPublished").GetBoolean());
|
||||
}
|
||||
|
|
@ -130,7 +127,7 @@ public sealed class PublishEndpointTests : IClassFixture<BlogsWebServerFixture>
|
|||
{
|
||||
ResetDatabase();
|
||||
using var http = NewClient("alice");
|
||||
var put = await http.PutAsJsonAsync(PublishUrl(99999L), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
var put = await http.PutAsJsonAsync(_fixture.PublishUrl(99999L), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.NotFound, put.StatusCode);
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +138,7 @@ public sealed class PublishEndpointTests : IClassFixture<BlogsWebServerFixture>
|
|||
var postId = SeedPost("alice");
|
||||
|
||||
using var http = NewClient("bob");
|
||||
var put = await http.PutAsJsonAsync(PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
var put = await http.PutAsJsonAsync(_fixture.PublishUrl(postId), new { publish = true }, TestContext.Current.CancellationToken);
|
||||
// 401 Challenge (the controller returns Challenge()
|
||||
// for AuthorizationFailureException). The exact code
|
||||
// is framework-dependent; what matters is "not 204".
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ public static class PayloadHelpers
|
|||
post.UserModified,
|
||||
post.AuthorId,
|
||||
ACL = post.GetACL(),
|
||||
Tags = post.GetTags()
|
||||
Tags = post.GetTags(),
|
||||
post.IsPublished
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
src/Yavsc.Tests.Shared/BlogHelpers.cs
Normal file
31
src/Yavsc.Tests.Shared/BlogHelpers.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
namespace Yavsc.Blogs.Tests.Fixtures;
|
||||
using static Yavsc.Constants;
|
||||
|
||||
public static class BlogHelpers
|
||||
{
|
||||
public static string ApiUrl(this IBackendFixture fixture, string apiSubPath)
|
||||
{
|
||||
var secured = fixture.Addresses.FirstOrDefault(a => a.StartsWith("https://"));
|
||||
if (secured is null)
|
||||
{
|
||||
var unsecured = fixture.Addresses.FirstOrDefault(a => a.StartsWith("http://"));
|
||||
if (unsecured is null)
|
||||
{
|
||||
throw new InvalidOperationException("No backend address found");
|
||||
}
|
||||
return $"{unsecured}/{APIPrefix}/{apiSubPath}";
|
||||
}
|
||||
return $"{secured}/{APIPrefix}/{apiSubPath}";
|
||||
}
|
||||
|
||||
public static string BlogAclUrl(this IBackendFixture fixture)
|
||||
=> fixture.ApiUrl(BlogAclPath);
|
||||
|
||||
public static string BlogSpotUrl(this IBackendFixture fixture)
|
||||
=> fixture.ApiUrl(BlogSpotPath);
|
||||
|
||||
public static string PublishUrl(this IBackendFixture fixture, long id)
|
||||
=> fixture.ApiUrl(BlogSpotPath) +"/" + id + "/publish";
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
using Yavsc.Blogs.Tests;
|
||||
|
||||
public interface IBackendFixture
|
||||
public interface IBackendFixture
|
||||
{
|
||||
/// <summary>
|
||||
/// The addresses the fixture bound to.
|
||||
|
|
@ -12,4 +10,4 @@ public interface IBackendFixture
|
|||
/// The service provider for the fixture host.
|
||||
/// </summary>
|
||||
IServiceProvider Services { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ namespace Yavsc.Tests.Shared;
|
|||
/// mapping are the responsibility of the subclass, through
|
||||
/// <see cref="BuildApp"/>.
|
||||
/// </summary>
|
||||
public abstract class WebHostFixture : IDisposable
|
||||
public abstract class WebHostFixture : IDisposable, IBackendFixture
|
||||
{
|
||||
private static readonly Lazy<X509Certificate2> _selfSignedCertificate =
|
||||
new Lazy<X509Certificate2>(CreateSelfSignedCertificate);
|
||||
|
|
|
|||
|
|
@ -23,4 +23,7 @@
|
|||
<PackageReference Include="Microsoft.IdentityModel.Tokens" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue