diff --git a/ArcaneLibs b/ArcaneLibs
-Subproject 68eca20fbf4d5c08b6960fb2362ba3733d2df9e
+Subproject 808f94b5dc151e6659d2b13aa92302cc1a37b17
diff --git a/LibMatrix/Events/BaseEvent.cs b/LibMatrix/Events/BaseEvent.cs
new file mode 100644
index 0000000..2e27368
--- /dev/null
+++ b/LibMatrix/Events/BaseEvent.cs
@@ -0,0 +1,52 @@
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Events;
+
+public class StateEvent {
+ [JsonPropertyName("state_key")]
+ public string? StateKey { get; set; }
+
+ [JsonPropertyName("type")]
+ public string Type { get; set; }
+
+ [JsonPropertyName("replaces_state")]
+ public string? ReplacesState { get; set; }
+}
+
+public class StateEventResponse : StateEvent {
+ [JsonPropertyName("origin_server_ts")]
+ public long? OriginServerTs { get; set; }
+
+ [JsonPropertyName("room_id")]
+ public string? RoomId { get; set; }
+
+ [JsonPropertyName("sender")]
+ public string? Sender { get; set; }
+
+ [JsonPropertyName("unsigned")]
+ public UnsignedData? Unsigned { get; set; }
+
+ [JsonPropertyName("event_id")]
+ public string? EventId { get; set; }
+
+ public class UnsignedData {
+ [JsonPropertyName("age")]
+ public ulong? Age { get; set; }
+
+ [JsonPropertyName("redacted_because")]
+ public object? RedactedBecause { get; set; }
+
+ [JsonPropertyName("transaction_id")]
+ public string? TransactionId { get; set; }
+
+ [JsonPropertyName("replaces_state")]
+ public string? ReplacesState { get; set; }
+
+ [JsonPropertyName("prev_sender")]
+ public string? PrevSender { get; set; }
+
+ [JsonPropertyName("prev_content")]
+ public JsonObject? PrevContent { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix/Extensions/HttpClientExtensions.cs b/LibMatrix/Extensions/HttpClientExtensions.cs
index 64b4f6a..f801e16 100644
--- a/LibMatrix/Extensions/HttpClientExtensions.cs
+++ b/LibMatrix/Extensions/HttpClientExtensions.cs
@@ -1,8 +1,10 @@
+#define SINGLE_HTTPCLIENT // Use a single HttpClient instance for all MatrixHttpClient instances
+// #define SYNC_HTTPCLIENT // Only allow one request as a time, for debugging
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
using System.Net.Http.Headers;
using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -25,7 +27,16 @@ public static class HttpClientExtensions {
}
}
-public class MatrixHttpClient : HttpClient {
+#region Per-instance HTTP client code
+
+#if !SINGLE_HTTPCLIENT
+public class MatrixHttpClient() : HttpClient(handler) {
+ private static readonly SocketsHttpHandler handler = new() {
+ PooledConnectionLifetime = TimeSpan.FromMinutes(15),
+ MaxConnectionsPerServer = 256,
+ EnableMultipleHttp2Connections = true
+ };
+
public Dictionary<string, string> AdditionalQueryParameters { get; set; } = new();
internal string? AssertedUserId { get; set; }
@@ -44,7 +55,7 @@ public class MatrixHttpClient : HttpClient {
public async Task<HttpResponseMessage> SendUnhandledAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
if(debug) await _rateLimitSemaphore.WaitAsync(cancellationToken);
- // Console.WriteLine($"Sending {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)})");
+ Console.WriteLine($"Sending {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)})");
if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
if (!request.RequestUri.IsAbsoluteUri) request.RequestUri = new Uri(BaseAddress, request.RequestUri);
// if (AssertedUserId is not null) request.RequestUri = request.RequestUri.AddQuery("user_id", AssertedUserId);
@@ -73,6 +84,8 @@ public class MatrixHttpClient : HttpClient {
finally {
if(debug) _rateLimitSemaphore.Release();
}
+
+ Console.WriteLine($"Sending {request.Method} {request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}) -> {(int)responseMessage.StatusCode} {responseMessage.StatusCode} ({Util.BytesToString(responseMessage.Content.Headers.ContentLength ?? 0)})");
return responseMessage;
}
@@ -191,27 +204,220 @@ public class MatrixHttpClient : HttpClient {
await foreach (var resp in result) yield return resp;
}
}
+#endif
-public class JsonFloatStringConverter : JsonConverter<float> {
- public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- => float.Parse(reader.GetString()!);
+#endregion
- public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
- => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
-}
+#if SINGLE_HTTPCLIENT
+public class MatrixHttpClient {
+ private static readonly SocketsHttpHandler handler;
-public class JsonDoubleStringConverter : JsonConverter<double> {
- public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- => double.Parse(reader.GetString()!);
+ private static readonly HttpClient client;
- public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
- => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
-}
+ static MatrixHttpClient() {
+ try {
+ handler = new SocketsHttpHandler {
+ PooledConnectionLifetime = TimeSpan.FromMinutes(15),
+ MaxConnectionsPerServer = 4096,
+ EnableMultipleHttp2Connections = true
+ };
+ client = new HttpClient(handler) {
+ DefaultRequestVersion = new Version(3, 0)
+ };
+ }
+ catch (PlatformNotSupportedException e) {
+ Console.WriteLine("Failed to create HttpClient with connection pooling, continuing without connection pool!");
+ Console.WriteLine("Original exception (safe to ignore!):");
+ Console.WriteLine(e);
+
+ client = new HttpClient {
+ DefaultRequestVersion = new Version(3, 0)
+ };
+ }
+ catch (Exception e) {
+ Console.WriteLine("Failed to create HttpClient:");
+ Console.WriteLine(e);
+ throw;
+ }
+ }
+
+#if SYNC_HTTPCLIENT
+ internal SemaphoreSlim _rateLimitSemaphore { get; } = new(1, 1);
+#endif
+
+ public Dictionary<string, string> AdditionalQueryParameters { get; set; } = new();
+
+ public Uri? BaseAddress { get; set; }
+
+ // default headers, not bound to client
+ public HttpRequestHeaders DefaultRequestHeaders { get; set; } =
+ typeof(HttpRequestHeaders).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null)?.Invoke(new object[0]) as HttpRequestHeaders ??
+ throw new InvalidOperationException("Failed to create HttpRequestHeaders");
+
+ private JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerOptions? options = null) {
+ options ??= new JsonSerializerOptions();
+ options.Converters.Add(new JsonFloatStringConverter());
+ options.Converters.Add(new JsonDoubleStringConverter());
+ options.Converters.Add(new JsonDecimalStringConverter());
+ options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+ return options;
+ }
+
+ public async Task<HttpResponseMessage> SendUnhandledAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
+#if SYNC_HTTPCLIENT
+ await _rateLimitSemaphore.WaitAsync(cancellationToken);
+#endif
+
+ Console.WriteLine($"Sending {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)})");
+
+ if (request.RequestUri is null) throw new NullReferenceException("RequestUri is null");
+ if (!request.RequestUri.IsAbsoluteUri) request.RequestUri = new Uri(BaseAddress, request.RequestUri);
+ foreach (var (key, value) in AdditionalQueryParameters) request.RequestUri = request.RequestUri.AddQuery(key, value);
+ foreach (var (key, value) in DefaultRequestHeaders) request.Headers.Add(key, value);
+
+ request.Options.Set(new HttpRequestOptionsKey<bool>("WebAssemblyEnableStreamingResponse"), true);
-public class JsonDecimalStringConverter : JsonConverter<decimal> {
- public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- => decimal.Parse(reader.GetString()!);
+ HttpResponseMessage? responseMessage;
+ try {
+ responseMessage = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+ }
+ catch (Exception e) {
+ Console.WriteLine(
+ $"Failed to send request {request.Method} {BaseAddress}{request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}):\n{e}");
+ throw;
+ }
+#if SYNC_HTTPCLIENT
+ finally {
+ _rateLimitSemaphore.Release();
+ }
+#endif
+
+ Console.WriteLine(
+ $"Sending {request.Method} {request.RequestUri} ({Util.BytesToString(request.Content?.Headers.ContentLength ?? 0)}) -> {(int)responseMessage.StatusCode} {responseMessage.StatusCode} ({Util.BytesToString(responseMessage.Content.Headers.ContentLength ?? 0)})");
+
+ return responseMessage;
+ }
+
+ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) {
+ var responseMessage = await SendUnhandledAsync(request, cancellationToken);
+ if (responseMessage.IsSuccessStatusCode) return responseMessage;
- public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
- => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
-}
\ No newline at end of file
+ //error handling
+ var content = await responseMessage.Content.ReadAsStringAsync(cancellationToken);
+ if (content.Length == 0)
+ throw new MatrixException() {
+ ErrorCode = "M_UNKNOWN",
+ Error = "Unknown error, server returned no content"
+ };
+ if (!content.StartsWith('{')) throw new InvalidDataException("Encountered invalid data:\n" + content);
+ //we have a matrix error
+
+ MatrixException? ex = null;
+ try {
+ ex = JsonSerializer.Deserialize<MatrixException>(content);
+ }
+ catch (JsonException e) {
+ throw new LibMatrixException() {
+ ErrorCode = "M_INVALID_JSON",
+ Error = e.Message + "\nBody:\n" + await responseMessage.Content.ReadAsStringAsync(cancellationToken)
+ };
+ }
+
+ Debug.Assert(ex != null, nameof(ex) + " != null");
+ ex.RawContent = content;
+ // Console.WriteLine($"Failed to send request: {ex}");
+ if (ex?.RetryAfterMs is null) throw ex!;
+ //we have a ratelimit error
+ await Task.Delay(ex.RetryAfterMs.Value, cancellationToken);
+ typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
+ ?.SetValue(request, 0);
+ return await SendAsync(request, cancellationToken);
+ }
+
+ // GetAsync
+ public Task<HttpResponseMessage> GetAsync([StringSyntax("Uri")] string? requestUri, CancellationToken? cancellationToken = null) =>
+ SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken ?? CancellationToken.None);
+
+ // GetFromJsonAsync
+ public async Task<T?> TryGetFromJsonAsync<T>(string requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) {
+ try {
+ return await GetFromJsonAsync<T>(requestUri, options, cancellationToken);
+ }
+ catch (HttpRequestException e) {
+ Console.WriteLine($"Failed to get {requestUri}: {e.Message}");
+ return default;
+ }
+ }
+
+ public async Task<T> GetFromJsonAsync<T>(string requestUri, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) {
+ options = GetJsonSerializerOptions(options);
+ var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ var response = await SendAsync(request, cancellationToken);
+ response.EnsureSuccessStatusCode();
+ await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
+
+ return await JsonSerializer.DeserializeAsync<T>(responseStream, options, cancellationToken) ??
+ throw new InvalidOperationException("Failed to deserialize response");
+ }
+
+ // GetStreamAsync
+ public new async Task<Stream> GetStreamAsync(string requestUri, CancellationToken cancellationToken = default) {
+ var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ var response = await SendAsync(request, cancellationToken);
+ response.EnsureSuccessStatusCode();
+ return await response.Content.ReadAsStreamAsync(cancellationToken);
+ }
+
+ public async Task<HttpResponseMessage> PutAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
+ CancellationToken cancellationToken = default) where T : notnull {
+ options = GetJsonSerializerOptions(options);
+ var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
+ Encoding.UTF8, "application/json");
+ return await SendAsync(request, cancellationToken);
+ }
+
+ public async Task<HttpResponseMessage> PostAsJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, T value, JsonSerializerOptions? options = null,
+ CancellationToken cancellationToken = default) where T : notnull {
+ options ??= new JsonSerializerOptions();
+ options.Converters.Add(new JsonFloatStringConverter());
+ options.Converters.Add(new JsonDoubleStringConverter());
+ options.Converters.Add(new JsonDecimalStringConverter());
+ options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
+ var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ request.Content = new StringContent(JsonSerializer.Serialize(value, value.GetType(), options),
+ Encoding.UTF8, "application/json");
+ return await SendAsync(request, cancellationToken);
+ }
+
+ public async IAsyncEnumerable<T?> GetAsyncEnumerableFromJsonAsync<T>([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, JsonSerializerOptions? options = null) {
+ options = GetJsonSerializerOptions(options);
+ var res = await GetAsync(requestUri);
+ var result = JsonSerializer.DeserializeAsyncEnumerable<T>(await res.Content.ReadAsStreamAsync(), options);
+ await foreach (var resp in result) yield return resp;
+ }
+
+ public async Task<bool> CheckSuccessStatus(string url) {
+ //cors causes failure, try to catch
+ try {
+ var resp = await client.GetAsync(url);
+ return resp.IsSuccessStatusCode;
+ }
+ catch (Exception e) {
+ Console.WriteLine($"Failed to check success status: {e.Message}");
+ return false;
+ }
+ }
+
+ public async Task<HttpResponseMessage> PostAsync(string uri, HttpContent? content, CancellationToken cancellationToken = default) {
+ var request = new HttpRequestMessage(HttpMethod.Post, uri) {
+ Content = content
+ };
+ return await SendAsync(request, cancellationToken);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/LibMatrix/Extensions/JsonConverters.cs b/LibMatrix/Extensions/JsonConverters.cs
new file mode 100644
index 0000000..eed3fb2
--- /dev/null
+++ b/LibMatrix/Extensions/JsonConverters.cs
@@ -0,0 +1,29 @@
+using System.Globalization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.Extensions;
+
+public class JsonFloatStringConverter : JsonConverter<float> {
+ public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => float.Parse(reader.GetString()!);
+
+ public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
+ => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+}
+
+public class JsonDoubleStringConverter : JsonConverter<double> {
+ public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => double.Parse(reader.GetString()!);
+
+ public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
+ => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+}
+
+public class JsonDecimalStringConverter : JsonConverter<decimal> {
+ public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => decimal.Parse(reader.GetString()!);
+
+ public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
+ => writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+}
\ No newline at end of file
diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
index c729a44..891cc00 100644
--- a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
+++ b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
@@ -117,6 +117,8 @@ public class AuthenticatedHomeserverGeneric : RemoteHomeserver {
}
public virtual async Task Logout() {
+ // var res = await ClientHttpClient.PostAsync("/_matrix/client/v3/logout", null);
+ // TODO: investigate
var res = await ClientHttpClient.PostAsync("/_matrix/client/v3/logout", null);
if (!res.IsSuccessStatusCode) {
Console.WriteLine($"Failed to logout: {await res.Content.ReadAsStringAsync()}");
diff --git a/LibMatrix/Homeservers/FederationClient.cs b/LibMatrix/Homeservers/FederationClient.cs
index dc0d1f6..b7f39eb 100644
--- a/LibMatrix/Homeservers/FederationClient.cs
+++ b/LibMatrix/Homeservers/FederationClient.cs
@@ -9,7 +9,7 @@ public class FederationClient {
public FederationClient(string federationEndpoint, string? proxy = null) {
HttpClient = new MatrixHttpClient {
BaseAddress = new Uri(proxy?.TrimEnd('/') ?? federationEndpoint.TrimEnd('/')),
- Timeout = TimeSpan.FromSeconds(120)
+ // Timeout = TimeSpan.FromSeconds(120) // TODO: investigate need
};
if (proxy is not null) HttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", federationEndpoint);
}
diff --git a/LibMatrix/Homeservers/RemoteHomeServer.cs b/LibMatrix/Homeservers/RemoteHomeServer.cs
index 8669ca7..680ade7 100644
--- a/LibMatrix/Homeservers/RemoteHomeServer.cs
+++ b/LibMatrix/Homeservers/RemoteHomeServer.cs
@@ -19,7 +19,7 @@ public class RemoteHomeserver {
WellKnownUris = wellKnownUris;
ClientHttpClient = new MatrixHttpClient {
BaseAddress = new Uri(proxy?.TrimEnd('/') ?? wellKnownUris.Client?.TrimEnd('/') ?? throw new InvalidOperationException($"No client URI for {baseUrl}!")),
- Timeout = TimeSpan.FromSeconds(300)
+ // Timeout = TimeSpan.FromSeconds(300) // TODO: investigate need
};
if (proxy is not null) ClientHttpClient.DefaultRequestHeaders.Add("MXAE_UPSTREAM", baseUrl);
diff --git a/LibMatrix/Interfaces/Services/IStorageProvider.cs b/LibMatrix/Interfaces/Services/IStorageProvider.cs
deleted file mode 100644
index 165e7df..0000000
--- a/LibMatrix/Interfaces/Services/IStorageProvider.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-namespace LibMatrix.Interfaces.Services;
-
-public interface IStorageProvider {
- // save all children of a type with reflection
- public Task SaveAllChildrenAsync<T>(string key, T value) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveAllChildren<T>(key, value)!");
- throw new NotImplementedException();
- }
-
- // load all children of a type with reflection
- public Task<T?> LoadAllChildrenAsync<T>(string key) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadAllChildren<T>(key)!");
- throw new NotImplementedException();
- }
-
- public Task SaveObjectAsync<T>(string key, T value) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveObject<T>(key, value)!");
- throw new NotImplementedException();
- }
-
- // load
- public Task<T?> LoadObjectAsync<T>(string key) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadObject<T>(key)!");
- throw new NotImplementedException();
- }
-
- // check if exists
- public Task<bool> ObjectExistsAsync(string key) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement ObjectExists(key)!");
- throw new NotImplementedException();
- }
-
- // get all keys
- public Task<List<string>> GetAllKeysAsync() {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement GetAllKeys()!");
- throw new NotImplementedException();
- }
-
- // delete
- public Task DeleteObjectAsync(string key) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement DeleteObject(key)!");
- throw new NotImplementedException();
- }
-
- // save stream
- public Task SaveStreamAsync(string key, Stream stream) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement SaveStream(key, stream)!");
- throw new NotImplementedException();
- }
-
- // load stream
- public Task<Stream?> LoadStreamAsync(string key) {
- Console.WriteLine($"StorageProvider<{GetType().Name}> does not implement LoadStream(key)!");
- throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/LibMatrix/LibMatrix.csproj b/LibMatrix/LibMatrix.csproj
index b85df52..131eea8 100644
--- a/LibMatrix/LibMatrix.csproj
+++ b/LibMatrix/LibMatrix.csproj
@@ -8,11 +8,13 @@
<Optimize>true</Optimize>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
+
+ <IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0"/>
- <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0"/>
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs
index f15327c..77bff71 100644
--- a/LibMatrix/RoomTypes/GenericRoom.cs
+++ b/LibMatrix/RoomTypes/GenericRoom.cs
@@ -106,7 +106,7 @@ public class GenericRoom {
Console.WriteLine("WARNING: Homeserver does not support getting event ID from state events, falling back to sync");
var sh = new SyncHelper(Homeserver);
var emptyFilter = new SyncFilter.EventFilter(types: [], limit: 1, senders: [], notTypes: ["*"]);
- var emptyStateFilter = new SyncFilter.RoomFilter.StateFilter(types: [], limit: 1, senders: [], notTypes: ["*"], rooms:[]);
+ var emptyStateFilter = new SyncFilter.RoomFilter.StateFilter(types: [], limit: 1, senders: [], notTypes: ["*"], rooms: []);
sh.Filter = new() {
Presence = emptyFilter,
AccountData = emptyFilter,
@@ -121,10 +121,11 @@ public class GenericRoom {
var sync = await sh.SyncAsync();
var state = sync.Rooms.Join[RoomId].State.Events;
var stateEvent = state.FirstOrDefault(x => x.Type == type && x.StateKey == stateKey);
- if (stateEvent is null) throw new LibMatrixException() {
- ErrorCode = LibMatrixException.ErrorCodes.M_NOT_FOUND,
- Error = "State event not found in sync response"
- };
+ if (stateEvent is null)
+ throw new LibMatrixException() {
+ ErrorCode = LibMatrixException.ErrorCodes.M_NOT_FOUND,
+ Error = "State event not found in sync response"
+ };
return stateEvent.EventId;
}
@@ -231,7 +232,7 @@ public class GenericRoom {
// var sw = Stopwatch.StartNew();
var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members");
// if (sw.ElapsedMilliseconds > 1000)
- // Console.WriteLine($"Members call responded in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call responded in {sw.GetElapsedAndRestart()}");
// else sw.Restart();
// var resText = await res.Content.ReadAsStringAsync();
// Console.WriteLine($"Members call response read in {sw.GetElapsedAndRestart()}");
@@ -239,7 +240,7 @@ public class GenericRoom {
TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default
});
// if (sw.ElapsedMilliseconds > 100)
- // Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}");
// else sw.Restart();
foreach (var resp in result.Chunk) {
if (resp?.Type != "m.room.member") continue;
@@ -248,14 +249,14 @@ public class GenericRoom {
}
// if (sw.ElapsedMilliseconds > 100)
- // Console.WriteLine($"Members call iterated in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call iterated in {sw.GetElapsedAndRestart()}");
}
public async Task<FrozenSet<StateEventResponse>> GetMembersListAsync(bool joinedOnly = true) {
// var sw = Stopwatch.StartNew();
var res = await Homeserver.ClientHttpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members");
// if (sw.ElapsedMilliseconds > 1000)
- // Console.WriteLine($"Members call responded in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call responded in {sw.GetElapsedAndRestart()}");
// else sw.Restart();
// var resText = await res.Content.ReadAsStringAsync();
// Console.WriteLine($"Members call response read in {sw.GetElapsedAndRestart()}");
@@ -263,7 +264,7 @@ public class GenericRoom {
TypeInfoResolver = ChunkedStateEventResponseSerializerContext.Default
});
// if (sw.ElapsedMilliseconds > 100)
- // Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call deserialised in {sw.GetElapsedAndRestart()}");
// else sw.Restart();
var members = new List<StateEventResponse>();
foreach (var resp in result.Chunk) {
@@ -273,7 +274,7 @@ public class GenericRoom {
}
// if (sw.ElapsedMilliseconds > 100)
- // Console.WriteLine($"Members call iterated in {sw.GetElapsedAndRestart()}");
+ // Console.WriteLine($"Members call iterated in {sw.GetElapsedAndRestart()}");
return members.ToFrozenSet();
}
@@ -282,10 +283,10 @@ public class GenericRoom {
public Task<EventIdResponse> SendMessageEventAsync(RoomMessageEventContent content) =>
SendTimelineEventAsync("m.room.message", content);
- public async Task<List<string>?> GetAliasesAsync() {
- var res = await GetStateAsync<RoomAliasEventContent>("m.room.aliases");
- return res.Aliases;
- }
+ // public async Task<List<string>?> GetAliasesAsync() {
+ // var res = await GetStateAsync<RoomAliasEventContent>(RoomAliasEventContent.EventId);
+ // return res.Aliases;
+ // }
public Task<RoomCanonicalAliasEventContent?> GetCanonicalAliasAsync() =>
GetStateAsync<RoomCanonicalAliasEventContent>("m.room.canonical_alias");
@@ -382,18 +383,18 @@ public class GenericRoom {
public async Task KickAsync(string userId, string? reason = null) =>
await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/kick",
- new UserIdAndReason { UserId = userId, Reason = reason });
+ new UserIdAndReason(userId, reason));
public async Task BanAsync(string userId, string? reason = null) =>
await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/ban",
- new UserIdAndReason { UserId = userId, Reason = reason });
+ new UserIdAndReason(userId, reason));
- public async Task UnbanAsync(string userId) =>
+ public async Task<HttpResponseMessage> UnbanAsync(string userId, string? reason = null) =>
await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/unban",
- new UserIdAndReason { UserId = userId });
+ new UserIdAndReason(userId, reason));
public async Task InviteUserAsync(string userId, string? reason = null, bool skipExisting = true) {
- if (skipExisting && await GetStateAsync<RoomMemberEventContent>("m.room.member", userId) is not null)
+ if (skipExisting && await GetStateOrNullAsync<RoomMemberEventContent>("m.room.member", userId) is not null)
return;
await Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/v3/rooms/{RoomId}/invite", new UserIdAndReason(userId, reason));
}
@@ -524,21 +525,21 @@ public class GenericRoom {
var uri = new Uri(path, UriKind.Relative);
if (dir == "b" || dir == "f") uri = uri.AddQuery("dir", dir);
- else if(!string.IsNullOrWhiteSpace(dir)) throw new ArgumentException("Invalid direction", nameof(dir));
+ else if (!string.IsNullOrWhiteSpace(dir)) throw new ArgumentException("Invalid direction", nameof(dir));
if (!string.IsNullOrEmpty(from)) uri = uri.AddQuery("from", from);
if (chunkLimit is not null) uri = uri.AddQuery("limit", chunkLimit.Value.ToString());
if (recurse is not null) uri = uri.AddQuery("recurse", recurse.Value.ToString());
if (!string.IsNullOrEmpty(to)) uri = uri.AddQuery("to", to);
// Console.WriteLine($"Getting related events from {uri}");
- var result = await Homeserver.ClientHttpClient.GetFromJsonAsync<RecursedBatchedChunkedStateEventResponse>(uri);
+ var result = await Homeserver.ClientHttpClient.GetFromJsonAsync<RecursedBatchedChunkedStateEventResponse>(uri.ToString()); //TODO: investigate ToString call
while (result!.Chunk.Count > 0) {
foreach (var resp in result.Chunk) {
yield return resp;
}
if (result.NextBatch is null) break;
- result = await Homeserver.ClientHttpClient.GetFromJsonAsync<RecursedBatchedChunkedStateEventResponse>(uri.AddQuery("from", result.NextBatch));
+ result = await Homeserver.ClientHttpClient.GetFromJsonAsync<RecursedBatchedChunkedStateEventResponse>(uri.AddQuery("from", result.NextBatch).ToString()); //TODO: investigate ToString call
}
}
diff --git a/LibMatrix/RoomTypes/SpaceRoom.cs b/LibMatrix/RoomTypes/SpaceRoom.cs
index b40ccc6..45069d9 100644
--- a/LibMatrix/RoomTypes/SpaceRoom.cs
+++ b/LibMatrix/RoomTypes/SpaceRoom.cs
@@ -1,9 +1,12 @@
+using System.Text.Json.Nodes;
using ArcaneLibs.Extensions;
using LibMatrix.Homeservers;
namespace LibMatrix.RoomTypes;
public class SpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId) : GenericRoom(homeserver, roomId) {
+ public const string TypeName = "m.space";
+
public async IAsyncEnumerable<GenericRoom> GetChildrenAsync(bool includeRemoved = false) {
// var rooms = new List<GenericRoom>();
var state = GetFullStateAsync();
@@ -31,7 +34,7 @@ public class SpaceRoom(AuthenticatedHomeserverGeneric homeserver, string roomId)
});
return resp;
}
-
+
public async Task<EventIdResponse> AddChildByIdAsync(string id) {
return await AddChildAsync(Homeserver.GetRoom(id));
}
diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs
index 05ce733..27ad594 100644
--- a/LibMatrix/Services/HomeserverResolverService.cs
+++ b/LibMatrix/Services/HomeserverResolverService.cs
@@ -14,7 +14,7 @@ namespace LibMatrix.Services;
public class HomeserverResolverService {
private readonly MatrixHttpClient _httpClient = new() {
- Timeout = TimeSpan.FromSeconds(60)
+ // Timeout = TimeSpan.FromSeconds(60) //TODO: investigate need
};
private static readonly SemaphoreCache<WellKnownUris> WellKnownCache = new();
diff --git a/LibMatrix/Services/TieredStorageService.cs b/LibMatrix/Services/TieredStorageService.cs
deleted file mode 100644
index 9e411de..0000000
--- a/LibMatrix/Services/TieredStorageService.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using LibMatrix.Interfaces.Services;
-
-namespace LibMatrix.Services;
-
-public class TieredStorageService(IStorageProvider? cacheStorageProvider, IStorageProvider? dataStorageProvider) {
- public IStorageProvider? CacheStorageProvider { get; } = cacheStorageProvider;
- public IStorageProvider? DataStorageProvider { get; } = dataStorageProvider;
-}
\ No newline at end of file
diff --git a/LibMatrix/StateEvent.cs b/LibMatrix/StateEvent.cs
index 81ee3fe..3bd0672 100644
--- a/LibMatrix/StateEvent.cs
+++ b/LibMatrix/StateEvent.cs
@@ -1,6 +1,7 @@
using System.Collections.Frozen;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
@@ -54,6 +55,8 @@ public class StateEvent {
[JsonIgnore]
[SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global")]
public EventContent? TypedContent {
+ [RequiresDynamicCode("TypedContent requires reflection to deserialize the content of the event.")]
+ [RequiresUnreferencedCode("TypedContent requires reflection to deserialize the content of the event.")]
get {
// if (Type == "m.receipt") {
// return null;
@@ -72,6 +75,9 @@ public class StateEvent {
return null;
}
+
+ [RequiresDynamicCode("TypedContent requires reflection to deserialize the content of the event.")]
+ [RequiresUnreferencedCode("TypedContent requires reflection to deserialize the content of the event.")]
set {
if (value is null)
RawContent?.Clear();
diff --git a/LibMatrix/UserIdAndReason.cs b/LibMatrix/UserIdAndReason.cs
index 99c9eaf..5e52303 100644
--- a/LibMatrix/UserIdAndReason.cs
+++ b/LibMatrix/UserIdAndReason.cs
@@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
namespace LibMatrix;
-internal class UserIdAndReason(string userId = null!, string reason = null!) {
+internal class UserIdAndReason(string userId = null!, string? reason = null) {
[JsonPropertyName("user_id")]
public string UserId { get; set; } = userId;
diff --git a/Tests/LibMatrix.HomeserverEmulator/LibMatrix.HomeserverEmulator.csproj b/Tests/LibMatrix.HomeserverEmulator/LibMatrix.HomeserverEmulator.csproj
index 0a43299..122cfba 100644
--- a/Tests/LibMatrix.HomeserverEmulator/LibMatrix.HomeserverEmulator.csproj
+++ b/Tests/LibMatrix.HomeserverEmulator/LibMatrix.HomeserverEmulator.csproj
@@ -10,9 +10,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="EasyCompressor.LZMA" Version="1.4.0"/>
- <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0"/>
- <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
+ <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
+ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
<ItemGroup>
diff --git a/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs b/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
index c9727d6..401223c 100644
--- a/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
+++ b/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
@@ -1,71 +1,96 @@
using ArcaneLibs.Extensions;
using LibMatrix.Homeservers;
using LibMatrix.Responses;
+using LibMatrix.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Xunit.Abstractions;
+using Xunit.Sdk;
namespace LibMatrix.Tests.Abstractions;
-public static class HomeserverAbstraction {
- public static async Task<AuthenticatedHomeserverGeneric> GetHomeserver() {
- var rhs = await RemoteHomeserver.Create("https://matrixunittests.rory.gay");
- // string username = Guid.NewGuid().ToString();
- // string password = Guid.NewGuid().ToString();
- var username = "@f1a2d2d6-1924-421b-91d0-893b347b2a49:matrixunittests.rory.gay";
- var password = "d6d782d6-8bc9-4fac-9cd8-78e101b4298b";
+public class HomeserverAbstraction(HomeserverProviderService _hsProvider, Config _config, ILogger<HomeserverAbstraction> _logger) {
+ // private static readonly HomeserverResolverService _hsResolver = new HomeserverResolverService(NullLogger<HomeserverResolverService>.Instance);
+ // private static readonly HomeserverProviderService _hsProvider = new HomeserverProviderService(NullLogger<HomeserverProviderService>.Instance, _hsResolver);
+
+ private static AuthenticatedHomeserverGeneric? ConfiguredHomeserver { get; set; }
+ private static readonly SemaphoreSlim _lock = new(1, 1);
+
+ public async Task<AuthenticatedHomeserverGeneric> GetConfiguredHomeserver(ITestOutputHelper? testOutputHelper = null) {
+ Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver));
+ Assert.False(string.IsNullOrWhiteSpace(_config.TestUsername));
+ Assert.False(string.IsNullOrWhiteSpace(_config.TestPassword));
+
+ _logger.LogDebug("Using homeserver '{0}' with login '{1}' '{2}", _config.TestHomeserver, _config.TestUsername, _config.TestPassword);
+ testOutputHelper?.WriteLine($"Using homeserver '{_config.TestHomeserver}' with login '{_config.TestUsername}' '{_config.TestPassword}'");
+
+ await _lock.WaitAsync();
+ if (ConfiguredHomeserver is not null) {
+ _lock.Release();
+ return ConfiguredHomeserver;
+ }
+
+ var rhs = await _hsProvider.GetRemoteHomeserver(_config.TestHomeserver);
+
LoginResponse reg;
try {
- reg = await rhs.LoginAsync(username, password);
+ reg = await rhs.LoginAsync(_config.TestUsername, _config.TestPassword);
}
catch (MatrixException e) {
if (e.ErrorCode == "M_FORBIDDEN") {
await rhs.RegisterAsync(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "Unit tests!");
- reg = await rhs.RegisterAsync(username, password, "Unit tests!");
+ reg = await rhs.RegisterAsync(_config.TestUsername, _config.TestPassword, "Unit tests!");
}
else throw new Exception("Failed to register", e);
}
- var hs = await reg.GetAuthenticatedHomeserver("https://matrixunittests.rory.gay");
-
- //var rooms = await hs.GetJoinedRooms();
-
- // var disbandRoomTasks = rooms.Select(async room => {
- // // await room.DisbandRoomAsync();
- // await room.LeaveAsync();
- // await room.ForgetAsync();
- // return room;
- // }).ToList();
- // await Task.WhenAll(disbandRoomTasks);
-
- // foreach (var room in rooms) {
- // // await room.DisbandRoomAsync();
- // await room.LeaveAsync();
- // await room.ForgetAsync();
- // }
+ var hs = await _hsProvider.GetAuthenticatedWithToken(reg.Homeserver, reg.AccessToken);
+ ConfiguredHomeserver = hs;
+ _lock.Release();
return hs;
}
- public static async Task<AuthenticatedHomeserverGeneric> GetRandomHomeserver() {
- var rhs = await RemoteHomeserver.Create("https://matrixunittests.rory.gay");
- var reg = await rhs.RegisterAsync(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "Unit tests!");
- var hs = await reg.GetAuthenticatedHomeserver("https://matrixunittests.rory.gay");
-
- // var rooms = await hs.GetJoinedRooms();
- //
- // var disbandRoomTasks = rooms.Select(async room => {
- // // await room.DisbandRoomAsync();
- // await room.LeaveAsync();
- // await room.ForgetAsync();
- // return room;
- // }).ToList();
- // await Task.WhenAll(disbandRoomTasks);
-
+ public async Task<AuthenticatedHomeserverGeneric> GetNewHomeserver() {
+ Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver));
+ var username = Guid.NewGuid().ToString();
+ var password = Guid.NewGuid().ToString();
+
+ _logger.LogDebug("Creating new homeserver '{0}' with login '{1}' '{2}'", _config.TestHomeserver, username, password);
+
+ var rhs = await _hsProvider.GetRemoteHomeserver(_config.TestHomeserver);
+ var reg = await rhs.RegisterAsync(username, password, "Unit tests!");
+ var hs = await _hsProvider.GetAuthenticatedWithToken(reg.Homeserver, reg.AccessToken);
+
return hs;
}
- public static async IAsyncEnumerable<AuthenticatedHomeserverGeneric> GetRandomHomeservers(int count = 1) {
+ public async IAsyncEnumerable<AuthenticatedHomeserverGeneric> GetNewHomeservers(int count = 1) {
var createRandomUserTasks = Enumerable
.Range(0, count)
- .Select(_ => GetRandomHomeserver()).ToAsyncEnumerable();
+ .Select(_ => GetNewHomeserver()).ToAsyncEnumerable();
await foreach (var hs in createRandomUserTasks) yield return hs;
}
+
+ public async Task<(string username, string password, string token)> GetKnownCredentials() {
+ Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver));
+ var rhs = await _hsProvider.GetRemoteHomeserver(_config.TestHomeserver);
+
+ var username = _config.TestUsername;
+ var password = _config.TestPassword;
+
+ LoginResponse reg;
+ try {
+ reg = await rhs.LoginAsync(username, password);
+ }
+ catch (MatrixException e) {
+ if (e.ErrorCode == "M_FORBIDDEN") {
+ await rhs.RegisterAsync(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "Unit tests!");
+ reg = await rhs.RegisterAsync(username, password, "Unit tests!");
+ }
+ else throw new Exception("Failed to log in", e);
+ }
+
+ return (username, password, reg.AccessToken);
+ }
}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Abstractions/RoomAbstraction.cs b/Tests/LibMatrix.Tests/Abstractions/RoomAbstraction.cs
index 2a380fc..88b6758 100644
--- a/Tests/LibMatrix.Tests/Abstractions/RoomAbstraction.cs
+++ b/Tests/LibMatrix.Tests/Abstractions/RoomAbstraction.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using ArcaneLibs.Extensions;
using LibMatrix.EventTypes.Spec.State;
using LibMatrix.EventTypes.Spec.State.RoomInfo;
@@ -16,28 +17,28 @@ public static class RoomAbstraction {
};
crq.InitialState ??= new List<StateEvent>();
crq.InitialState.Add(new StateEvent() {
- Type = "m.room.topic",
+ Type = RoomTopicEventContent.EventId,
StateKey = "",
TypedContent = new RoomTopicEventContent() {
Topic = "LibMatrix Test Room " + DateTime.Now.ToString("O")
}
});
crq.InitialState.Add(new StateEvent() {
- Type = "m.room.name",
+ Type = RoomNameEventContent.EventId,
StateKey = "",
TypedContent = new RoomNameEventContent() {
Name = "LibMatrix Test Room " + DateTime.Now.ToString("O")
}
});
crq.InitialState.Add(new StateEvent() {
- Type = "m.room.avatar",
+ Type = RoomAvatarEventContent.EventId,
StateKey = "",
TypedContent = new RoomAvatarEventContent() {
Url = "mxc://conduit.rory.gay/r9KiT0f9eQbv8pv4RxwBZFuzhfKjGWHx"
}
});
crq.InitialState.Add(new StateEvent() {
- Type = "m.room.aliases",
+ Type = RoomAliasEventContent.EventId,
StateKey = "",
TypedContent = new RoomAliasEventContent() {
Aliases = Enumerable
diff --git a/Tests/LibMatrix.Tests/Config.cs b/Tests/LibMatrix.Tests/Config.cs
index ddbf705..045ea40 100644
--- a/Tests/LibMatrix.Tests/Config.cs
+++ b/Tests/LibMatrix.Tests/Config.cs
@@ -1,18 +1,41 @@
+using Microsoft.Extensions.Configuration;
+
namespace LibMatrix.Tests;
public class Config {
+ public Config(IConfiguration? config) {
+ config.GetSection("Configuration").Bind(this);
+ }
+
public string? TestHomeserver { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_HOMESERVER") ?? null;
- public string? TestUsername { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_USERNAME") ?? null;
- public string? TestPassword { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_PASSWORD") ?? null;
- public string? TestRoomId { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_ROOM_ID") ?? null;
- public string? TestRoomAlias { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_ROOM_ALIAS") ?? null;
+ public string? TestUsername { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_USERNAME") ?? Guid.NewGuid().ToString();
+
+ public string? TestPassword { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_PASSWORD") ?? Guid.NewGuid().ToString();
+ // public string? TestRoomId { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_ROOM_ID") ?? null;
+ // public string? TestRoomAlias { get; set; } = Environment.GetEnvironmentVariable("LIBMATRIX_TEST_ROOM_ALIAS") ?? null;
- public Dictionary<string, string> ExpectedHomeserverMappings { get; set; } = new() {
+ public Dictionary<string, string> ExpectedHomeserverClientMappings { get; set; } = new() {
{ "matrix.org", "https://matrix-client.matrix.org" },
- { "rory.gay", "https://matrix.rory.gay" }
+ { "rory.gay", "https://matrix.rory.gay" },
+ { "feline.support", "https://matrix.feline.support" },
+ { "transfem.dev", "https://matrix.transfem.dev" },
+ { "the-apothecary.club", "https://the-apothecary.club" },
+ { "nixos.org", "https://matrix.nixos.org" },
+ { "fedora.im", "https://fedora.ems.host" }
+ };
+
+ public Dictionary<string, string> ExpectedHomeserverFederationMappings { get; set; } = new() {
+ { "rory.gay", "https://matrix.rory.gay:443" },
+ { "matrix.org", "https://matrix-federation.matrix.org:443" },
+ { "feline.support", "https://matrix.feline.support:8448" },
+ { "transfem.dev", "https://matrix.transfem.dev:443" },
+ { "the-apothecary.club", "https://the-apothecary.club:443" },
+ { "nixos.org", "https://matrix.nixos.org:443" },
+ { "fedora.im", "https://fedora.ems.host:443" }
};
public Dictionary<string, string> ExpectedAliasMappings { get; set; } = new() {
- { "#libmatrix:rory.gay", "!tuiLEoMqNOQezxILzt:rory.gay" }
+ { "#libmatrix:rory.gay", "!tuiLEoMqNOQezxILzt:rory.gay" },
+ { "#matrix:matrix.org", "!OGEhHVWSdvArJzumhm:matrix.org" }
};
}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Fixtures/TestFixture.cs b/Tests/LibMatrix.Tests/Fixtures/TestFixture.cs
index 35c8704..01a0d2f 100644
--- a/Tests/LibMatrix.Tests/Fixtures/TestFixture.cs
+++ b/Tests/LibMatrix.Tests/Fixtures/TestFixture.cs
@@ -1,5 +1,6 @@
using ArcaneLibs.Extensions;
using LibMatrix.Services;
+using LibMatrix.Tests.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Xunit.Microsoft.DependencyInjection;
@@ -8,24 +9,19 @@ using Xunit.Microsoft.DependencyInjection.Abstracts;
namespace LibMatrix.Tests.Fixtures;
public class TestFixture : TestBedFixture {
- protected override void AddServices(IServiceCollection services, IConfiguration? configuration) {
- services.AddSingleton<TieredStorageService>(x =>
- new TieredStorageService(
- null,
- null
- )
- );
+ protected override void AddServices(IServiceCollection services, IConfiguration configuration) {
+ // services.AddSingleton<TieredStorageService>(x =>
+ // new TieredStorageService(
+ // null,
+ // null
+ // )
+ // );
+ services.AddSingleton(configuration);
services.AddRoryLibMatrixServices();
-
- services.AddSingleton<Config>(config => {
- var conf = new Config();
- configuration?.GetSection("Configuration").Bind(conf);
-
- File.WriteAllText("configuration.json", conf.ToJson());
-
- return conf;
- });
+ services.AddLogging();
+ services.AddSingleton<HomeserverAbstraction>();
+ services.AddSingleton<Config>();
}
protected override ValueTask DisposeAsyncCore()
diff --git a/Tests/LibMatrix.Tests/LibMatrix.Tests.csproj b/Tests/LibMatrix.Tests/LibMatrix.Tests.csproj
index d833d8b..52bec9f 100644
--- a/Tests/LibMatrix.Tests/LibMatrix.Tests.csproj
+++ b/Tests/LibMatrix.Tests/LibMatrix.Tests.csproj
@@ -12,14 +12,14 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0-preview-23531-01"/>
- <PackageReference Include="xunit" Version="2.6.1"/>
- <PackageReference Include="Xunit.Microsoft.DependencyInjection" Version="7.0.10"/>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
+ <PackageReference Include="xunit" Version="2.8.0" />
+ <PackageReference Include="Xunit.Microsoft.DependencyInjection" Version="8.1.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
- <PackageReference Include="coverlet.collector" Version="3.2.0">
+ <PackageReference Include="coverlet.collector" Version="6.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
diff --git a/Tests/LibMatrix.Tests/Tests/AuthTests.cs b/Tests/LibMatrix.Tests/Tests/AuthTests.cs
index 67ba8eb..c1fefe4 100644
--- a/Tests/LibMatrix.Tests/Tests/AuthTests.cs
+++ b/Tests/LibMatrix.Tests/Tests/AuthTests.cs
@@ -1,4 +1,5 @@
using LibMatrix.Services;
+using LibMatrix.Tests.Abstractions;
using LibMatrix.Tests.DataTests;
using LibMatrix.Tests.Fixtures;
using Xunit.Abstractions;
@@ -7,43 +8,29 @@ using Xunit.Microsoft.DependencyInjection.Abstracts;
namespace LibMatrix.Tests.Tests;
public class AuthTests : TestBed<TestFixture> {
- private readonly TestFixture _fixture;
- private readonly HomeserverResolverService _resolver;
private readonly Config _config;
private readonly HomeserverProviderService _provider;
+ private readonly HomeserverAbstraction _hsAbstraction;
public AuthTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
- _fixture = fixture;
- _resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
_config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
_provider = _fixture.GetService<HomeserverProviderService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverProviderService)}");
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
}
-
+
[Fact]
public async Task LoginWithPassword() {
- Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver), $"{nameof(_config.TestHomeserver)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestUsername), $"{nameof(_config.TestUsername)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestPassword), $"{nameof(_config.TestPassword)} must be set in appsettings!");
-
- // var server = await _resolver.ResolveHomeserverFromWellKnown(_config.TestHomeserver!);
- var login = await _provider.Login(_config.TestHomeserver!, _config.TestUsername!, _config.TestPassword!);
+ var credentials = await _hsAbstraction.GetKnownCredentials();
+
+ var login = await _provider.Login(_config.TestHomeserver!, credentials.username, credentials.password);
Assert.NotNull(login);
- var hs = await _provider.GetAuthenticatedWithToken(_config.TestHomeserver!, login.AccessToken);
- Assert.NotNull(hs);
- await hs.Logout();
+ Assert.NotNull(login.AccessToken);
}
[Fact]
public async Task LoginWithToken() {
- Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver), $"{nameof(_config.TestHomeserver)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestUsername), $"{nameof(_config.TestUsername)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestPassword), $"{nameof(_config.TestPassword)} must be set in appsettings!");
-
- // var server = await _resolver.ResolveHomeserverFromWellKnown(_config.TestHomeserver!);
- var login = await _provider.Login(_config.TestHomeserver!, _config.TestUsername!, _config.TestPassword!);
- Assert.NotNull(login);
-
- var hs = await _provider.GetAuthenticatedWithToken(_config.TestHomeserver!, login.AccessToken);
+ var credentials = await _hsAbstraction.GetKnownCredentials();
+ var hs = await _provider.GetAuthenticatedWithToken(_config.TestHomeserver!, credentials.token);
Assert.NotNull(hs);
Assert.NotNull(hs.WhoAmI);
hs.WhoAmI.VerifyRequiredFields();
@@ -60,7 +47,7 @@ public class AuthTests : TestBed<TestFixture> {
Assert.NotNull(reg.AccessToken);
Assert.NotNull(reg.DeviceId);
Assert.NotNull(reg.UserId);
- var hs = await reg.GetAuthenticatedHomeserver();
+ var hs = await _provider.GetAuthenticatedWithToken(reg.Homeserver, reg.AccessToken);
Assert.NotNull(hs);
Assert.NotNull(hs.WhoAmI);
hs.WhoAmI.VerifyRequiredFields();
diff --git a/Tests/LibMatrix.Tests/Tests/HomeserverResolverTests.cs b/Tests/LibMatrix.Tests/Tests/HomeserverResolverTests.cs
new file mode 100644
index 0000000..ef2426d
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/HomeserverResolverTests.cs
@@ -0,0 +1,43 @@
+using LibMatrix.Services;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests;
+
+public class HomeserverResolverTests : TestBed<TestFixture> {
+ private readonly Config _config;
+ private readonly HomeserverResolverService _resolver;
+
+ public HomeserverResolverTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
+ _resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
+ }
+
+ [Fact]
+ public async Task ResolveServerClient() {
+ var tasks = _config.ExpectedHomeserverClientMappings.Select(async mapping => {
+ var server = await _resolver.ResolveHomeserverFromWellKnown(mapping.Key);
+ Assert.Equal(mapping.Value, server.Client);
+ return server;
+ }).ToList();
+ await Task.WhenAll(tasks);
+ }
+
+ [Fact]
+ public async Task ResolveServerServer() {
+ var tasks = _config.ExpectedHomeserverFederationMappings.Select(async mapping => {
+ var server = await _resolver.ResolveHomeserverFromWellKnown(mapping.Key);
+ Assert.Equal(mapping.Value, server.Server);
+ return server;
+ }).ToList();
+ await Task.WhenAll(tasks);
+ }
+
+ [Fact]
+ public async Task ResolveMedia() {
+ var media = await _resolver.ResolveMediaUri("matrix.org", "mxc://matrix.org/eqwrRZRoPpNbcMeUwyXAuVRo");
+
+ Assert.Equal("https://matrix-client.matrix.org/_matrix/media/v3/download/matrix.org/eqwrRZRoPpNbcMeUwyXAuVRo", media);
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/ResolverTest.cs b/Tests/LibMatrix.Tests/Tests/RemoteHomeserverTests.cs
index 700aa96..03f3c24 100644
--- a/Tests/LibMatrix.Tests/Tests/ResolverTest.cs
+++ b/Tests/LibMatrix.Tests/Tests/RemoteHomeserverTests.cs
@@ -5,13 +5,13 @@ using Xunit.Microsoft.DependencyInjection.Abstracts;
namespace LibMatrix.Tests.Tests;
-public class ResolverTest : TestBed<TestFixture> {
+public class RemoteHomeserverTests : TestBed<TestFixture> {
private readonly TestFixture _fixture;
private readonly HomeserverResolverService _resolver;
private readonly Config _config;
private readonly HomeserverProviderService _provider;
- public ResolverTest(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ public RemoteHomeserverTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
_fixture = fixture;
_resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
_config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
@@ -19,29 +19,30 @@ public class ResolverTest : TestBed<TestFixture> {
}
[Fact]
- public async Task ResolveServer() {
- foreach (var (domain, expected) in _config.ExpectedHomeserverMappings) {
- var server = await _resolver.ResolveHomeserverFromWellKnown(domain);
- Assert.Equal(expected, server.Client);
- }
- }
-
- [Fact]
public async Task ResolveMedia() {
- var media = await _resolver.ResolveMediaUri("matrix.org", "mxc://matrix.org/eqwrRZRoPpNbcMeUwyXAuVRo");
+ var hs = await _provider.GetRemoteHomeserver("matrix.org");
+ var media = hs.ResolveMediaUri("mxc://matrix.org/eqwrRZRoPpNbcMeUwyXAuVRo");
+
Assert.Equal("https://matrix-client.matrix.org/_matrix/media/v3/download/matrix.org/eqwrRZRoPpNbcMeUwyXAuVRo", media);
}
[Fact]
public async Task ResolveRoomAliasAsync() {
- var hs = await _provider.GetRemoteHomeserver("matrix.org");
- var alias = await hs.ResolveRoomAliasAsync("#matrix:matrix.org");
- Assert.Equal("!OGEhHVWSdvArJzumhm:matrix.org", alias.RoomId);
+ // var hs = await _provider.GetRemoteHomeserver("matrix.org");
+ // var alias = await hs.ResolveRoomAliasAsync("#matrix:matrix.org");
+ // Assert.Equal("!OGEhHVWSdvArJzumhm:matrix.org", alias.RoomId);
+ var tasks = _config.ExpectedAliasMappings.Select(async mapping => {
+ var hs = await _provider.GetRemoteHomeserver("matrix.org");
+ var alias = await hs.ResolveRoomAliasAsync(mapping.Key);
+ Assert.Equal(mapping.Value, alias.RoomId);
+ return alias;
+ }).ToList();
+ await Task.WhenAll(tasks);
}
[Fact]
public async Task GetClientVersionsAsync() {
- var hs = await _provider.GetRemoteHomeserver("matrix.org");
+ var hs = await _provider.GetRemoteHomeserver(_config.TestHomeserver);
var versions = await hs.GetClientVersionsAsync();
Assert.NotNull(versions);
}
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests.cs
deleted file mode 100644
index 4c8dcb4..0000000
--- a/Tests/LibMatrix.Tests/Tests/RoomTests.cs
+++ /dev/null
@@ -1,248 +0,0 @@
-using System.Text;
-using LibMatrix.EventTypes.Spec.State;
-using LibMatrix.Homeservers;
-using LibMatrix.Responses;
-using LibMatrix.Services;
-using LibMatrix.Tests.Abstractions;
-using LibMatrix.Tests.Fixtures;
-using Xunit.Abstractions;
-using Xunit.Microsoft.DependencyInjection.Abstracts;
-
-namespace LibMatrix.Tests.Tests;
-
-public class RoomTests : TestBed<TestFixture> {
- private readonly TestFixture _fixture;
- private readonly HomeserverResolverService _resolver;
- private readonly Config _config;
- private readonly HomeserverProviderService _provider;
-
- public RoomTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
- _fixture = fixture;
- _resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
- _config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
- _provider = _fixture.GetService<HomeserverProviderService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverProviderService)}");
- }
-
- private async Task<AuthenticatedHomeserverGeneric> GetHomeserver() => await HomeserverAbstraction.GetHomeserver();
-
- [Fact]
- public async Task GetJoinedRoomsAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- //make 100 rooms
- var createRoomTasks = Enumerable.Range(0, 10).Select(_ => RoomAbstraction.GetTestRoom(hs)).ToList();
- await Task.WhenAll(createRoomTasks);
-
- var rooms = await hs.GetJoinedRooms();
- Assert.NotNull(rooms);
- Assert.NotEmpty(rooms);
- Assert.All(rooms, Assert.NotNull);
- Assert.True(rooms.Count >= 10, "Not enough rooms were found");
-
- await hs.Logout();
- }
-
- [Fact]
- public async Task GetMembersAsync() {
- Assert.True(StateEvent.KnownStateEventTypes is { Count: > 0 }, "StateEvent.KnownStateEventTypes is empty!");
- Assert.True(StateEvent.KnownStateEventTypesByName is { Count: > 0 }, "StateEvent.KnownStateEventTypesByName is empty!");
-
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- var members = room.GetMembersEnumerableAsync();
- Assert.NotNull(members);
- var hitMembers = false;
- await foreach (var member in members) {
- Assert.NotNull(member);
- Assert.NotNull(member.StateKey);
- Assert.NotEmpty(member.StateKey);
- Assert.NotNull(member.Sender);
- Assert.NotEmpty(member.Sender);
- Assert.NotNull(member.RawContent);
- Assert.NotEmpty(member.RawContent);
- Assert.NotNull(member.TypedContent);
- Assert.IsType<RoomMemberEventContent>(member.TypedContent);
- var content = (RoomMemberEventContent)member.TypedContent;
- Assert.NotNull(content);
- Assert.NotNull(content.Membership);
- Assert.NotEmpty(content.Membership);
- hitMembers = true;
- }
-
- Assert.True(hitMembers, "No members were found in the room");
- }
-
- [Fact]
- public async Task JoinAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- var id = await room.JoinAsync();
- Assert.NotNull(id);
- Assert.NotNull(id.RoomId);
- Assert.NotEmpty(id.RoomId);
- }
-
- [Fact]
- public async Task ForgetAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- await room.ForgetAsync();
- }
-
- [Fact]
- public async Task LeaveAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- await room.LeaveAsync();
- }
-
- [Fact]
- public async Task KickAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var hs2 = await HomeserverAbstraction.GetRandomHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- await room.InviteUserAsync(hs2.UserId, "Unit test!");
- await hs2.GetRoom(room.RoomId).JoinAsync();
- await room.KickAsync(hs2.UserId, "test");
- var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
- Assert.NotNull(banState);
- Assert.Equal("leave", banState.Membership);
- }
-
- [Fact]
- public async Task BanAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var hs2 = await HomeserverAbstraction.GetRandomHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- await room.BanAsync(hs2.UserId, "test");
- var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
- Assert.NotNull(banState);
- Assert.Equal("ban", banState.Membership);
- }
-
- [Fact]
- public async Task UnbanAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var hs2 = await HomeserverAbstraction.GetRandomHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- await room.BanAsync(hs2.UserId, "test");
- var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
- Assert.NotNull(banState);
- Assert.Equal("ban", banState.Membership);
- await room.UnbanAsync(hs2.UserId);
- var unbanState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
- Assert.NotNull(unbanState);
- Assert.Equal("leave", unbanState.Membership);
- }
-
- [SkippableFact(typeof(MatrixException))]
- public async Task SendStateEventAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
-
- await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", new UserProfileResponse() {
- DisplayName = "wee_woo",
- AvatarUrl = "no"
- });
- await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", "state_key_maybe", new UserProfileResponse() {
- DisplayName = "wee_woo",
- AvatarUrl = "yes"
- });
- }
-
- [SkippableFact(typeof(MatrixException))]
- public async Task SendAndGetStateEventAsync() {
- await SendStateEventAsync();
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
-
- await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", new UserProfileResponse() {
- DisplayName = "wee_woo",
- AvatarUrl = "no"
- });
- await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", "state_key_maybe", new UserProfileResponse() {
- DisplayName = "wee_woo",
- AvatarUrl = "yes"
- });
-
- var state1 = await room.GetStateAsync<UserProfileResponse>("gay.rory.libmatrix.unit_tests");
- Assert.NotNull(state1);
- Assert.NotNull(state1.DisplayName);
- Assert.NotEmpty(state1.DisplayName);
- Assert.NotNull(state1.AvatarUrl);
- Assert.NotEmpty(state1.AvatarUrl);
- Assert.Equal("wee_woo", state1.DisplayName);
- Assert.Equal("no", state1.AvatarUrl);
-
- var state2 = await room.GetStateAsync<UserProfileResponse>("gay.rory.libmatrix.unit_tests", "state_key_maybe");
- Assert.NotNull(state2);
- Assert.NotNull(state2.DisplayName);
- Assert.NotEmpty(state2.DisplayName);
- Assert.NotNull(state2.AvatarUrl);
- Assert.NotEmpty(state2.AvatarUrl);
- Assert.Equal("wee_woo", state2.DisplayName);
- Assert.Equal("yes", state2.AvatarUrl);
- }
-
- [Fact]
- public async Task DisbandAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
-
- await room.PermanentlyBrickRoomAsync();
- }
-
- [Fact]
- public async Task SendFileAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
-
- var res = await room.SendFileAsync("test.txt", new MemoryStream(Encoding.UTF8.GetBytes("This test was written by Emma [it/its], member of the Rory& system." +
- "\nIf you are reading this on matrix, it means the unit test for uploading a file works!")));
- Assert.NotNull(res);
- Assert.NotNull(res.EventId);
- }
-
- [Fact]
- public async Task GetSpaceChildrenAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var space = await RoomAbstraction.GetTestSpace(hs, 2, false, 1);
- Assert.NotNull(space);
- var children = space.GetChildrenAsync();
- Assert.NotNull(children);
- var found = 0;
- await foreach (var room in children) found++;
- Assert.Equal(2, found);
- }
-
- [Fact]
- public async Task InviteAndJoinAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- var otherUsers = HomeserverAbstraction.GetRandomHomeservers(15);
- Assert.NotNull(room);
-
- // var expectedCount = 1;
-
- var tasks = new List<Task>();
- await foreach (var otherUser in otherUsers)
- tasks.Add(Task.Run(async () => {
- await room.InviteUserAsync(otherUser.UserId);
- await otherUser.GetRoom(room.RoomId).JoinAsync();
- }));
- await Task.WhenAll(tasks);
-
- var states = await room.GetMembersListAsync(false);
- Assert.Equal(16, states.Count);
- }
-}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/OtherRoomTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/OtherRoomTests.cs
new file mode 100644
index 0000000..1ae195d
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/OtherRoomTests.cs
@@ -0,0 +1,101 @@
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests.BasicRoomEventTests;
+
+public class OtherRoomTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public OtherRoomTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [SkippableFact(typeof(MatrixException))]
+ public async Task GetCanonicalAliasAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var alias = await room.GetCanonicalAliasAsync();
+ Assert.NotNull(alias);
+ Assert.NotNull(alias.Alias);
+ Assert.NotEmpty(alias.Alias);
+ }
+
+ [Fact]
+ public async Task GetJoinRuleAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var rule = await room.GetJoinRuleAsync();
+ Assert.NotNull(rule);
+ Assert.NotNull(rule.JoinRuleValue);
+ Assert.NotEmpty(rule.JoinRuleValue);
+ }
+
+ [Fact]
+ public async Task GetHistoryVisibilityAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var visibility = await room.GetHistoryVisibilityAsync();
+ Assert.NotNull(visibility);
+ Assert.NotNull(visibility.HistoryVisibility);
+ Assert.NotEmpty(visibility.HistoryVisibility);
+ }
+
+ [Fact]
+ public async Task GetGuestAccessAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ try {
+ var access = await room.GetGuestAccessAsync();
+ Assert.NotNull(access);
+ Assert.NotNull(access.GuestAccess);
+ Assert.NotEmpty(access.GuestAccess);
+ }
+ catch (Exception e) {
+ if (e is not MatrixException exception) throw;
+ Assert.Equal("M_NOT_FOUND", exception.ErrorCode);
+ }
+ }
+
+ [Fact]
+ public async Task GetCreateEventAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var create = await room.GetCreateEventAsync();
+ Assert.NotNull(create);
+ Assert.NotNull(create.Creator);
+ Assert.NotEmpty(create.RoomVersion!);
+ }
+
+ [Fact]
+ public async Task GetRoomType() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.GetRoomType();
+ }
+
+ [Fact]
+ public async Task GetPowerLevelsAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var power = await room.GetPowerLevelsAsync();
+ Assert.NotNull(power);
+ Assert.NotNull(power.Ban);
+ Assert.NotNull(power.Kick);
+ Assert.NotNull(power.Invite);
+ Assert.NotNull(power.Redact);
+ Assert.NotNull(power.StateDefault);
+ Assert.NotNull(power.EventsDefault);
+ Assert.NotNull(power.UsersDefault);
+ Assert.NotNull(power.Users);
+ // Assert.NotNull(power.Events);
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomAvatarTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomAvatarTests.cs
new file mode 100644
index 0000000..78f007c
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomAvatarTests.cs
@@ -0,0 +1,27 @@
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests.BasicRoomEventTests;
+
+public class RoomAvatarTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public RoomAvatarTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [SkippableFact(typeof(MatrixException))]
+ public async Task GetAvatarUrlAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var url = await room.GetAvatarUrlAsync();
+ Assert.NotNull(url);
+ Assert.NotNull(url.Url);
+ Assert.NotEmpty(url.Url);
+
+ await room.LeaveAsync();
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomNameTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomNameTests.cs
new file mode 100644
index 0000000..1ea3e18
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomNameTests.cs
@@ -0,0 +1,42 @@
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests.BasicRoomEventTests;
+
+public class RoomNameTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public RoomNameTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [Fact]
+ public async Task GetNameAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var name = await room.GetNameAsync();
+ Assert.NotNull(name);
+ Assert.NotEmpty(name);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task SetNameAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var name = Guid.NewGuid().ToString();
+ await room.SendStateEventAsync(RoomNameEventContent.EventId, new RoomNameEventContent { Name = name });
+ var newName = await room.GetNameAsync();
+ Assert.Equal(name, newName);
+
+ await room.LeaveAsync();
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomTopicTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomTopicTests.cs
new file mode 100644
index 0000000..6610035
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/BasicRoomEventTests/RoomTopicTests.cs
@@ -0,0 +1,27 @@
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests.BasicRoomEventTests;
+
+public class RoomTopicTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public RoomTopicTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [SkippableFact(typeof(MatrixException))]
+ public async Task GetTopicAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var topic = await room.GetTopicAsync();
+ Assert.NotNull(topic);
+ Assert.NotNull(topic.Topic);
+ Assert.NotEmpty(topic.Topic);
+
+ await room.LeaveAsync();
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomEventTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomEventTests.cs
index 932909f..9081a5a 100644
--- a/Tests/LibMatrix.Tests/Tests/RoomEventTests.cs
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomEventTests.cs
@@ -8,23 +8,16 @@ using Xunit.Microsoft.DependencyInjection.Abstracts;
namespace LibMatrix.Tests.Tests;
public class RoomEventTests : TestBed<TestFixture> {
- private readonly TestFixture _fixture;
- private readonly HomeserverResolverService _resolver;
- private readonly Config _config;
- private readonly HomeserverProviderService _provider;
+ private readonly HomeserverAbstraction _hsAbstraction;
public RoomEventTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
- _fixture = fixture;
- _resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
- _config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
- _provider = _fixture.GetService<HomeserverProviderService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverProviderService)}");
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
}
- private async Task<AuthenticatedHomeserverGeneric> GetHomeserver() => await HomeserverAbstraction.GetHomeserver();
-
[Fact]
public async Task GetNameAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var name = await room.GetNameAsync();
@@ -34,7 +27,7 @@ public class RoomEventTests : TestBed<TestFixture> {
[SkippableFact(typeof(MatrixException))]
public async Task GetTopicAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var topic = await room.GetTopicAsync();
@@ -44,19 +37,8 @@ public class RoomEventTests : TestBed<TestFixture> {
}
[SkippableFact(typeof(MatrixException))]
- public async Task GetAliasesAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
- var room = await RoomAbstraction.GetTestRoom(hs);
- Assert.NotNull(room);
- var aliases = await room.GetAliasesAsync();
- Assert.NotNull(aliases);
- Assert.NotEmpty(aliases);
- Assert.All(aliases, Assert.NotNull);
- }
-
- [SkippableFact(typeof(MatrixException))]
public async Task GetCanonicalAliasAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var alias = await room.GetCanonicalAliasAsync();
@@ -67,40 +49,46 @@ public class RoomEventTests : TestBed<TestFixture> {
[SkippableFact(typeof(MatrixException))]
public async Task GetAvatarUrlAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var url = await room.GetAvatarUrlAsync();
Assert.NotNull(url);
Assert.NotNull(url.Url);
Assert.NotEmpty(url.Url);
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetJoinRuleAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var rule = await room.GetJoinRuleAsync();
Assert.NotNull(rule);
Assert.NotNull(rule.JoinRuleValue);
Assert.NotEmpty(rule.JoinRuleValue);
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetHistoryVisibilityAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var visibility = await room.GetHistoryVisibilityAsync();
Assert.NotNull(visibility);
Assert.NotNull(visibility.HistoryVisibility);
Assert.NotEmpty(visibility.HistoryVisibility);
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetGuestAccessAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
try {
@@ -113,30 +101,36 @@ public class RoomEventTests : TestBed<TestFixture> {
if (e is not MatrixException exception) throw;
Assert.Equal("M_NOT_FOUND", exception.ErrorCode);
}
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetCreateEventAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var create = await room.GetCreateEventAsync();
Assert.NotNull(create);
Assert.NotNull(create.Creator);
Assert.NotEmpty(create.RoomVersion!);
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetRoomType() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
await room.GetRoomType();
+
+ await room.LeaveAsync();
}
[Fact]
public async Task GetPowerLevelsAsync() {
- var hs = await HomeserverAbstraction.GetHomeserver();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
var room = await RoomAbstraction.GetTestRoom(hs);
Assert.NotNull(room);
var power = await room.GetPowerLevelsAsync();
@@ -150,5 +144,7 @@ public class RoomEventTests : TestBed<TestFixture> {
Assert.NotNull(power.UsersDefault);
Assert.NotNull(power.Users);
// Assert.NotNull(power.Events);
+
+ await room.LeaveAsync();
}
}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/RoomMembershipTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomMembershipTests.cs
new file mode 100644
index 0000000..2e552e2
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomMembershipTests.cs
@@ -0,0 +1,178 @@
+using System.Diagnostics;
+using System.Text;
+using ArcaneLibs.Extensions;
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.Homeservers;
+using LibMatrix.Responses;
+using LibMatrix.Services;
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests;
+
+public class RoomMembershipTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public RoomMembershipTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [Fact]
+ public async Task GetMembersAsync() {
+ Assert.True(StateEvent.KnownStateEventTypes is { Count: > 0 }, "StateEvent.KnownStateEventTypes is empty!");
+ Assert.True(StateEvent.KnownStateEventTypesByName is { Count: > 0 }, "StateEvent.KnownStateEventTypesByName is empty!");
+
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var members = room.GetMembersEnumerableAsync();
+ Assert.NotNull(members);
+ var hitMembers = false;
+ await foreach (var member in members) {
+ Assert.NotNull(member);
+ Assert.NotNull(member.StateKey);
+ Assert.NotEmpty(member.StateKey);
+ Assert.NotNull(member.Sender);
+ Assert.NotEmpty(member.Sender);
+ Assert.NotNull(member.RawContent);
+ Assert.NotEmpty(member.RawContent);
+ Assert.NotNull(member.TypedContent);
+ Assert.IsType<RoomMemberEventContent>(member.TypedContent);
+ var content = (RoomMemberEventContent)member.TypedContent;
+ Assert.NotNull(content);
+ Assert.NotNull(content.Membership);
+ Assert.NotEmpty(content.Membership);
+ hitMembers = true;
+ }
+
+ Assert.True(hitMembers, "No members were found in the room");
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task JoinAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver(_testOutputHelper);
+ var hs2 = await _hsAbstraction.GetNewHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.SendStateEventAsync(RoomJoinRulesEventContent.EventId, new RoomJoinRulesEventContent() {
+ JoinRule = RoomJoinRulesEventContent.JoinRules.Public
+ });
+ // var id = await room.JoinAsync();
+ var id = await hs2.GetRoom(room.RoomId).JoinAsync();
+ Assert.NotNull(id);
+ Assert.NotNull(id.RoomId);
+ Assert.NotEmpty(id.RoomId);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task ForgetAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.ForgetAsync();
+ }
+
+ [Fact]
+ public async Task LeaveAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task KickAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var hs2 = await _hsAbstraction.GetNewHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.InviteUserAsync(hs2.UserId, "Unit test!");
+ await hs2.GetRoom(room.RoomId).JoinAsync();
+ await room.KickAsync(hs2.UserId, "test");
+ var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
+ Assert.NotNull(banState);
+ Assert.Equal("leave", banState.Membership);
+ Assert.Equal("test", banState.Reason);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task BanAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var hs2 = await _hsAbstraction.GetNewHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.BanAsync(hs2.UserId, "test");
+ var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
+ Assert.NotNull(banState);
+ Assert.Equal("ban", banState.Membership);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task UnbanAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var hs2 = await _hsAbstraction.GetNewHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ await room.BanAsync(hs2.UserId, "test");
+ var banState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
+ Assert.NotNull(banState);
+ Assert.Equal("ban", banState.Membership);
+ await room.UnbanAsync(hs2.UserId, "testing");
+
+ var unbanState = await room.GetStateAsync<RoomMemberEventContent>("m.room.member", hs2.UserId);
+ Assert.NotNull(unbanState);
+ Assert.Equal("leave", unbanState.Membership);
+ Assert.Equal("testing", unbanState.Reason);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task InviteAndJoinAsync() {
+ int count = 5;
+
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ var otherUsers = _hsAbstraction.GetNewHomeservers(count);
+ Assert.NotNull(room);
+
+ // var expectedCount = 1;
+
+ // var tasks = new List<Task>();
+ // await foreach (var otherUser in otherUsers)
+ // tasks.AddRange([
+ // room.InviteUserAsync(otherUser.UserId),
+ // otherUser.GetRoom(room.RoomId).JoinAsync()
+ // ]);
+
+ Dictionary<AuthenticatedHomeserverGeneric, Task> tasks = new();
+ await foreach (var otherUser in otherUsers) {
+ _testOutputHelper.WriteLine($"Inviting {otherUser.UserId} to {room.RoomId}");
+ tasks.Add(otherUser, room.InviteUserAsync(otherUser.UserId, "Unit test!"));
+ }
+
+ await foreach (var otherUser in tasks.ToAsyncEnumerable()) {
+ _testOutputHelper.WriteLine($"Joining {otherUser.UserId} to {room.RoomId}");
+ await otherUser.GetRoom(room.RoomId).JoinAsync(reason: "Unit test!");
+ }
+
+ var states = await room.GetMembersListAsync(false);
+ Assert.Equal(count + 1, states.Count);
+
+ await room.LeaveAsync();
+ await foreach (var authenticatedHomeserverGeneric in otherUsers)
+ {
+ await authenticatedHomeserverGeneric.GetRoom(room.RoomId).LeaveAsync();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/RoomTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomTests.cs
new file mode 100644
index 0000000..401b24f
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/RoomTests.cs
@@ -0,0 +1,320 @@
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using ArcaneLibs.Extensions;
+using LibMatrix.EventTypes.Spec;
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.Homeservers;
+using LibMatrix.Responses;
+using LibMatrix.Services;
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests;
+
+public class RoomTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public RoomTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [Fact]
+ public async Task GetJoinedRoomsAsync() {
+ var hs = await _hsAbstraction.GetNewHomeserver();
+ //make 100 rooms
+ var createRoomTasks = Enumerable.Range(0, 10).Select(_ => RoomAbstraction.GetTestRoom(hs)).ToList();
+ await Task.WhenAll(createRoomTasks);
+
+ var rooms = await hs.GetJoinedRooms();
+ Assert.NotNull(rooms);
+ Assert.NotEmpty(rooms);
+ Assert.All(rooms, Assert.NotNull);
+ // Assert.True(rooms.Count >= 10, "Not enough rooms were found");
+ Assert.Equal(10, rooms.Count);
+ await hs.Logout();
+ }
+
+ [Fact]
+ public async Task GetMembersAsync() {
+ Assert.True(StateEvent.KnownStateEventTypes is { Count: > 0 }, "StateEvent.KnownStateEventTypes is empty!");
+ Assert.True(StateEvent.KnownStateEventTypesByName is { Count: > 0 }, "StateEvent.KnownStateEventTypesByName is empty!");
+
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+ var members = room.GetMembersEnumerableAsync();
+ Assert.NotNull(members);
+ var hitMembers = false;
+ await foreach (var member in members) {
+ Assert.NotNull(member);
+ Assert.NotNull(member.StateKey);
+ Assert.NotEmpty(member.StateKey);
+ Assert.NotNull(member.Sender);
+ Assert.NotEmpty(member.Sender);
+ Assert.NotNull(member.RawContent);
+ Assert.NotEmpty(member.RawContent);
+ Assert.NotNull(member.TypedContent);
+ Assert.IsType<RoomMemberEventContent>(member.TypedContent);
+ var content = (RoomMemberEventContent)member.TypedContent;
+ Assert.NotNull(content);
+ Assert.NotNull(content.Membership);
+ Assert.NotEmpty(content.Membership);
+ hitMembers = true;
+ }
+
+ Assert.True(hitMembers, "No members were found in the room");
+
+ await room.LeaveAsync();
+ }
+
+ [SkippableFact(typeof(MatrixException))]
+ public async Task SendStateEventAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", new UserProfileResponse() {
+ DisplayName = "wee_woo",
+ AvatarUrl = "no"
+ });
+ await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", "state_key_maybe", new UserProfileResponse() {
+ DisplayName = "wee_woo",
+ AvatarUrl = "yes"
+ });
+
+ await room.LeaveAsync();
+ }
+
+ [SkippableFact(typeof(MatrixException))]
+ public async Task SendAndGetStateEventAsync() {
+ await SendStateEventAsync();
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", new UserProfileResponse() {
+ DisplayName = "wee_woo",
+ AvatarUrl = "no"
+ });
+ await room.SendStateEventAsync("gay.rory.libmatrix.unit_tests", "state_key_maybe", new UserProfileResponse() {
+ DisplayName = "wee_woo",
+ AvatarUrl = "yes"
+ });
+
+ var state1 = await room.GetStateAsync<UserProfileResponse>("gay.rory.libmatrix.unit_tests");
+ Assert.NotNull(state1);
+ Assert.NotNull(state1.DisplayName);
+ Assert.NotEmpty(state1.DisplayName);
+ Assert.NotNull(state1.AvatarUrl);
+ Assert.NotEmpty(state1.AvatarUrl);
+ Assert.Equal("wee_woo", state1.DisplayName);
+ Assert.Equal("no", state1.AvatarUrl);
+
+ var state2 = await room.GetStateAsync<UserProfileResponse>("gay.rory.libmatrix.unit_tests", "state_key_maybe");
+ Assert.NotNull(state2);
+ Assert.NotNull(state2.DisplayName);
+ Assert.NotEmpty(state2.DisplayName);
+ Assert.NotNull(state2.AvatarUrl);
+ Assert.NotEmpty(state2.AvatarUrl);
+ Assert.Equal("wee_woo", state2.DisplayName);
+ Assert.Equal("yes", state2.AvatarUrl);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task DisbandAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ await room.PermanentlyBrickRoomAsync();
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task SendFileAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var res = await room.SendFileAsync("test.txt", new MemoryStream(Encoding.UTF8.GetBytes("This test was written by Emma [it/its], member of the Rory& system." +
+ "\nIf you are reading this on matrix, it means the unit test for uploading a file works!")));
+ Assert.NotNull(res);
+ Assert.NotNull(res.EventId);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task GetFullStateAsListAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var state = await room.GetFullStateAsListAsync();
+ Assert.NotNull(state);
+ Assert.NotEmpty(state);
+ Assert.All(state, Assert.NotNull);
+ Assert.All(state, s => {
+ Assert.NotNull(s.EventId);
+ Assert.NotEmpty(s.EventId);
+ Assert.NotNull(s.Sender);
+ Assert.NotEmpty(s.Sender);
+ Assert.NotNull(s.RawContent);
+ Assert.NotNull(s.TypedContent);
+ });
+
+ await room.LeaveAsync();
+ }
+
+ [SkippableFact(typeof(LibMatrixException))]
+ public async Task GetStateEventAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var state = await room.GetStateEventAsync("m.room.name");
+ Assert.NotNull(state);
+ Assert.NotNull(state.EventId);
+ Assert.NotEmpty(state.EventId);
+ Assert.NotNull(state.Sender);
+ Assert.NotEmpty(state.Sender);
+ Assert.NotNull(state.RawContent);
+ Assert.NotEmpty(state.RawContent);
+ Assert.NotNull(state.TypedContent);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task GetStateEventIdAsync() {
+ var hs = await _hsAbstraction.GetNewHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var state = await room.GetStateEventIdAsync("m.room.name");
+ Assert.NotNull(state);
+ Assert.NotEmpty(state);
+
+ await room.LeaveAsync();
+ }
+
+ [SkippableFact(typeof(LibMatrixException))]
+ public async Task GetStateEventOrNullAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var state = await room.GetStateEventOrNullAsync("m.room.name");
+ Assert.NotNull(state);
+ Assert.NotNull(state.EventId);
+ Assert.NotEmpty(state.EventId);
+ Assert.NotNull(state.Sender);
+ Assert.NotEmpty(state.Sender);
+ Assert.NotNull(state.RawContent);
+ Assert.NotEmpty(state.RawContent);
+ Assert.NotNull(state.TypedContent);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task GetMessagesAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var messages = await room.GetMessagesAsync();
+ Assert.NotNull(messages);
+ Assert.NotNull(messages.Chunk);
+ Assert.NotEmpty(messages.Chunk);
+ Assert.All(messages.Chunk, Assert.NotNull);
+ Assert.All(messages.Chunk, m => {
+ Assert.NotNull(m.EventId);
+ Assert.NotEmpty(m.EventId);
+ Assert.NotNull(m.Sender);
+ Assert.NotEmpty(m.Sender);
+ Assert.NotNull(m.RawContent);
+ Assert.NotNull(m.TypedContent);
+ });
+
+ await room.LeaveAsync();
+
+ await File.WriteAllTextAsync("test.json", messages.ToJson());
+ }
+
+ [Fact]
+ public async Task GetManyMessagesAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var messages = room.GetManyMessagesAsync(chunkSize: 2);
+ await foreach (var resp in messages) {
+ Assert.NotNull(resp);
+ Assert.NotNull(resp.Chunk);
+ // Assert.NotEmpty(resp.Chunk);
+ Assert.All(resp.Chunk, Assert.NotNull);
+ Assert.All(resp.Chunk, m => {
+ Assert.NotNull(m.EventId);
+ Assert.NotEmpty(m.EventId);
+ Assert.NotNull(m.Sender);
+ Assert.NotEmpty(m.Sender);
+ Assert.NotNull(m.RawContent);
+ Assert.NotNull(m.TypedContent);
+ });
+ }
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task SendMessageEventAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var res = await room.SendMessageEventAsync(new RoomMessageEventContent(body: "This test was written by Emma [it/its], member of the Rory& system." +
+ "\nIf you are reading this on matrix, it means the unit test for sending a message works!", messageType: "m.text"));
+ Assert.NotNull(res);
+ Assert.NotNull(res.EventId);
+
+ await room.LeaveAsync();
+ }
+
+ [Fact]
+ public async Task InviteUsersAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var room = await RoomAbstraction.GetTestRoom(hs);
+ Assert.NotNull(room);
+
+ var users = _hsAbstraction.GetNewHomeservers(32).ToBlockingEnumerable().ToList();
+ Assert.NotNull(users);
+ Assert.NotEmpty(users);
+ Assert.All(users, Assert.NotNull);
+ Assert.All(users, u => {
+ Assert.NotNull(u);
+ Assert.NotNull(u.UserId);
+ Assert.NotEmpty(u.UserId);
+ });
+
+ await room.InviteUsersAsync(users.Select(u => u.UserId));
+ var members = await room.GetMembersListAsync(false);
+ Assert.NotNull(members);
+ Assert.NotEmpty(members);
+ Assert.All(members, Assert.NotNull);
+ Assert.All(members, m => {
+ Assert.NotNull(m);
+ Assert.NotNull(m.StateKey);
+ Assert.NotEmpty(m.StateKey);
+ });
+ Assert.All(users, u => Assert.Contains(u.UserId, members.Select(m => m.StateKey)));
+
+ await room.LeaveAsync();
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/RoomTests/SpaceTests.cs b/Tests/LibMatrix.Tests/Tests/RoomTests/SpaceTests.cs
new file mode 100644
index 0000000..148b5fe
--- /dev/null
+++ b/Tests/LibMatrix.Tests/Tests/RoomTests/SpaceTests.cs
@@ -0,0 +1,101 @@
+using System.Diagnostics;
+using System.Text;
+using ArcaneLibs.Extensions;
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.Homeservers;
+using LibMatrix.Responses;
+using LibMatrix.RoomTypes;
+using LibMatrix.Services;
+using LibMatrix.Tests.Abstractions;
+using LibMatrix.Tests.Fixtures;
+using Xunit.Abstractions;
+using Xunit.Microsoft.DependencyInjection.Abstracts;
+
+namespace LibMatrix.Tests.Tests;
+
+public class SpaceTests : TestBed<TestFixture> {
+ private readonly HomeserverAbstraction _hsAbstraction;
+
+ public SpaceTests(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+ _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+ }
+
+ [Fact]
+ public async Task AddChildAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var crq = new CreateRoomRequest() {
+ Name = "Test space"
+ };
+ crq.CreationContent["type"] = SpaceRoom.TypeName;
+ var space = (await hs.CreateRoom(crq)).AsSpace;
+
+ var child = await hs.CreateRoom(new CreateRoomRequest() {
+ Name = "Test child"
+ });
+
+ await space.AddChildAsync(child);
+
+ //validate children
+ var children = space.GetChildrenAsync().ToBlockingEnumerable().ToList();
+ Assert.NotNull(children);
+ Assert.NotEmpty(children);
+ Assert.Single(children, x => x.RoomId == child.RoomId);
+ }
+
+ [Fact]
+ public async Task AddChildByIdAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var crq = new CreateRoomRequest() {
+ Name = "Test space"
+ };
+ crq.CreationContent["type"] = SpaceRoom.TypeName;
+ var space = (await hs.CreateRoom(crq)).AsSpace;
+
+ var child = await hs.CreateRoom(new CreateRoomRequest() {
+ Name = "Test child"
+ });
+
+ await space.AddChildByIdAsync(child.RoomId);
+
+ //validate children
+ var children = space.GetChildrenAsync().ToBlockingEnumerable().ToList();
+ Assert.NotNull(children);
+ Assert.NotEmpty(children);
+ Assert.Single(children, x => x.RoomId == child.RoomId);
+ }
+
+ [Fact]
+ public async Task GetChildrenAsync() {
+ var hs = await _hsAbstraction.GetConfiguredHomeserver();
+ var expectedChildren = Enumerable.Range(0, 10).Select(async _ => {
+ var room = await hs.CreateRoom(new CreateRoomRequest() {
+ Name = "Test child"
+ });
+ return room;
+ }).ToAsyncEnumerable().ToBlockingEnumerable().ToList();
+
+ var crq = new CreateRoomRequest() {
+ Name = "Test space",
+ InitialState = expectedChildren.Select(c => new StateEvent() {
+ Type = "m.space.child",
+ StateKey = c.RoomId,
+ TypedContent = new SpaceChildEventContent() {
+ Via = new List<string> {
+ c.RoomId.Split(":")[1]
+ }
+ }
+ }).ToList()
+ };
+ crq.CreationContent["type"] = SpaceRoom.TypeName;
+ var space = (await hs.CreateRoom(crq)).AsSpace;
+
+ var children = space.GetChildrenAsync().ToBlockingEnumerable().ToList();
+ Assert.NotNull(children);
+ Assert.NotEmpty(children);
+ Assert.Equal(expectedChildren.Count, children.Count);
+ foreach (var expectedChild in expectedChildren)
+ {
+ Assert.Single(children, x => x.RoomId == expectedChild.RoomId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tests/LibMatrix.Tests/Tests/TestCleanup.cs b/Tests/LibMatrix.Tests/Tests/TestCleanup.cs
index 7fc7c64..1c5747c 100644
--- a/Tests/LibMatrix.Tests/Tests/TestCleanup.cs
+++ b/Tests/LibMatrix.Tests/Tests/TestCleanup.cs
@@ -1,74 +1,69 @@
-using System.Diagnostics;
-using LibMatrix.Helpers;
-using LibMatrix.Services;
-using LibMatrix.Tests.Abstractions;
-using LibMatrix.Tests.Fixtures;
-using Microsoft.Extensions.Logging;
-using Xunit.Abstractions;
-using Xunit.Microsoft.DependencyInjection.Abstracts;
-
-namespace LibMatrix.Tests.Tests;
-
-public class TestCleanup : TestBed<TestFixture> {
- // private readonly TestFixture _fixture;
- private readonly HomeserverResolverService _resolver;
- private readonly Config _config;
- private readonly HomeserverProviderService _provider;
- private readonly ILogger<TestCleanup> _logger;
-
- public TestCleanup(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
- // _fixture = fixture;
- _resolver = _fixture.GetService<HomeserverResolverService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverResolverService)}");
- _config = _fixture.GetService<Config>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(Config)}");
- _provider = _fixture.GetService<HomeserverProviderService>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverProviderService)}");
- _logger = _fixture.GetService<ILogger<TestCleanup>>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(ILogger<TestCleanup>)}");
- }
-
- [Fact]
- public async Task Cleanup() {
- Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver), $"{nameof(_config.TestHomeserver)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestUsername), $"{nameof(_config.TestUsername)} must be set in appsettings!");
- Assert.False(string.IsNullOrWhiteSpace(_config.TestPassword), $"{nameof(_config.TestPassword)} must be set in appsettings!");
-
- var hs = await HomeserverAbstraction.GetHomeserver();
- Assert.NotNull(hs);
-
- var syncHelper = new SyncHelper(hs, _logger) {
- Timeout = 3000
- };
- _testOutputHelper.WriteLine("Starting sync loop");
- var cancellationTokenSource = new CancellationTokenSource();
- var sw = Stopwatch.StartNew();
- syncHelper.SyncReceivedHandlers.Add(async response => {
- if (sw.ElapsedMilliseconds >= 3000) {
- _testOutputHelper.WriteLine("Cancelling sync loop");
-
- var tasks = (await hs.GetJoinedRooms()).Select(async room => {
- _logger.LogInformation("Leaving room: {}", room.RoomId);
- await room.LeaveAsync();
- await room.ForgetAsync();
- return room;
- }).ToList();
- await Task.WhenAll(tasks);
-
- cancellationTokenSource.Cancel();
- }
-
- sw.Restart();
- if (response.Rooms?.Leave is { Count: > 0 }) {
- // foreach (var room in response.Rooms.Leave) {
- // await hs.GetRoom(room.Key).ForgetAsync();
- // }
- var tasks = response.Rooms.Leave.Select(async room => {
- await hs.GetRoom(room.Key).ForgetAsync();
- return room;
- }).ToList();
- await Task.WhenAll(tasks);
- }
- });
- await syncHelper.RunSyncLoopAsync(cancellationToken: cancellationTokenSource.Token);
-
- Assert.NotNull(hs);
- await hs.Logout();
- }
-}
\ No newline at end of file
+// using System.Diagnostics;
+// using LibMatrix.Helpers;
+// using LibMatrix.Services;
+// using LibMatrix.Tests.Abstractions;
+// using LibMatrix.Tests.Fixtures;
+// using Microsoft.Extensions.Logging;
+// using Xunit.Abstractions;
+// using Xunit.Microsoft.DependencyInjection.Abstracts;
+//
+// namespace LibMatrix.Tests.Tests;
+//
+// public class TestCleanup : TestBed<TestFixture> {
+// private readonly HomeserverAbstraction _hsAbstraction;
+// private readonly ILogger<TestCleanup> _logger;
+//
+// public TestCleanup(ITestOutputHelper testOutputHelper, TestFixture fixture) : base(testOutputHelper, fixture) {
+// // _fixture = fixture;
+// _logger = _fixture.GetService<ILogger<TestCleanup>>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(ILogger<TestCleanup>)}");
+// _hsAbstraction = _fixture.GetService<HomeserverAbstraction>(_testOutputHelper) ?? throw new InvalidOperationException($"Failed to get {nameof(HomeserverAbstraction)}");
+// }
+//
+// [SkippableFact(typeof(MatrixException))]
+// public async Task Cleanup() {
+// // Assert.False(string.IsNullOrWhiteSpace(_config.TestHomeserver), $"{nameof(_config.TestHomeserver)} must be set in appsettings!");
+// // Assert.False(string.IsNullOrWhiteSpace(_config.TestUsername), $"{nameof(_config.TestUsername)} must be set in appsettings!");
+// // Assert.False(string.IsNullOrWhiteSpace(_config.TestPassword), $"{nameof(_config.TestPassword)} must be set in appsettings!");
+//
+// var hs = await _hsAbstraction.GetConfiguredHomeserver();
+// Assert.NotNull(hs);
+//
+// var syncHelper = new SyncHelper(hs, _logger) {
+// Timeout = 3000
+// };
+// _testOutputHelper.WriteLine("Starting sync loop");
+// var cancellationTokenSource = new CancellationTokenSource();
+// var sw = Stopwatch.StartNew();
+// syncHelper.SyncReceivedHandlers.Add(async response => {
+// // if (sw.ElapsedMilliseconds >= 3000) {
+// // _testOutputHelper.WriteLine("Cancelling sync loop");
+//
+// var tasks = (await hs.GetJoinedRooms()).Select(async room => {
+// _logger.LogInformation("Leaving room: {}", room.RoomId);
+// await room.LeaveAsync();
+// await room.ForgetAsync();
+// return room;
+// }).ToList();
+// await Task.WhenAll(tasks);
+//
+// // cancellationTokenSource.Cancel();
+// // }
+//
+// sw.Restart();
+// if (response.Rooms?.Leave is { Count: > 0 }) {
+// // foreach (var room in response.Rooms.Leave) {
+// // await hs.GetRoom(room.Key).ForgetAsync();
+// // }
+// var tasks2 = response.Rooms.Leave.Select(async room => {
+// await hs.GetRoom(room.Key).ForgetAsync();
+// return room;
+// }).ToList();
+// await Task.WhenAll(tasks2);
+// }
+// });
+// await syncHelper.RunSyncLoopAsync(cancellationToken: cancellationTokenSource.Token);
+//
+// Assert.NotNull(hs);
+// await hs.Logout();
+// }
+// }
\ No newline at end of file
diff --git a/Tests/TestDataGenerator/Program.cs b/Tests/TestDataGenerator/Program.cs
index 2583817..1168cae 100644
--- a/Tests/TestDataGenerator/Program.cs
+++ b/Tests/TestDataGenerator/Program.cs
@@ -9,12 +9,12 @@ using TestDataGenerator.Bot;
Console.WriteLine("Hello, World!");
var host = Host.CreateDefaultBuilder(args).ConfigureServices((_, services) => {
- services.AddScoped<TieredStorageService>(_ =>
- new TieredStorageService(
- new FileStorageProvider("bot_data/cache/"),
- new FileStorageProvider("bot_data/data/")
- )
- );
+ // services.AddScoped<TieredStorageService>(_ =>
+ // new TieredStorageService(
+ // new FileStorageProvider("bot_data/cache/"),
+ // new FileStorageProvider("bot_data/data/")
+ // )
+ // );
// services.AddSingleton<DataFetcherConfiguration>();
services.AddSingleton<AppServiceConfiguration>();
diff --git a/LibMatrix/Extensions/JsonElementExtensions.cs b/Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs
index c4ed743..c4ed743 100644
--- a/LibMatrix/Extensions/JsonElementExtensions.cs
+++ b/Utilities/LibMatrix.DebugDataValidationApi/JsonElementExtensions.cs
diff --git a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj
index 24fd617..3466fb1 100644
--- a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj
+++ b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj
@@ -9,8 +9,8 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0"/>
- <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0"/>
+ <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.5" />
+ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
<ItemGroup>
diff --git a/Utilities/LibMatrix.DevTestBot/Bot/FileStorageProvider.cs b/Utilities/LibMatrix.DevTestBot/Bot/FileStorageProvider.cs
index cc866e6..05b357e 100644
--- a/Utilities/LibMatrix.DevTestBot/Bot/FileStorageProvider.cs
+++ b/Utilities/LibMatrix.DevTestBot/Bot/FileStorageProvider.cs
@@ -1,36 +1,36 @@
-using System.Text.Json;
-using ArcaneLibs.Extensions;
-using LibMatrix.Interfaces.Services;
-using Microsoft.Extensions.Logging;
-
-namespace LibMatrix.ExampleBot.Bot;
-
-public class FileStorageProvider : IStorageProvider {
- private readonly ILogger<FileStorageProvider> _logger;
-
- public string TargetPath { get; }
-
- /// <summary>
- /// Creates a new instance of <see cref="FileStorageProvider" />.
- /// </summary>
- /// <param name="targetPath"></param>
- public FileStorageProvider(string targetPath) {
- new Logger<FileStorageProvider>(new LoggerFactory()).LogInformation("test");
- Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
- TargetPath = targetPath;
- if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath);
- }
-
- public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), value?.ToJson());
-
- public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
-
- public Task<bool> ObjectExistsAsync(string key) => Task.FromResult(File.Exists(Path.Join(TargetPath, key)));
-
- public Task<List<string>> GetAllKeysAsync() => Task.FromResult(Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList());
-
- public Task DeleteObjectAsync(string key) {
- File.Delete(Path.Join(TargetPath, key));
- return Task.CompletedTask;
- }
-}
\ No newline at end of file
+// using System.Text.Json;
+// using ArcaneLibs.Extensions;
+// using LibMatrix.Interfaces.Services;
+// using Microsoft.Extensions.Logging;
+//
+// namespace LibMatrix.ExampleBot.Bot;
+//
+// public class FileStorageProvider : IStorageProvider {
+// private readonly ILogger<FileStorageProvider> _logger;
+//
+// public string TargetPath { get; }
+//
+// /// <summary>
+// /// Creates a new instance of <see cref="FileStorageProvider" />.
+// /// </summary>
+// /// <param name="targetPath"></param>
+// public FileStorageProvider(string targetPath) {
+// new Logger<FileStorageProvider>(new LoggerFactory()).LogInformation("test");
+// Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
+// TargetPath = targetPath;
+// if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath);
+// }
+//
+// public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), value?.ToJson());
+//
+// public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
+//
+// public Task<bool> ObjectExistsAsync(string key) => Task.FromResult(File.Exists(Path.Join(TargetPath, key)));
+//
+// public Task<List<string>> GetAllKeysAsync() => Task.FromResult(Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList());
+//
+// public Task DeleteObjectAsync(string key) {
+// File.Delete(Path.Join(TargetPath, key));
+// return Task.CompletedTask;
+// }
+// }
\ No newline at end of file
diff --git a/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs b/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs
index b762937..f723c57 100644
--- a/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs
+++ b/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs
@@ -1,32 +1,32 @@
-using System.Text.Json;
-using ArcaneLibs.Extensions;
-using LibMatrix.Interfaces.Services;
-
-namespace LibMatrix.Utilities.Bot;
-
-public class FileStorageProvider : IStorageProvider {
- public string TargetPath { get; }
-
- /// <summary>
- /// Creates a new instance of <see cref="FileStorageProvider" />.
- /// </summary>
- /// <param name="targetPath"></param>
- public FileStorageProvider(string targetPath) {
- Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
- TargetPath = targetPath;
- if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath);
- }
-
- public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), value?.ToJson());
-
- public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
-
- public Task<bool> ObjectExistsAsync(string key) => Task.FromResult(File.Exists(Path.Join(TargetPath, key)));
-
- public Task<List<string>> GetAllKeysAsync() => Task.FromResult(Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList());
-
- public Task DeleteObjectAsync(string key) {
- File.Delete(Path.Join(TargetPath, key));
- return Task.CompletedTask;
- }
-}
\ No newline at end of file
+// using System.Text.Json;
+// using ArcaneLibs.Extensions;
+// using LibMatrix.Interfaces.Services;
+//
+// namespace LibMatrix.Utilities.Bot;
+//
+// public class FileStorageProvider : IStorageProvider {
+// public string TargetPath { get; }
+//
+// /// <summary>
+// /// Creates a new instance of <see cref="FileStorageProvider" />.
+// /// </summary>
+// /// <param name="targetPath"></param>
+// public FileStorageProvider(string targetPath) {
+// Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
+// TargetPath = targetPath;
+// if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath);
+// }
+//
+// public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), value?.ToJson());
+//
+// public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
+//
+// public Task<bool> ObjectExistsAsync(string key) => Task.FromResult(File.Exists(Path.Join(TargetPath, key)));
+//
+// public Task<List<string>> GetAllKeysAsync() => Task.FromResult(Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList());
+//
+// public Task DeleteObjectAsync(string key) {
+// File.Delete(Path.Join(TargetPath, key));
+// return Task.CompletedTask;
+// }
+// }
\ No newline at end of file
diff --git a/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj
index 89ea5af..6e67373 100644
--- a/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj
+++ b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj
@@ -12,9 +12,9 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0"/>
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
- <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0"/>
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
</ItemGroup>
|