summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2026-06-19 08:59:16 +0200
committerRory& <root@rory.gay>2026-06-19 08:59:16 +0200
commitfefc571558883d4a878565ec9f92356606d2816f (patch)
tree733c104ca787143fe3a23db308df4ebd3e9b6f92
parentUpdate basic deps (diff)
downloadserver-ts-fefc571558883d4a878565ec9f92356606d2816f.tar.xz
More tests
-rw-r--r--extra/admin-api/Interop/Spacebar.Interop.Authentication/deps.json16
-rw-r--r--extra/admin-api/Models/Spacebar.Models.Api/TypingResponse.cs23
-rw-r--r--extra/admin-api/Spacebar.Cdn.Worker/DiscordImageResizeService.cs6
-rw-r--r--extra/admin-api/Spacebar.Cdn.Worker/Program.cs2
-rw-r--r--extra/admin-api/Tests/Spacebar.Tests/Spacebar.Tests.csproj1
-rw-r--r--extra/admin-api/Tests/Spacebar.Tests/Tests/ChannelTests.cs31
-rw-r--r--extra/admin-api/Tests/Spacebar.Tests/Tests/DMTests.cs84
-rw-r--r--extra/admin-api/Tests/Spacebar.Tests/Tests/GuildTests.cs28
-rw-r--r--extra/admin-api/Utilities/Spacebar.Sdk/Core/SpacebarClient.cs14
-rw-r--r--extra/admin-api/Utilities/Spacebar.Sdk/Spacebar.Sdk.csproj5
-rwxr-xr-xscripts/validateImports.cs43
11 files changed, 231 insertions, 22 deletions
diff --git a/extra/admin-api/Interop/Spacebar.Interop.Authentication/deps.json b/extra/admin-api/Interop/Spacebar.Interop.Authentication/deps.json

index 85c76a7b..89c9ffe6 100644 --- a/extra/admin-api/Interop/Spacebar.Interop.Authentication/deps.json +++ b/extra/admin-api/Interop/Spacebar.Interop.Authentication/deps.json
@@ -1,13 +1,13 @@ [ { "pname": "ArcaneLibs", - "version": "1.0.1-preview.20260420-212318", - "hash": "sha256-y+gU8S3jbcFgIwwc0vkkEPMfHzGZ+55//9uvsKOEGXY=" + "version": "1.0.1-preview.20260619-035441", + "hash": "sha256-jNEGd8Ccgkk4A8ZMaJO4QDExmsf9q7TeuhiNESos3Q4=" }, { "pname": "BCrypt.Net-Next", - "version": "4.1.0", - "hash": "sha256-Efjrsw4FXgVKA2vQV6ztc40pLsonnV3JxwxW7eOyfDk=" + "version": "4.2.0", + "hash": "sha256-dqDg0iQQUjncCN+bIASlsrxt4oEfyg/JkPu34wSRpc4=" }, { "pname": "Microsoft.EntityFrameworkCore", @@ -141,13 +141,13 @@ }, { "pname": "Npgsql", - "version": "10.0.2", - "hash": "sha256-hW03ZWoW7y16vvScwsjZNyqFybGy+s6hQYQXebo78yQ=" + "version": "10.0.3", + "hash": "sha256-ddCXCSOoyfy7035OvnL+4LEDYqHjZyPoZ3ffG2coMW0=" }, { "pname": "Npgsql.EntityFrameworkCore.PostgreSQL", - "version": "10.0.1", - "hash": "sha256-G5WmWoc02gHTsdBLXESFQ5eMV+liwiO8YjzFKg4NDEk=" + "version": "10.0.2", + "hash": "sha256-JlJXttrCmPFUGVznTGl7hsfn9/BzKt91y/uLErDqQfY=" }, { "pname": "System.IdentityModel.Tokens.Jwt", diff --git a/extra/admin-api/Models/Spacebar.Models.Api/TypingResponse.cs b/extra/admin-api/Models/Spacebar.Models.Api/TypingResponse.cs
index e69de29b..99a1d115 100644 --- a/extra/admin-api/Models/Spacebar.Models.Api/TypingResponse.cs +++ b/extra/admin-api/Models/Spacebar.Models.Api/TypingResponse.cs
@@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace Spacebar.Models.Api; + +public class TypingResponse { + [JsonPropertyName("message_send_cooldown_ms")] + public int? MessageSendCooldownMilliseconds { get; set; } + + [JsonPropertyName("thread_create_cooldown_ms")] + public int? ThreadCreateCooldownMilliseconds { get; set; } + + [JsonIgnore] + public TimeSpan? MessageSendCooldown { + get => MessageSendCooldownMilliseconds is null ? null : TimeSpan.FromMilliseconds((long)MessageSendCooldownMilliseconds); + set => MessageSendCooldownMilliseconds = (int?)value?.TotalMilliseconds; + } + + [JsonIgnore] + public TimeSpan? ThreadCreateCooldown { + get => ThreadCreateCooldownMilliseconds is null ? null : TimeSpan.FromMilliseconds((long)ThreadCreateCooldownMilliseconds); + set => ThreadCreateCooldownMilliseconds = (int?)value?.TotalMilliseconds; + } +} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn.Worker/DiscordImageResizeService.cs b/extra/admin-api/Spacebar.Cdn.Worker/DiscordImageResizeService.cs
index 6509a0b6..5a70bfd6 100644 --- a/extra/admin-api/Spacebar.Cdn.Worker/DiscordImageResizeService.cs +++ b/extra/admin-api/Spacebar.Cdn.Worker/DiscordImageResizeService.cs
@@ -14,9 +14,10 @@ public class DiscordImageResizeParams { public bool SpacebarAllowUpscale { get; set; } = false; public bool SpacebarOptimiseGif { get; set; } = true; + public string Format { get; set; } = "webp"; public string ToSerializedName() { - return $"{(Animated ? "a_" : "")}{Size}px_{Quality.ToString()}_u.{SpacebarAllowUpscale}_o.{SpacebarOptimiseGif}"; + return $"{(Animated ? "a_" : "")}{Size}px_{Quality.ToString()}_u.{SpacebarAllowUpscale}_o.{SpacebarOptimiseGif}.{Format}"; } } @@ -33,6 +34,7 @@ public static class HttpRequestExtensions { Animated = request.Query.ContainsKey("animated") && bool.TryParse(request.Query["animated"], out bool an) && an, SpacebarAllowUpscale = request.Query.ContainsKey("allowUpscale") && bool.TryParse(request.Query["allowUpscale"], out bool au) && au, SpacebarOptimiseGif = request.Query.ContainsKey("optimiseGif") && bool.TryParse(request.Query["optimiseGif"], out bool og) && og, + Format = request.Query.ContainsKey("format") ? request.Query["format"]! : "webp", }; } } @@ -72,7 +74,7 @@ public class DiscordImageResizeService { if (!resizeParams.Animated) { var oldImg = img; - img = new MagickImageCollection([oldImg.First()]); + img = new MagickImageCollection([oldImg.First().Clone()]); oldImg.Dispose(); } diff --git a/extra/admin-api/Spacebar.Cdn.Worker/Program.cs b/extra/admin-api/Spacebar.Cdn.Worker/Program.cs
index 289b869b..60d2a447 100644 --- a/extra/admin-api/Spacebar.Cdn.Worker/Program.cs +++ b/extra/admin-api/Spacebar.Cdn.Worker/Program.cs
@@ -96,7 +96,7 @@ app.MapGet("/scale/{*path}", async (HttpContext ctx, IFileSource ifs, DiscordIma await mig.ReadAsync(f.Stream, ctx.RequestAborted); var res = await dirs.Apply(mig, ctx.Request.GetResizeParams()); await ctx.Response.StartAsync(); - await res.WriteAsync(ctx.Response.Body); + await res.WriteAsync(ctx.Response.Body, Mimes.GetFormatForExtension(ctx.Request.GetResizeParams().Format)); await ctx.Response.CompleteAsync(); }); diff --git a/extra/admin-api/Tests/Spacebar.Tests/Spacebar.Tests.csproj b/extra/admin-api/Tests/Spacebar.Tests/Spacebar.Tests.csproj
index b521b61c..508e160d 100644 --- a/extra/admin-api/Tests/Spacebar.Tests/Spacebar.Tests.csproj +++ b/extra/admin-api/Tests/Spacebar.Tests/Spacebar.Tests.csproj
@@ -10,6 +10,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="ArcaneLibs" Version="1.0.1-preview.20260619-035441" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.8" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" /> diff --git a/extra/admin-api/Tests/Spacebar.Tests/Tests/ChannelTests.cs b/extra/admin-api/Tests/Spacebar.Tests/Tests/ChannelTests.cs
index 0bae6d34..080a991e 100644 --- a/extra/admin-api/Tests/Spacebar.Tests/Tests/ChannelTests.cs +++ b/extra/admin-api/Tests/Spacebar.Tests/Tests/ChannelTests.cs
@@ -1,4 +1,5 @@ using System.Net.Http.Json; +using System.Text.Json.Nodes; using Spacebar.Models.Generic; using Spacebar.Sdk.Core; using Spacebar.Tests.Abstractions; @@ -53,4 +54,34 @@ public class ChannelTests(ITestOutputHelper testOutputHelper, TestFixture fixtur public async Task SendTyping() { await Assert.HttpSuccess(await Client.ApiHttpClient.PostAsync($"channels/{Channel!.Id}/typing", null, TestContext.Current.CancellationToken)); } + + [Fact] + public async Task UpdateChannel() { + var cg = Client.GetGuild(Guild.Id); + var nc = await cg.CreateChannelAsync(new() { + Name = "asdf", + Type = 0 + }); + + var res = await Assert.HttpSuccess(await Client.ApiHttpClient.PatchAsJsonAsync($"channels/{nc.Id}", new JsonObject() { + { "name", "hellorld" } + }, cancellationToken: TestContext.Current.CancellationToken)); + + var resC = await res.Content.ReadFromJsonAsync<Channel>(cancellationToken: TestContext.Current.CancellationToken); + Assert.Equal("hellorld", resC!.Name); + + var c = await Client.GetChannel(nc.Id).GetInfoAsync(); + Assert.Equal("hellorld", c.Name); + } + + [Fact] + public async Task DeleteChannel() { + var cg = Client.GetGuild(Guild.Id); + var c = await cg.CreateChannelAsync(new() { + Name = "asdf", + Type = 0 + }); + + await Assert.HttpSuccess(await Client.ApiHttpClient.DeleteAsync($"channels/{c.Id}", TestContext.Current.CancellationToken)); + } } \ No newline at end of file diff --git a/extra/admin-api/Tests/Spacebar.Tests/Tests/DMTests.cs b/extra/admin-api/Tests/Spacebar.Tests/Tests/DMTests.cs new file mode 100644
index 00000000..76f147d1 --- /dev/null +++ b/extra/admin-api/Tests/Spacebar.Tests/Tests/DMTests.cs
@@ -0,0 +1,84 @@ +using System.Net.Http.Json; +using System.Text.Json.Nodes; +using Spacebar.Models.Generic; +using Spacebar.Sdk.Core; +using Spacebar.Tests.Abstractions; +using Spacebar.Tests.Extensions; +using Spacebar.Tests.Fixtures; +using Xunit.Microsoft.DependencyInjection.Abstracts; + +namespace Spacebar.Tests.Tests; + +public class DmTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : TestBed<TestFixture>(testOutputHelper, fixture), IAsyncLifetime { + private readonly Config _config = fixture.GetRequiredService<Config>(testOutputHelper); + private readonly SpacebarClientWellKnownResolverService _wellKnownResolver = fixture.GetRequiredService<SpacebarClientWellKnownResolverService>(testOutputHelper); + private readonly SpacebarClientProviderService _clientProvider = fixture.GetRequiredService<SpacebarClientProviderService>(testOutputHelper); + private readonly UserAbstraction _userAbstraction = fixture.GetRequiredService<UserAbstraction>(testOutputHelper); + + private static AuthenticatedSpacebarClient Client { get; set; } = null!; + private static AuthenticatedSpacebarClient? Client2 { get; set; } = null!; + private static Channel? Channel { get; set; } + + public async ValueTask InitializeAsync() { + testOutputHelper.WriteLine("Running InitializeAsync"); + // All these tests can share a single client + Client = await _userAbstraction.GetSharedUser(); + Client2 ??= await _userAbstraction.GetFreshUser(); + // Channel ??= await Client.GetGuild(Guild.Id).CreateChannelAsync(new() { Name = "meow", Type = 0 }); + } + + // [Fact] + // public async Task CreateChannel() { + // Assert.Equal("Test guild", Guild!.Name); + // var channel = await Client!.GetGuild(Guild.Id).CreateChannelAsync(new() { + // Name = "test", + // Type = 0 // TODO: this should be the default + // }); + // + // Assert.Equal("test", channel.Name); + // } + // + // [Fact] + // public async Task GetChannel() { + // var res = await Assert.HttpSuccess(await Client.ApiHttpClient.GetAsync("channels/" + Channel.Id, TestContext.Current.CancellationToken)); + // + // var channelResp = await res.Content.ReadFromJsonAsync<Channel>(cancellationToken: TestContext.Current.CancellationToken); + // Assert.Equal(Channel.Name, channelResp!.Name); + // Assert.Equal(Channel.Id, channelResp!.Id); + // } + // + // [Fact] + // public async Task SendTyping() { + // await Assert.HttpSuccess(await Client.ApiHttpClient.PostAsync($"channels/{Channel!.Id}/typing", null, TestContext.Current.CancellationToken)); + // } + // + // [Fact] + // public async Task UpdateChannel() { + // var cg = Client.GetGuild(Guild.Id); + // var nc = await cg.CreateChannelAsync(new() { + // Name = "asdf", + // Type = 0 + // }); + // + // var res = await Assert.HttpSuccess(await Client.ApiHttpClient.PatchAsJsonAsync($"channels/{nc.Id}", new JsonObject() { + // { "name", "hellorld" } + // }, cancellationToken: TestContext.Current.CancellationToken)); + // + // var resC = await res.Content.ReadFromJsonAsync<Channel>(cancellationToken: TestContext.Current.CancellationToken); + // Assert.Equal("hellorld", resC!.Name); + // + // var c = await Client.GetChannel(nc.Id).GetInfoAsync(); + // Assert.Equal("hellorld", c.Name); + // } + // + // [Fact] + // public async Task DeleteChannel() { + // var cg = Client.GetGuild(Guild.Id); + // var c = await cg.CreateChannelAsync(new() { + // Name = "asdf", + // Type = 0 + // }); + // + // await Assert.HttpSuccess(await Client.ApiHttpClient.DeleteAsync($"channels/{c.Id}", TestContext.Current.CancellationToken)); + // } +} \ No newline at end of file diff --git a/extra/admin-api/Tests/Spacebar.Tests/Tests/GuildTests.cs b/extra/admin-api/Tests/Spacebar.Tests/Tests/GuildTests.cs
index 7d8fae17..9447ad96 100644 --- a/extra/admin-api/Tests/Spacebar.Tests/Tests/GuildTests.cs +++ b/extra/admin-api/Tests/Spacebar.Tests/Tests/GuildTests.cs
@@ -1,4 +1,6 @@ -using ArcaneLibs.Extensions; +using System.Net.Http.Json; +using System.Text.Json.Nodes; +using ArcaneLibs.Extensions; using Spacebar.Models.Generic; using Spacebar.Sdk.Core; using Spacebar.Tests.Abstractions; @@ -56,7 +58,29 @@ public class GuildTests(ITestOutputHelper testOutputHelper, TestFixture fixture) [Fact] public async Task SetChannelOrder() { var cg = Client.GetGuild(Guild.Id); + + await Task.WhenAll(Enumerable.Range(1, 10).Select(x => cg.CreateChannelAsync(new() { + Name = Guid.NewGuid().ToString(), + Type = 0 + }))); + var guildChannels = await cg.GetChannelsAsync(); - // testOutputHelper.WriteLine(guildChannels.Select(x=>(x.Id, x.Name)).ToJson(includeFields: true)); + testOutputHelper.WriteLine(guildChannels.Select(x=>(x.Id, x.Name, x.Position)).ToJson(includeFields: true)); + + var payload = new JsonArray(); + + var i = 0; + foreach (var c in guildChannels.OrderBy(x=>x.Name)) { + payload.Add(new JsonObject() { + {"id", c.Id.ToString()}, + {"position", i++} + }); + } + + await Assert.HttpSuccess(await Client.ApiHttpClient.PatchAsJsonAsync($"guilds/{cg.Id}/channels", payload, cancellationToken: TestContext.Current.CancellationToken)); + + var newGuildChannels = await cg.GetChannelsAsync(); + testOutputHelper.WriteLine(newGuildChannels.Select(x=>(x.Id, x.Name, x.Position)).ToJson(includeFields: true)); + Assert.Equal(guildChannels.OrderBy(x=>x.Name), newGuildChannels, (a, b) => a.Id == b.Id); } } \ No newline at end of file diff --git a/extra/admin-api/Utilities/Spacebar.Sdk/Core/SpacebarClient.cs b/extra/admin-api/Utilities/Spacebar.Sdk/Core/SpacebarClient.cs
index 2b4a4ba4..2058e21f 100644 --- a/extra/admin-api/Utilities/Spacebar.Sdk/Core/SpacebarClient.cs +++ b/extra/admin-api/Utilities/Spacebar.Sdk/Core/SpacebarClient.cs
@@ -114,6 +114,20 @@ public class SpacebarClientChannel(AuthenticatedSpacebarClient client, long chan if (!resp.IsSuccessStatusCode) throw SpacebarApiException.FromJson((await resp.Content.ReadFromJsonAsync<JsonObject>())!); return (await resp.Content.ReadFromJsonAsync<List<Webhook>>())!; } + + public async Task<TypingResponse> SendTypingAsync() { + var resp = await client.ApiHttpClient.GetAsync($"channels/{channelId}/webhooks"); + // TODO: abstract out + if (!resp.IsSuccessStatusCode) throw SpacebarApiException.FromJson((await resp.Content.ReadFromJsonAsync<JsonObject>())!); + return (await resp.Content.ReadFromJsonAsync<TypingResponse>())!; + } + + public async Task<Channel> GetInfoAsync() { + var resp = await client.ApiHttpClient.GetAsync($"channels/{channelId}"); + // TODO: abstract out + if (!resp.IsSuccessStatusCode) throw SpacebarApiException.FromJson((await resp.Content.ReadFromJsonAsync<JsonObject>())!); + return (await resp.Content.ReadFromJsonAsync<Channel>())!; + } } public class SpacebarClientGuild(AuthenticatedSpacebarClient client, long guildId) { diff --git a/extra/admin-api/Utilities/Spacebar.Sdk/Spacebar.Sdk.csproj b/extra/admin-api/Utilities/Spacebar.Sdk/Spacebar.Sdk.csproj
index fb9f9d9e..4cc3e6d2 100644 --- a/extra/admin-api/Utilities/Spacebar.Sdk/Spacebar.Sdk.csproj +++ b/extra/admin-api/Utilities/Spacebar.Sdk/Spacebar.Sdk.csproj
@@ -12,4 +12,9 @@ <ProjectReference Include="..\..\Models\Spacebar.Models.Gateway\Spacebar.Models.Gateway.csproj"/> <ProjectReference Include="..\..\Models\Spacebar.Models.Generic\Spacebar.Models.Generic.csproj"/> </ItemGroup> + + <ItemGroup> + <PackageReference Include="ArcaneLibs" Version="1.0.1-preview.20260619-035441" /> + <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.9" /> + </ItemGroup> </Project> diff --git a/scripts/validateImports.cs b/scripts/validateImports.cs
index ac301923..9008ecdb 100755 --- a/scripts/validateImports.cs +++ b/scripts/validateImports.cs
@@ -22,24 +22,42 @@ void LogError(string fileName, ImportReference import) foreach (var f in ReadDirRecursive("./src")) { - if (f.EndsWith(".test.ts")) - { - } + if (f.EndsWith(".test.ts")) continue; //ignore for now else await foreach (var import in GetImports(f)) { // These files are completely idempotent and safe to import - if (import.ImportSource.EndsWith("util/util/ProcessLifeCycle") && import.ImportEntities.SequenceEqual(["ProcessLifecycle"])) continue; + if (import.ImportSource.EndsWith("util/util/ProcessLifeCycle") && + import.ImportEntities.SequenceEqual(["ProcessLifecycle"])) continue; + + // Technically valid but what the heck + if (import.ImportSource.StartsWith('#')) LogError(f, import); // file level - if (f == "./src/schemas/Validator.ts") + else if (new FileInfo(f).Name == "start.ts") + { + if (import is + { + ImportSource: "module-alias" or "dotenv" or "./Server" // good imports + or "node:cluster" or "node:os" or "node:fs" // do we want to keep these around? + }) continue; + LogError(f, import); + } + else if (f != "./src/bundle/Server.ts" && import is + { + ImportSource: "@spacebar/api" + or "@spacebar/cdn" + // or "@spacebar/gateway" + // or "@spacebar/webrtc" + }) LogError(f, import); + else if (f == "./src/schemas/Validator.ts") { if (import is not { ImportSource: "ajv" or "ajv-formats" or "node:fs" or "node:path" }) LogError(f, import); } else if (f == "./src/database/Database.ts") { - if (import is not { ImportSource: "picocolors" or "dotenv" or "node:fs" or "node:path" }) + if (import is not { ImportSource: "picocolors" or "dotenv" or "typeorm" or "node:fs" or "node:path" }) LogError(f, import); } @@ -64,12 +82,15 @@ foreach (var f in ReadDirRecursive("./src")) { LogError(f, import); } - else + else if (f.StartsWith("./src/api")) { + if (import.ImportSource == "express" && + ((string[])["Request", "Response", "Router"]).ContainsAll(import.ImportEntities)) continue; + LogError(f, import); } } - if (importErrors.ContainsKey(f)) Console.Write("\n"); + if (importErrors.ContainsKey(f)) Console.Write("\n\n"); } if (importErrors.Any()) @@ -83,7 +104,7 @@ Console.WriteLine(); IEnumerable<string> ReadDirRecursive(string path) { - foreach (var f in Directory.GetFiles(path).OrderBy(x=>x.TrimEnd(".ts").ToString())) + foreach (var f in Directory.GetFiles(path).OrderBy(x => x.TrimEnd(".ts").ToString())) yield return f; foreach (var d in Directory.GetDirectories(path).Order()) @@ -118,6 +139,7 @@ async IAsyncEnumerable<ImportReference> GetImports(string path) if (p.StartsWith("lambert-server")) return ImportSourceTypeValue.VendoredModule; if (p.StartsWith("../")) return ImportSourceTypeValue.Path; if (p.StartsWith("./")) return ImportSourceTypeValue.LocalPath; + if (p.StartsWith('#')) return ImportSourceTypeValue.Hashtag; return ImportSourceTypeValue.Npm; } @@ -204,4 +226,7 @@ enum ImportSourceTypeValue [Color(255, 255, 0)] [FriendlyName(Name = "Local file path")] LocalPath, + + [FriendlyName(Name = "Hashtag import")] [Color(255, 82, 82)] + Hashtag } \ No newline at end of file