test: strengthen audit coverage and enable CI integration checks
Some checks failed
Build and Test / test (push) Has been cancelled
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
Build and Test / build (win-arm64) (push) Has been cancelled
Build and Test / build (win-x64) (push) Has been cancelled
Build and Test / build-msix (ARM64, win-arm64) (push) Has been cancelled
Build and Test / build-msix (x64, win-x64) (push) Has been cancelled
Build and Test / build-extension (arm64) (push) Has been cancelled
Build and Test / build-extension (x64) (push) Has been cancelled
Build and Test / release (push) Has been cancelled

Tighten weak assertions identified during the three-model test-suite audit and enable the Shared integration test lane in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Scott Hanselman 2026-04-19 22:55:35 -07:00
parent 0852ffee2e
commit 9134be49e1
4 changed files with 48 additions and 15 deletions

View File

@ -51,6 +51,8 @@ jobs:
dotnet build tests/OpenClaw.Tray.Tests -c Debug
- name: Run Shared Tests
env:
OPENCLAW_RUN_INTEGRATION: 1
run: >
dotnet test tests/OpenClaw.Shared.Tests
--no-build

View File

@ -248,6 +248,16 @@ public class SystemRunTests
var res = await cap.ExecuteAsync(req);
Assert.True(res.Ok, res.Error);
var json = JsonSerializer.Serialize(res.Payload);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
Assert.Equal("git status --short", root.GetProperty("cmdText").GetString());
var plan = root.GetProperty("plan");
var argv = plan.GetProperty("argv");
Assert.Equal("git", argv[0].GetString());
Assert.Equal("status", argv[1].GetString());
Assert.Equal("--short", argv[2].GetString());
}
[Fact]
@ -263,6 +273,14 @@ public class SystemRunTests
var res = await cap.ExecuteAsync(req);
Assert.True(res.Ok, res.Error);
var json = JsonSerializer.Serialize(res.Payload);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
Assert.Equal("\"echo hello\"", root.GetProperty("cmdText").GetString());
var argv = root.GetProperty("plan").GetProperty("argv");
Assert.Single(argv.EnumerateArray());
Assert.Equal("echo hello", argv[0].GetString());
}
[Fact]

View File

@ -75,12 +75,11 @@ public class WebSocketClientBaseTests
[InlineData("https://gateway.example.com", "wss://gateway.example.com")]
[InlineData("ws://localhost:18789", "ws://localhost:18789")]
[InlineData("wss://gateway.example.com", "wss://gateway.example.com")]
public void Constructor_NormalizesUrl(string input, string _)
public void Constructor_NormalizesUrl(string input, string expected)
{
var client = new TestWebSocketClient(input, "test-token", _logger);
// GatewayUrlForDisplay is the sanitized version — just verify it's set
Assert.NotNull(client.TestGatewayUrlForDisplay);
Assert.DoesNotContain("@", client.TestGatewayUrlForDisplay); // credentials stripped
Assert.Equal(expected, client.TestGatewayUrlForDisplay);
Assert.DoesNotContain("@", client.TestGatewayUrlForDisplay);
client.Dispose();
}
@ -132,6 +131,7 @@ public class WebSocketClientBaseTests
public void Constructor_WithCredentialUrl_StripsFromDisplay()
{
var client = new TestWebSocketClient("ws://user:pass@localhost:18789", "token", _logger);
Assert.Equal("ws://localhost:18789", client.TestGatewayUrlForDisplay);
Assert.DoesNotContain("pass", client.TestGatewayUrlForDisplay);
client.Dispose();
}
@ -245,7 +245,9 @@ public class WebSocketClientBaseTests
client.StatusChanged += (_, s) => statuses.Add(s);
await client.ConnectAsync();
await Task.Delay(150);
await WaitForConditionAsync(
() => statuses.Count(s => s == ConnectionStatus.Connecting) >= 2,
TimeSpan.FromSeconds(2));
Assert.Contains(ConnectionStatus.Error, statuses);
Assert.True(statuses.Count(s => s == ConnectionStatus.Connecting) >= 2);
@ -265,7 +267,7 @@ public class WebSocketClientBaseTests
client.StatusChanged += (_, s) => statuses.Add(s);
await client.ConnectAsync();
await Task.Delay(150);
await Task.Delay(250);
Assert.Contains(ConnectionStatus.Error, statuses);
Assert.Single(statuses, s => s == ConnectionStatus.Connecting);
@ -273,6 +275,18 @@ public class WebSocketClientBaseTests
client.Dispose();
}
private static async Task WaitForConditionAsync(Func<bool> predicate, TimeSpan timeout)
{
var start = DateTime.UtcNow;
while (!predicate())
{
if (DateTime.UtcNow - start > timeout)
throw new TimeoutException("Condition was not met before the timeout.");
await Task.Delay(25);
}
}
}
public class TestLogger : IOpenClawLogger

View File

@ -48,16 +48,15 @@ public class MenuDisplayHelperTests
}
[Theory]
[InlineData("OK")]
[InlineData("Connected")]
[InlineData("RUNNING")]
[InlineData("Error")]
[InlineData("Connecting")]
[InlineData("RECONNECTING")]
public void GetChannelStatusIcon_CaseInsensitive(string status)
[InlineData("OK", "🟢")]
[InlineData("Connected", "🟢")]
[InlineData("RUNNING", "🟢")]
[InlineData("Error", "🔴")]
[InlineData("Connecting", "🟡")]
[InlineData("RECONNECTING", "🟡")]
public void GetChannelStatusIcon_CaseInsensitive(string status, string expected)
{
// Should not return the neutral fallback
Assert.NotEqual("⚪", MenuDisplayHelper.GetChannelStatusIcon(status));
Assert.Equal(expected, MenuDisplayHelper.GetChannelStatusIcon(status));
}
[Theory]