146 lines
5.0 KiB
C#
146 lines
5.0 KiB
C#
using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
|
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||
|
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||
|
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
|
|
||
|
|
using MongoDB.Entities;
|
||
|
|
|
||
|
|
using PrivaPub.Federation.Inbox;
|
||
|
|
using PrivaPub.Infrastructure.Jobs;
|
||
|
|
using PrivaPub.Models;
|
||
|
|
using PrivaPub.Models.Jobs;
|
||
|
|
using PrivaPub.Models.Post;
|
||
|
|
using PrivaPub.Tests.Support;
|
||
|
|
using PrivaPub.Tests.Support.Host;
|
||
|
|
|
||
|
|
using System.Net;
|
||
|
|
using System.Text.Json.Nodes;
|
||
|
|
|
||
|
|
namespace PrivaPub.Tests.Http
|
||
|
|
{
|
||
|
|
[Trait("Category", "Integration")]
|
||
|
|
public sealed class HostBootTests : IAsyncLifetime
|
||
|
|
{
|
||
|
|
PrivaPubHost _host;
|
||
|
|
|
||
|
|
public async ValueTask InitializeAsync()
|
||
|
|
{
|
||
|
|
Assert.SkipUnless(MongoFixture.Enabled, MongoFixture.Skip);
|
||
|
|
_host = await PrivaPubHost.Shared();
|
||
|
|
}
|
||
|
|
|
||
|
|
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task The_host_shares_the_fixture_database()
|
||
|
|
{
|
||
|
|
Assert.True(await DB.Default.Find<AppConfiguration>().ExecuteAnyAsync(TestContext.Current.CancellationToken));
|
||
|
|
using var client = _host.Client();
|
||
|
|
Assert.Equal(HttpStatusCode.OK, (await client.GetAsync("/build.json", TestContext.Current.CancellationToken)).StatusCode);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task The_harness_handles_the_same_activities_as_the_server()
|
||
|
|
{
|
||
|
|
await using var harness = await Harness.Start();
|
||
|
|
var registered = _host.Services.GetServices<IActivityHandler>().Select(h => h.GetType()).OrderBy(t => t.Name);
|
||
|
|
var harnessed = harness.Handlers.Select(h => h.GetType()).OrderBy(t => t.Name);
|
||
|
|
|
||
|
|
Assert.Equal(registered, harnessed);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Every_job_kind_has_exactly_one_handler()
|
||
|
|
{
|
||
|
|
var handlers = _host.Services.GetServices<IJobHandler>().GroupBy(h => h.Kind).ToDictionary(g => g.Key, g => g.Count());
|
||
|
|
|
||
|
|
foreach (var kind in Enum.GetValues<JobKind>())
|
||
|
|
Assert.True(handlers.GetValueOrDefault(kind) == 1, $"{kind} has {handlers.GetValueOrDefault(kind)} handlers");
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Every_controller_and_page_model_can_be_made()
|
||
|
|
{
|
||
|
|
using var scope = _host.Services.CreateScope();
|
||
|
|
var controllers = _host.Get<IActionDescriptorCollectionProvider>().ActionDescriptors.Items
|
||
|
|
.OfType<ControllerActionDescriptor>()
|
||
|
|
.Select(d => d.ControllerTypeInfo.AsType())
|
||
|
|
.Distinct()
|
||
|
|
.ToList();
|
||
|
|
var pages = typeof(Program).Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(PageModel)) && !t.IsAbstract).ToList();
|
||
|
|
|
||
|
|
Assert.NotEmpty(controllers);
|
||
|
|
Assert.NotEmpty(pages);
|
||
|
|
foreach (var type in controllers.Concat(pages))
|
||
|
|
Assert.NotNull(ActivatorUtilities.CreateInstance(scope.ServiceProvider, type));
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void The_service_graph_is_valid()
|
||
|
|
{
|
||
|
|
var services = new ServiceCollection();
|
||
|
|
foreach (var descriptor in _host.Registered)
|
||
|
|
((ICollection<ServiceDescriptor>)services).Add(descriptor);
|
||
|
|
|
||
|
|
using var provider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true, ValidateScopes = true });
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Swagger_is_not_served_outside_development()
|
||
|
|
{
|
||
|
|
using var client = _host.Client();
|
||
|
|
|
||
|
|
Assert.Equal(HttpStatusCode.NotFound, (await client.GetAsync("/swagger/index.html", TestContext.Current.CancellationToken)).StatusCode);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task A_persona_gets_a_mastodon_token_through_the_real_code_flow()
|
||
|
|
{
|
||
|
|
var root = await _host.SignUp();
|
||
|
|
var persona = await _host.Persona(root, "boot");
|
||
|
|
|
||
|
|
var token = await _host.MastodonToken(persona);
|
||
|
|
|
||
|
|
using var client = _host.As(token);
|
||
|
|
var account = await client.GetStringAsync("/api/v1/accounts/verify_credentials", TestContext.Current.CancellationToken);
|
||
|
|
Assert.Contains($"\"id\":\"{persona.Id}\"", account);
|
||
|
|
Assert.DoesNotContain(root.Id, account);
|
||
|
|
Assert.DoesNotContain(root.UserName, account);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task A_signed_delivery_through_the_real_route_is_queued_and_stored()
|
||
|
|
{
|
||
|
|
var token = TestContext.Current.CancellationToken;
|
||
|
|
await using var peer = await Peer.Start();
|
||
|
|
var persona = await _host.Persona(await _host.SignUp(), "mouth");
|
||
|
|
var bob = new RemoteActor(peer, "bob");
|
||
|
|
var noteId = $"{peer.A}/notes/{Guid.NewGuid():N}";
|
||
|
|
var activity = new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = noteId + "/activity",
|
||
|
|
["type"] = "Create",
|
||
|
|
["actor"] = bob.Id,
|
||
|
|
["to"] = new JsonArray($"{PrivaPubHost.Base}/peasants/{persona.UserName}"),
|
||
|
|
["object"] = new JsonObject
|
||
|
|
{
|
||
|
|
["id"] = noteId,
|
||
|
|
["type"] = "Note",
|
||
|
|
["attributedTo"] = bob.Id,
|
||
|
|
["to"] = new JsonArray($"{PrivaPubHost.Base}/peasants/{persona.UserName}"),
|
||
|
|
["content"] = "<p>hello through the front door</p>",
|
||
|
|
["published"] = DateTime.UtcNow.ToString("O")
|
||
|
|
}
|
||
|
|
};
|
||
|
|
using var client = _host.Client();
|
||
|
|
|
||
|
|
var response = await client.SendAsync(bob.SignedPost($"/peasants/{persona.UserName}/mouth", activity), token);
|
||
|
|
|
||
|
|
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
||
|
|
Assert.Equal(1, await _host.RunInbox(noteId + "/activity", token));
|
||
|
|
var stored = await DB.Default.Find<Post>().Match(p => p.ObjectURI == noteId).ExecuteFirstAsync(token);
|
||
|
|
Assert.Equal(PostVisibility.Direct, stored.Visibility);
|
||
|
|
Assert.Contains("front door", stored.ContentHtml);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|