diff --git a/testFrontend/SafeNSound.FakeUser/MonitorService.cs b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
index 57d90a5..fa2022a 100644
--- a/testFrontend/SafeNSound.FakeUser/MonitorService.cs
+++ b/testFrontend/SafeNSound.FakeUser/MonitorService.cs
@@ -1,14 +1,21 @@
+using System.Net;
using ArcaneLibs.Extensions;
namespace SafeNSound.FakeUser;
-public class MonitorService(ILogger<MonitorService> logger, UserStore userStore): IHostedService {
- private Task? _getAllAlarmsTask, _assignBudgetTask;
+public class MonitorService(ILogger<MonitorService> logger, UserStore userStore) : IHostedService {
+ private Task? _getAllAlarmsTask,
+ _assignBudgetTask,
+ _getAlarmForRandomUserTask,
+ _rotateMonitoredUsersTask;
+
private readonly CancellationTokenSource _cts = new();
-
+
public async Task StartAsync(CancellationToken cancellationToken) {
_getAllAlarmsTask = GetAllAlarms(_cts.Token);
_assignBudgetTask = AssignBudget(_cts.Token);
+ _getAlarmForRandomUserTask = GetAlarmForRandomUser(_cts.Token);
+ _rotateMonitoredUsersTask = RotateMonitoredUsers(_cts.Token);
}
private async Task GetAllAlarms(CancellationToken cancellationToken) {
@@ -16,37 +23,88 @@ public class MonitorService(ILogger<MonitorService> logger, UserStore userStore)
try {
var user = userStore.GetRandomMonitor();
var alarms = await user.Client!.GetAllAlarms();
- if(alarms.Count > 0)
+ 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 user.Client!.GetAlarm(alarms.Keys.First());
+ await user.Client!.DeleteAlarm(alarms.Keys.First());
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
+ }
+ catch (Exception ex) {
+ logger.LogError(ex, "Error querying alarm list");
+ }
+ }
+ }
+
+ private async Task GetAlarmForRandomUser(CancellationToken cancellationToken) {
+ while (!cancellationToken.IsCancellationRequested) {
+ try {
+ var user = userStore.GetRandomMonitor();
+ var watchedUserIds = await user.Client!.GetAssignedUsers();
+ if (watchedUserIds.Count == 0) {
+ logger.LogInformation("Monitor {UserId} has no assigned users", user.Auth.Username);
+ continue;
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
+ }
+ catch (Exception ex) {
+ logger.LogError(ex, "Error querying alarm for user");
+ }
+ }
+ }
+
+ private async Task RotateMonitoredUsers(CancellationToken cancellationToken) {
+ while (!cancellationToken.IsCancellationRequested) {
+ try {
+ var user = userStore.GetRandomMonitor();
+ var watchedUserIds = (await user.Client!.GetAssignedUsers()).ToArray();
+ if (watchedUserIds.Length == 0) {
+ logger.LogInformation("Monitor {UserId} has no assigned users", user.Auth.Username);
+ }
+ else {
+ var idToRemove = Random.Shared.GetItems(watchedUserIds, 1).First();
+ await user.Client!.RemoveAssignedUser(idToRemove);
+ }
+
+ string idToAdd;
+ do {
+ idToAdd = userStore.GetRandomUserOfAnyType().WhoAmI!.UserId;
+ } while (watchedUserIds.Contains(idToAdd));
+
+ await user.Client!.AddAssignedUser(idToAdd);
+
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
- } catch (Exception ex) {
- logger.LogError(ex, "Error querying alarm");
+ }
+ catch (Exception ex) {
+ logger.LogError(ex, "Error rotating monitored users");
}
}
}
-
+
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));
+ // 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");
+ // 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 assigning budget");
}
-
}
}
public async Task StopAsync(CancellationToken cancellationToken) {
await _cts.CancelAsync();
await _getAllAlarmsTask!;
+ await _assignBudgetTask!;
+ await _getAlarmForRandomUserTask!;
+ await _rotateMonitoredUsersTask!;
}
}
\ No newline at end of file
diff --git a/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs b/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs
index 7835f89..a2e133f 100644
--- a/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs
+++ b/testFrontend/SafeNSound.FakeUser/RandomAlarmService.cs
@@ -1,20 +1,23 @@
namespace SafeNSound.FakeUser;
-public class RandomAlarmService(UserStore userStore): IHostedService {
+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 static readonly string[] validReasons = ["fall", "toilet"];
+
private async Task Run(CancellationToken cancellationToken) {
while (!cancellationToken.IsCancellationRequested) {
try {
var user = userStore.GetRandomUser();
- if (Random.Shared.Next(100) > 90) {
+ var currentAlarm = await user.Client!.GetAlarm();
+ if (currentAlarm is null) {
await user.Client!.SetAlarm(new Sdk.AlarmDto {
- Reason = "fall"
+ Reason = Random.Shared.GetItems(validReasons, 1).First()
});
}
else {
@@ -25,7 +28,7 @@ public class RandomAlarmService(UserStore userStore): IHostedService {
Console.WriteLine($"Error setting/deleting alarm: {ex.Message}");
}
- await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
+ await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken);
}
}
diff --git a/testFrontend/SafeNSound.FakeUser/UserStore.cs b/testFrontend/SafeNSound.FakeUser/UserStore.cs
index 9b04efb..f643a68 100644
--- a/testFrontend/SafeNSound.FakeUser/UserStore.cs
+++ b/testFrontend/SafeNSound.FakeUser/UserStore.cs
@@ -5,7 +5,7 @@ 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> Users { get; } = Enumerable.Range(0, 15).Select(_ => new ClientContainer()).ToList();
public List<ClientContainer> AllUsers => [.. Users, .. Monitors, .. Admins];
public ClientContainer GetRandomUser() {
@@ -51,8 +51,16 @@ public class UserStore(SafeNSoundAuthentication authService, SafeNSoundConfigura
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();
+ container.Client = new SafeNSoundClient(config, (await authService.Login(container.Auth)).AccessToken);
+ container.WhoAmI = await container.Client.WhoAmI();
+ await container.Client.UpdateDevice(container.WhoAmI.DeviceId, new() {
+ Name = "FakeUser-" + container.Auth.Username,
+ });
+
+ if (container.Auth.UserType == "admin") {
+ await container.Client.MonitorAllUsers();
+ }
+
ss.Release();
}).ToList();
await Task.WhenAll(tasks);
@@ -76,6 +84,10 @@ public class UserStore(SafeNSoundAuthentication authService, SafeNSoundConfigura
private async Task Cleanup(ClientContainer container) {
if (container.Client == null) return;
try {
+ _ = await container.Client.GetDevices();
+ if(Random.Shared.Next(100)>50)
+ await container.Client.DeleteDevice(container.WhoAmI!.DeviceId);
+ else await container.Client.LogOut();
await container.Client.DeleteAccount(container.Auth);
}
catch {
diff --git a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs
index 9ea8073..8b06c30 100644
--- a/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs
+++ b/testFrontend/SafeNSound.Sdk/SafeNSoundClient.cs
@@ -20,19 +20,29 @@ public class SafeNSoundClient(SafeNSoundConfiguration config, string accessToken
#region Alarm
- public async Task<AlarmDto> GetAlarm(string userId = "@me") {
- var res = await HttpClient.GetAsync($"/alarm/{userId}");
+ public async Task SetAlarm(AlarmDto alarm) {
+ var res = await HttpClient.PutAsJsonAsync("/alarm/@me", alarm);
res.EnsureSuccessStatusCode();
- return (await res.Content.ReadFromJsonAsync<AlarmDto>())!;
}
- public async Task SetAlarm(AlarmDto alarm, string userId = "@me") {
- var res = await HttpClient.PutAsJsonAsync("/alarm/@me", alarm);
+ public async Task<AlarmDto?> GetAlarm(string userId = "@me") {
+ var res = await HttpClient.GetAsync(
+ // required due to express routing not being closest-match
+ userId == "@me"
+ ? $"/alarm/@me"
+ : $"/user/{userId}/alarm"
+ );
res.EnsureSuccessStatusCode();
+ return (await res.Content.ReadFromJsonAsync<AlarmDto?>());
}
public async Task DeleteAlarm(string userId = "@me") {
- var res = await HttpClient.DeleteAsync($"/alarm/{userId}");
+ var res = await HttpClient.DeleteAsync(
+ // required due to express routing not being closest-match
+ userId == "@me"
+ ? $"/alarm/@me"
+ : $"/user/{userId}/alarm"
+ );
res.EnsureSuccessStatusCode();
}
@@ -103,6 +113,11 @@ public class SafeNSoundClient(SafeNSoundConfiguration config, string accessToken
var res = await HttpClient.PatchAsJsonAsync($"/auth/devices/{deviceId}", device);
res.EnsureSuccessStatusCode();
}
+
+ public async Task LogOut() {
+ var res = await HttpClient.PostAsync("/auth/logout", null);
+ res.EnsureSuccessStatusCode();
+ }
}
public class AlarmDto {
diff --git a/testFrontend/SafeNSound.sln.DotSettings.user b/testFrontend/SafeNSound.sln.DotSettings.user
index ae9fb74..43e3164 100644
--- a/testFrontend/SafeNSound.sln.DotSettings.user
+++ b/testFrontend/SafeNSound.sln.DotSettings.user
@@ -1,4 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpResponseMessage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc04aec05cdf74c1a9565aec2103f20961a1e00_003F43_003Ff3c3d460_003FHttpResponseMessage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+ <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARandom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fba81a6af46624b56ac6210bdbcc99af2d19e00_003F48_003Fde29dea3_003FRandom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATaskAwaiter_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fba81a6af46624b56ac6210bdbcc99af2d19e00_003F4b_003Fb9d0e80e_003FTaskAwaiter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:Boolean x:Key="/Default/Monitoring/Counters/=System_002ERuntime/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Monitoring/Counters/=Microsoft_002EAspNetCore_002EHttp_002EConnections/@EntryIndexedValue">True</s:Boolean>
|