summary refs log tree commit diff
path: root/testFrontend/SafeNSound.FakeUser
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-06-03 01:01:40 +0200
committerRory& <root@rory.gay>2025-06-03 01:01:40 +0200
commit6f3f08ed340e59a62a2d0428a5c32f99551ef1ce (patch)
treeff77390b1d3ea61414c14c94ac1fa2a05030879b /testFrontend/SafeNSound.FakeUser
parentMore alarm testing (diff)
downloadnodejs-final-assignment-6f3f08ed340e59a62a2d0428a5c32f99551ef1ce.tar.xz
Fix performance issues, add fake user bot to test client, more testing
Diffstat (limited to 'testFrontend/SafeNSound.FakeUser')
-rw-r--r--testFrontend/SafeNSound.FakeUser/MonitorService.cs52
-rw-r--r--testFrontend/SafeNSound.FakeUser/Program.cs22
-rw-r--r--testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs35
-rw-r--r--testFrontend/SafeNSound.FakeUser/SafeNSound.FakeUser.csproj10
-rw-r--r--testFrontend/SafeNSound.FakeUser/UserStore.cs97
-rw-r--r--testFrontend/SafeNSound.FakeUser/appsettings.json13
6 files changed, 228 insertions, 1 deletions
diff --git a/testFrontend/SafeNSound.FakeUser/MonitorService.cs b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
new file mode 100644

index 0000000..57d90a5 --- /dev/null +++ b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
@@ -0,0 +1,52 @@ +using ArcaneLibs.Extensions; + +namespace SafeNSound.FakeUser; + +public class MonitorService(ILogger<MonitorService> logger, UserStore userStore): IHostedService { + private Task? _getAllAlarmsTask, _assignBudgetTask; + private readonly CancellationTokenSource _cts = new(); + + public async Task StartAsync(CancellationToken cancellationToken) { + _getAllAlarmsTask = GetAllAlarms(_cts.Token); + _assignBudgetTask = AssignBudget(_cts.Token); + } + + private async Task GetAllAlarms(CancellationToken cancellationToken) { + while (!cancellationToken.IsCancellationRequested) { + try { + var user = userStore.GetRandomMonitor(); + var alarms = await user.Client!.GetAllAlarms(); + if(alarms.Count > 0) + logger.LogInformation("Monitor {UserId} has outstanding alarms: {Alarm}", user.Auth.Username, alarms.ToJson(indent: false)); + // else + // logger.LogInformation("Monitor {UserId} found no alarms to query", user.Auth.Username); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } catch (Exception ex) { + logger.LogError(ex, "Error querying alarm"); + } + } + } + + private async Task AssignBudget(CancellationToken cancellationToken) { + while (!cancellationToken.IsCancellationRequested) { + try { + var user = userStore.GetRandomMonitor(); + // var alarms = await user.Client!.GetAllAlarms(); + // if(alarms.Count > 0) + // logger.LogInformation("Monitor {UserId} has outstanding alarms: {Alarm}", user.Auth.Username, alarms.ToJson(indent: false)); + // else + // logger.LogInformation("Monitor {UserId} found no alarms to query", user.Auth.Username); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + + } catch (Exception ex) { + logger.LogError(ex, "Error querying alarm"); + } + + } + } + + public async Task StopAsync(CancellationToken cancellationToken) { + await _cts.CancelAsync(); + await _getAllAlarmsTask!; + } +} \ No newline at end of file diff --git a/testFrontend/SafeNSound.FakeUser/Program.cs b/testFrontend/SafeNSound.FakeUser/Program.cs
index 3751555..7c3eaff 100644 --- a/testFrontend/SafeNSound.FakeUser/Program.cs +++ b/testFrontend/SafeNSound.FakeUser/Program.cs
@@ -1,2 +1,24 @@ // See https://aka.ms/new-console-template for more information + +using SafeNSound.FakeUser; +using SafeNSound.Sdk; + Console.WriteLine("Hello, World!"); + +var builder = Host.CreateApplicationBuilder(args); +// longer shutdown timeout +builder.Services.Configure<HostOptions>(options => { + options.ShutdownTimeout = TimeSpan.FromSeconds(120); +}); + +builder.Services.AddSingleton<SafeNSoundConfiguration>(); +builder.Services.AddSingleton<SafeNSoundAuthentication>(); +builder.Services.AddSingleton<UserStore>(); +builder.Services.AddHostedService<UserStore>(sp => sp.GetRequiredService<UserStore>()); +builder.Services.AddHostedService<RandomAlarmService>(); +builder.Services.AddHostedService<MonitorService>(); + +// WrappedHttpClient.LogRequests = false; + +var host = builder.Build(); +host.Run(); \ No newline at end of file diff --git a/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs b/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs new file mode 100644
index 0000000..7835f89 --- /dev/null +++ b/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs
@@ -0,0 +1,35 @@ +namespace SafeNSound.FakeUser; + +public class RandomAlarmService(UserStore userStore): IHostedService { + private Task? _listenerTask; + private readonly CancellationTokenSource _cts = new(); + + public async Task StartAsync(CancellationToken cancellationToken) { + _listenerTask = Run(_cts.Token); + } + + private async Task Run(CancellationToken cancellationToken) { + while (!cancellationToken.IsCancellationRequested) { + try { + var user = userStore.GetRandomUser(); + if (Random.Shared.Next(100) > 90) { + await user.Client!.SetAlarm(new Sdk.AlarmDto { + Reason = "fall" + }); + } + else { + await user.Client!.DeleteAlarm(); + } + } + catch (Exception ex) { + Console.WriteLine($"Error setting/deleting alarm: {ex.Message}"); + } + + await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken); + } + } + + public async Task StopAsync(CancellationToken cancellationToken) { + await _cts.CancelAsync(); + } +} \ No newline at end of file diff --git a/testFrontend/SafeNSound.FakeUser/SafeNSound.FakeUser.csproj b/testFrontend/SafeNSound.FakeUser/SafeNSound.FakeUser.csproj
index fd4bd08..830faaa 100644 --- a/testFrontend/SafeNSound.FakeUser/SafeNSound.FakeUser.csproj +++ b/testFrontend/SafeNSound.FakeUser/SafeNSound.FakeUser.csproj
@@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk.Worker"> <PropertyGroup> <OutputType>Exe</OutputType> @@ -7,4 +7,12 @@ <Nullable>enable</Nullable> </PropertyGroup> + <ItemGroup> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2"/> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\SafeNSound.Sdk\SafeNSound.Sdk.csproj" /> + </ItemGroup> + </Project> diff --git a/testFrontend/SafeNSound.FakeUser/UserStore.cs b/testFrontend/SafeNSound.FakeUser/UserStore.cs new file mode 100644
index 0000000..9b04efb --- /dev/null +++ b/testFrontend/SafeNSound.FakeUser/UserStore.cs
@@ -0,0 +1,97 @@ +using SafeNSound.Sdk; + +namespace SafeNSound.FakeUser; + +public class UserStore(SafeNSoundAuthentication authService, SafeNSoundConfiguration config) : IHostedService { + public List<ClientContainer> Admins { get; } = Enumerable.Range(0, 1).Select(_ => new ClientContainer()).ToList(); + public List<ClientContainer> Monitors { get; } = Enumerable.Range(0, 5).Select(_ => new ClientContainer()).ToList(); + public List<ClientContainer> Users { get; } = Enumerable.Range(0, 150000).Select(_ => new ClientContainer()).ToList(); + public List<ClientContainer> AllUsers => [.. Users, .. Monitors, .. Admins]; + + public ClientContainer GetRandomUser() { + ClientContainer user; + do { + user = Users[new Random().Next(Users.Count)]; + } while (user.Client == null); + + return user; + } + + public ClientContainer GetRandomMonitor() { + ClientContainer user; + do { + user = Monitors[new Random().Next(Monitors.Count)]; + } while (user.Client == null); + + return user; + } + + public ClientContainer GetRandomAdmin() { + ClientContainer user; + do { + user = Admins[new Random().Next(Admins.Count)]; + } while (user.Client == null); + + return user; + } + + public ClientContainer GetRandomUserOfAnyType() { + ClientContainer user; + do { + user = AllUsers[new Random().Next(AllUsers.Count)]; + } while (user.Client == null); + + return user; + } + + public async Task StartAsync(CancellationToken cancellationToken) { + Admins.ForEach(x => x.Auth.UserType = "admin"); + Monitors.ForEach(x => x.Auth.UserType = "monitor"); + var ss = new SemaphoreSlim(256, 256); + var tasks = ((ClientContainer[]) [..Users, ..Monitors, ..Admins]).Select(async container => { + await ss.WaitAsync(); + await authService.Register(container.Auth); + // container.Client = new SafeNSoundClient(config, (await authService.Login(container.Auth)).AccessToken); + // container.WhoAmI = await container.Client.WhoAmI(); + ss.Release(); + }).ToList(); + await Task.WhenAll(tasks); + + var users = Users.ToArray(); + tasks = Monitors.Select(async container => { + var items = Random.Shared.GetItems(users, Users.Count / Monitors.Count).DistinctBy(x=>x.WhoAmI!.UserId); + foreach (var user in items) { + await container.Client!.AddAssignedUser(user.WhoAmI!.UserId); + } + }).ToList(); + await Task.WhenAll(tasks); + } + + public async Task StopAsync(CancellationToken cancellationToken) { + await Task.WhenAll(Users.Select(Cleanup).ToList()); + await Task.WhenAll(Monitors.Select(Cleanup).ToList()); + await Task.WhenAll(Admins.Select(Cleanup).ToList()); + } + + private async Task Cleanup(ClientContainer container) { + if (container.Client == null) return; + try { + await container.Client.DeleteAccount(container.Auth); + } + catch { + Console.WriteLine("Failed to delete account for user: " + container.Auth.Username); + } + } + + public class ClientContainer { + public RegisterDto Auth { get; set; } = new() { + Email = $"{Guid.NewGuid()}@example.com", + Username = $"user-{Guid.NewGuid()}", + Password = Guid.NewGuid().ToString(), + UserType = "user" + }; + + public SafeNSoundClient? Client { get; set; } + public WhoAmI? WhoAmI { get; set; } + } +} \ No newline at end of file diff --git a/testFrontend/SafeNSound.FakeUser/appsettings.json b/testFrontend/SafeNSound.FakeUser/appsettings.json new file mode 100644
index 0000000..f77ef07 --- /dev/null +++ b/testFrontend/SafeNSound.FakeUser/appsettings.json
@@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "System": "Information", + "Microsoft": "Information", + "ArcaneLibs.Blazor.Components.AuthorizedImage": "Information" + } + }, + "SafeNSound": { + "BaseUrl": "http://localhost:3000" + } +}