Files
WorkspaceAccessHost/tests/WorkspaceAccessServer.Tests/ActiveClientDevicesTests.cs
T
Nitload 0ea679932e
Verify / verify (ubuntu-latest, linux-bionic-arm64) (push) Canceled after 0s
Verify / verify (ubuntu-latest, linux-x64) (push) Canceled after 0s
Verify / verify (windows-latest, win-x64) (push) Canceled after 0s
Verify / postgres (push) Canceled after 0s
Build Charac server and client with OIDC, SSH sessions, and packages
2026-10-05 14:02:50 +08:00

82 lines
3.5 KiB
C#

using System.Security.Cryptography;
using Charac.Server.Authentication;
using Charac.Server.Connections;
using Charac.Client;
namespace Charac.Server.Tests;
public sealed class ActiveClientDevicesTests
{
private static readonly ExternalIdentity Alice = new("https://auth.example/", "alice");
private static readonly ExternalIdentity Bob = new("https://auth.example/", "bob");
[Fact]
public void SameInstallationCanHoldSeveralConnectionsWhileAnotherIsRejected()
{
var devices = new ActiveClientDevices();
var first = Credential();
var second = Credential();
Assert.Equal(ClientDeviceStatus.Invalid, devices.Check(Alice, "spoofed"));
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Alice, first, out var one));
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Alice, first, out var two));
Assert.Equal(ClientDeviceStatus.Occupied, devices.Check(Alice, second));
Assert.Equal(ClientDeviceStatus.Occupied, devices.Acquire(Alice, second, out var rejected));
Assert.Null(rejected);
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Bob, second, out var bob));
one!.Dispose();
Assert.Equal(ClientDeviceStatus.Occupied, devices.Check(Alice, second));
two!.Dispose();
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Alice, second, out var replacement));
replacement!.Dispose();
bob!.Dispose();
}
[Fact]
public void OperatorDisconnectReleasesDeviceAndStaleLeaseCannotReleaseReplacement()
{
var devices = new ActiveClientDevices();
var first = Credential();
var second = Credential();
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Alice, first, out var old));
using (devices.BeginDisconnect(Alice))
{
Assert.Equal(ClientDeviceStatus.Occupied, devices.Check(Alice, second));
Assert.False(devices.TryUse(old!, () => new object(), out _));
}
Assert.Equal(ClientDeviceStatus.Allowed, devices.Acquire(Alice, second, out var current));
old!.Dispose();
Assert.Equal(ClientDeviceStatus.Occupied, devices.Check(Alice, first));
current!.Dispose();
}
[Fact]
public async Task InstallationCredentialPersistsAndIsPrivate()
{
var directory = Path.Combine(Path.GetTempPath(), "rac-device-" + Guid.NewGuid().ToString("N"));
try
{
var concurrent = await Task.WhenAll(Enumerable.Range(0, 8)
.Select(_ => Task.Run(() => ClientDeviceCredential.LoadOrCreate(directory))));
var first = concurrent[0];
Assert.Equal(43, first.Length);
Assert.Equal(first, ClientDeviceCredential.LoadOrCreate(directory));
Assert.All(concurrent, value => Assert.Equal(first, value));
if (!OperatingSystem.IsWindows())
{
var mode = File.GetUnixFileMode(Path.Combine(directory, "device-key"));
Assert.Equal(UnixFileMode.UserRead | UnixFileMode.UserWrite, mode &
(UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.GroupRead |
UnixFileMode.GroupWrite | UnixFileMode.OtherRead | UnixFileMode.OtherWrite));
}
}
finally
{
if (Directory.Exists(directory))
Directory.Delete(directory, recursive: true);
}
}
private static string Credential() => Convert.ToBase64String(RandomNumberGenerator.GetBytes(32))
.TrimEnd('=').Replace('+', '-').Replace('/', '_');
}