133 lines
4.0 KiB
C#
133 lines
4.0 KiB
C#
using Nexus.Api.Data;
|
|
using Nexus.Api.Models;
|
|
using Nexus.Api.Services;
|
|
using Xunit;
|
|
|
|
namespace Nexus.Api.Tests;
|
|
|
|
public sealed class AgentServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task GetAgentsAsync_ProjectsOnlyLiveOpenClawInventory()
|
|
{
|
|
var service = new AgentService(new StubOpenClawControlService());
|
|
|
|
var agents = await service.GetAgentsAsync(CancellationToken.None);
|
|
|
|
Assert.Equal(6, agents.Count);
|
|
Assert.Contains(agents, agent =>
|
|
agent.Id == "product-owner" &&
|
|
agent.Workspace == "/workspace-po" &&
|
|
agent.Role == "Product Owner");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAgentAsync_Iris_ReturnsOrchestrator()
|
|
{
|
|
var service = new AgentService(new StubOpenClawControlService());
|
|
|
|
var agent = await service.GetAgentAsync("iris", CancellationToken.None);
|
|
|
|
Assert.NotNull(agent);
|
|
Assert.Equal("Orchestrator", agent.Role);
|
|
Assert.Equal("/workspace/iris", agent.Workspace);
|
|
Assert.Null(agent.AgentDir);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAgentAsync_Unknown_ReturnsNull()
|
|
{
|
|
var service = new AgentService(new StubOpenClawControlService());
|
|
|
|
var agent = await service.GetAgentAsync("nonexistent", CancellationToken.None);
|
|
|
|
Assert.Null(agent);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAllowedAgentIdsAsync_UsesLiveIds()
|
|
{
|
|
var control = new StubOpenClawControlService(
|
|
agents:
|
|
[
|
|
Agent("custom-live", "Custom"),
|
|
Agent("product-owner", "Product Owner")
|
|
]);
|
|
var service = new AgentService(control);
|
|
|
|
var ids = await service.GetAllowedAgentIdsAsync(CancellationToken.None);
|
|
|
|
Assert.Equal(2, ids.Count);
|
|
Assert.Contains("custom-live", ids);
|
|
Assert.Contains("product-owner", ids);
|
|
Assert.DoesNotContain("iris", ids);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAgentAsync_LatestSessionModelOverridesInventoryModel()
|
|
{
|
|
var older = DateTimeOffset.UtcNow.AddMinutes(-10);
|
|
var newer = DateTimeOffset.UtcNow;
|
|
var control = new StubOpenClawControlService(
|
|
agents: [Agent("programmer-fast", "Programmer Fast", "openai/default")],
|
|
sessions:
|
|
[
|
|
Session("old", "programmer-fast", "openai/gpt-5.3", older),
|
|
Session("new", "programmer-fast", "openai/gpt-5.5", newer)
|
|
]);
|
|
var service = new AgentService(control);
|
|
|
|
var agent = await service.GetAgentAsync("programmer-fast", CancellationToken.None);
|
|
|
|
Assert.NotNull(agent);
|
|
Assert.Equal("Developer", agent.Role);
|
|
Assert.Equal("openai/gpt-5.5", agent.Model);
|
|
Assert.Equal(newer, agent.LastSeen);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAgentsAsync_DisconnectedGatewayMarksAgentsOffline()
|
|
{
|
|
var service = new AgentService(new StubOpenClawControlService(connected: false));
|
|
|
|
var agents = await service.GetAgentsAsync(CancellationToken.None);
|
|
|
|
Assert.All(agents, agent => Assert.Equal(OperationalStatus.Offline, agent.Status));
|
|
}
|
|
|
|
private static OpenClawAgentDto Agent(
|
|
string id,
|
|
string name,
|
|
string model = "openai/gpt-5.5")
|
|
=> new(
|
|
Id: id,
|
|
Name: name,
|
|
Description: null,
|
|
Model: model,
|
|
Provider: "openai",
|
|
Workspace: $"/live/{id}",
|
|
Status: "ready");
|
|
|
|
private static OpenClawSessionDto Session(
|
|
string key,
|
|
string agentId,
|
|
string model,
|
|
DateTimeOffset updatedAt)
|
|
=> new(
|
|
Key: key,
|
|
SessionId: key,
|
|
AgentId: agentId,
|
|
Title: key,
|
|
Status: "active",
|
|
Kind: "agent",
|
|
Channel: null,
|
|
Model: model,
|
|
Provider: "openai",
|
|
RunId: null,
|
|
UpdatedAt: updatedAt,
|
|
InputTokens: null,
|
|
OutputTokens: null,
|
|
TotalTokens: null,
|
|
CanAbort: true);
|
|
}
|