M5: Windows client moderation UI; add C ABI getters for account list, user mute/deafen, channel topic
This commit is contained in:
@@ -55,6 +55,22 @@ public sealed class VoiceCatClientSmokeTests : IDisposable
|
||||
}
|
||||
Assert.True(port is not null, "voicecat-server.exe did not report a bound TCP port within 10s.");
|
||||
_port = port!.Value;
|
||||
|
||||
// M5: provision a known admin account so we can exercise moderation wrappers end-to-end.
|
||||
string adminExe = Path.Combine(FindRepoRoot(), "build", "m1-dev", "bin", "voicecat-admin.exe");
|
||||
Assert.True(File.Exists(adminExe), "voicecat-admin.exe not found — build the m1-dev preset.");
|
||||
var adminPsi = new ProcessStartInfo(adminExe)
|
||||
{
|
||||
Arguments = $"--data-dir \"{_tempDir}\" account add admin2 --admin --password testpassword123",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
};
|
||||
using (var adminProc = Process.Start(adminPsi) ?? throw new InvalidOperationException("failed to start voicecat-admin.exe"))
|
||||
{
|
||||
Assert.True(adminProc.WaitForExit(10000), "voicecat-admin.exe did not exit within 10s.");
|
||||
Assert.Equal(0, adminProc.ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -124,6 +140,110 @@ public sealed class VoiceCatClientSmokeTests : IDisposable
|
||||
var channels = client.ListChannels();
|
||||
Assert.Contains(channels, c => c.Id == 1 && c.Name == "Lobby");
|
||||
|
||||
// M5: permissions getter round-trip.
|
||||
var perms = client.GetPermissions();
|
||||
Assert.False(perms.IsAdmin);
|
||||
Assert.False(perms.CanKick);
|
||||
|
||||
// M5: moderation request wrappers queue without error. As a guest, account listing
|
||||
// is rejected by the server with a GenericResult, which proves the wrapper path works
|
||||
// end-to-end and that the new event type is delivered through P/Invoke.
|
||||
Assert.Equal(VcResult.Ok, client.RequestAccountList());
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult), 3000),
|
||||
"did not receive VC_EVENT_GENERIC_RESULT for guest ListAccounts");
|
||||
var generic = events.First(e => e.Type == VcEventType.GenericResult);
|
||||
Assert.Equal(VcResult.PermissionDenied, generic.Result);
|
||||
|
||||
client.Disconnect();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Admin_ChannelCrud_AccountCrud_RoundTrips()
|
||||
{
|
||||
var events = new List<VoiceCatEvent>();
|
||||
using var client = new VoiceCatClient("vc-csharp-admin", "0.1", VcLogLevel.Off,
|
||||
tofuStorePath: Path.Combine(_tempDir, "tofu_pins_admin.txt"));
|
||||
client.EventReceived += events.Add;
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.Connect("127.0.0.1", _port));
|
||||
Assert.Equal(VcResult.Ok, client.AuthenticateUser("admin2", "testpassword123"));
|
||||
|
||||
Assert.True(PumpUntil(client, () => events.Any(e => e.Type == VcEventType.ServerIdentity), 5000));
|
||||
Assert.Equal(VcResult.Ok, client.ConfirmServerIdentity(accept: true));
|
||||
Assert.True(PumpUntil(client, () => events.Any(e => e.Type == VcEventType.AuthResult), 5000));
|
||||
Assert.Equal(VcResult.Ok, events.First(e => e.Type == VcEventType.AuthResult).Result);
|
||||
Assert.True(PumpUntil(client, () => events.Any(e => e.Type == VcEventType.ChannelList), 3000));
|
||||
|
||||
var perms = client.GetPermissions();
|
||||
Assert.True(perms.IsAdmin || perms.CanAdminAccounts);
|
||||
|
||||
// Channel CRUD
|
||||
Assert.Equal(VcResult.Ok, client.CreateChannel(new ChannelEditInfo(
|
||||
Id: 0,
|
||||
ParentId: 0,
|
||||
Name: "CSharp Test Channel",
|
||||
Topic: "Created by C# smoke test",
|
||||
PasswordProtected: false,
|
||||
Password: null,
|
||||
MaxUsers: 42,
|
||||
SortOrder: 0,
|
||||
Audio: new AudioConfigInfo(0, true, 48000, 64000, 20, 1, true, 5, false, 10))));
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"CreateChannel did not succeed");
|
||||
|
||||
var channels = client.ListChannels();
|
||||
var created = channels.FirstOrDefault(c => c.Name == "CSharp Test Channel");
|
||||
Assert.NotNull(created);
|
||||
Assert.Equal("Created by C# smoke test", created.Topic);
|
||||
Assert.True(created.PasswordProtected == false);
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.EditChannel(new ChannelEditInfo(
|
||||
created.Id,
|
||||
created.ParentId,
|
||||
created.Name,
|
||||
"Updated topic",
|
||||
created.PasswordProtected,
|
||||
null,
|
||||
100,
|
||||
0,
|
||||
new AudioConfigInfo(0, true, 48000, 64000, 20, 1, true, 5, false, 10))));
|
||||
events.Clear();
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"EditChannel did not succeed");
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.DeleteChannel(created.Id));
|
||||
events.Clear();
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"DeleteChannel did not succeed");
|
||||
|
||||
// Account CRUD
|
||||
Assert.Equal(VcResult.Ok, client.CreateAccount("csharp_smoke_user", "initialpw"));
|
||||
events.Clear();
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"CreateAccount did not succeed");
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.RequestAccountList());
|
||||
Assert.True(PumpUntil(client, () => events.Any(e => e.Type == VcEventType.AccountList), 3000));
|
||||
var accounts = client.ListAccounts();
|
||||
Assert.Contains(accounts, a => a.Username == "csharp_smoke_user");
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.ResetPassword("csharp_smoke_user", "newpw123"));
|
||||
events.Clear();
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"ResetPassword did not succeed");
|
||||
|
||||
Assert.Equal(VcResult.Ok, client.DeleteAccount("csharp_smoke_user"));
|
||||
events.Clear();
|
||||
Assert.True(PumpUntil(client,
|
||||
() => events.Any(e => e.Type == VcEventType.GenericResult && e.Result == VcResult.Ok), 3000),
|
||||
"DeleteAccount did not succeed");
|
||||
|
||||
client.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user