83e072bc27
- Bao darf jetzt Status ändern (neben Iris), Sub-Agents weiterhin nicht - CanEditContent für Inhaltsbearbeitung durch alle bekannten Caller - Bao-Content-Änderungen triggern task_content_changed-Notification an Iris - Bao-Status-Änderungen triggern task_status_changed-Notification an Iris - Iris-Status-Änderungen triggern task_status_changed-Notification an Bao - Neue WorkTask-Felder: IsAgentTask (bool), ExpectedFrom (string) - Agent-Workflow-API: CreateAgentTask, WaitingTasks, AgentOverview - Frontend: Agent-Task-Badge, Iris-Overview-Panel, isBao-Getter - Login-Rate-Limiter mit strukturiertem JSON-Fehlermeldungs-Body - Volume-Name: nexus-postgres → postgres-data (Standardisierung)
254 lines
8.3 KiB
C#
254 lines
8.3 KiB
C#
using Nexus.Api.Data;
|
|
using Xunit;
|
|
|
|
namespace Nexus.Api.Tests;
|
|
|
|
public class TaskBoardTests
|
|
{
|
|
// ── TaskStateHelper: BoardGroupKey ──
|
|
|
|
[Theory]
|
|
[InlineData("Backlog", "offen")]
|
|
[InlineData("In progress", "inProgress")]
|
|
[InlineData("Delegated", "delegated")]
|
|
[InlineData("Review", "review")]
|
|
[InlineData("Blocked", "blocked")]
|
|
[InlineData("Done", "done")]
|
|
[InlineData("backlog", "offen")]
|
|
[InlineData("in progress", "inProgress")]
|
|
[InlineData("delegated", "delegated")]
|
|
[InlineData("review", "review")]
|
|
[InlineData("blocked", "blocked")]
|
|
[InlineData("done", "done")]
|
|
[InlineData("", "offen")]
|
|
[InlineData(null, "offen")]
|
|
[InlineData("unknown", "offen")]
|
|
public void BoardGroupKey_ReturnsExpectedGroup(string? state, string expected)
|
|
{
|
|
var result = TaskStateHelper.BoardGroupKey(state);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
// ── TaskStateHelper: BoardGroupToState ──
|
|
|
|
[Theory]
|
|
[InlineData("offen", "Backlog")]
|
|
[InlineData("inProgress", "In progress")]
|
|
[InlineData("inprogress", "In progress")]
|
|
[InlineData("delegated", "Delegated")]
|
|
[InlineData("review", "Review")]
|
|
[InlineData("blocked", "Blocked")]
|
|
[InlineData("done", "Done")]
|
|
[InlineData("Offen", "Backlog")]
|
|
[InlineData("", null)]
|
|
[InlineData(null, null)]
|
|
[InlineData("unknown", null)]
|
|
public void BoardGroupToState_ReturnsExpectedState(string? groupKey, string? expected)
|
|
{
|
|
var result = TaskStateHelper.BoardGroupToState(groupKey);
|
|
Assert.Equal(expected, result);
|
|
}
|
|
|
|
// ── TaskStateHelper: AllStates has 6 entries ──
|
|
|
|
[Fact]
|
|
public void AllStates_ContainsAllSixStates()
|
|
{
|
|
var states = TaskStateHelper.AllStates;
|
|
Assert.Equal(6, states.Length);
|
|
Assert.Contains("Backlog", states);
|
|
Assert.Contains("In progress", states);
|
|
Assert.Contains("Delegated", states);
|
|
Assert.Contains("Review", states);
|
|
Assert.Contains("Blocked", states);
|
|
Assert.Contains("Done", states);
|
|
}
|
|
|
|
// ── TaskStateHelper: IsValidState ──
|
|
|
|
[Theory]
|
|
[InlineData("Backlog", true)]
|
|
[InlineData("In progress", true)]
|
|
[InlineData("Delegated", true)]
|
|
[InlineData("Review", true)]
|
|
[InlineData("Blocked", true)]
|
|
[InlineData("Done", true)]
|
|
[InlineData("backlog", true)]
|
|
[InlineData("offen", false)]
|
|
[InlineData("", false)]
|
|
[InlineData(null, false)]
|
|
[InlineData("unknown", false)]
|
|
public void IsValidState_ReturnsCorrectResult(string? state, bool expected)
|
|
{
|
|
Assert.Equal(expected, TaskStateHelper.IsValidState(state));
|
|
}
|
|
|
|
// ── TaskStateHelper: IsInProgressOrBlocked ──
|
|
|
|
[Theory]
|
|
[InlineData("In progress", true)]
|
|
[InlineData("Blocked", true)]
|
|
[InlineData("Backlog", false)]
|
|
[InlineData("Delegated", false)]
|
|
[InlineData("Review", false)]
|
|
[InlineData("Done", false)]
|
|
[InlineData(null, false)]
|
|
public void IsInProgressOrBlocked_ReturnsCorrectResult(string? state, bool expected)
|
|
{
|
|
Assert.Equal(expected, TaskStateHelper.IsInProgressOrBlocked(state));
|
|
}
|
|
|
|
// ── TaskStateHelper: IsDoneOrBacklog ──
|
|
|
|
[Theory]
|
|
[InlineData("Done", true)]
|
|
[InlineData("Backlog", true)]
|
|
[InlineData("In progress", false)]
|
|
[InlineData("Delegated", false)]
|
|
[InlineData("Review", false)]
|
|
[InlineData("Blocked", false)]
|
|
[InlineData(null, false)]
|
|
public void IsDoneOrBacklog_ReturnsCorrectResult(string? state, bool expected)
|
|
{
|
|
Assert.Equal(expected, TaskStateHelper.IsDoneOrBacklog(state));
|
|
}
|
|
|
|
// ── TaskStateHelper: ToDisplayString ──
|
|
|
|
[Theory]
|
|
[InlineData("Backlog", "Offen")]
|
|
[InlineData("In progress", "In Bearbeitung")]
|
|
[InlineData("Delegated", "Delegiert")]
|
|
[InlineData("Review", "Review")]
|
|
[InlineData("Blocked", "Blockiert")]
|
|
[InlineData("Done", "Erledigt")]
|
|
[InlineData("backlog", "Offen")]
|
|
[InlineData("", "")]
|
|
[InlineData(null, "")]
|
|
[InlineData("unknown", "unknown")]
|
|
public void ToDisplayString_ReturnsGermanLabel(string? state, string expected)
|
|
{
|
|
Assert.Equal(expected, TaskStateHelper.ToDisplayString(state));
|
|
}
|
|
|
|
// ── TaskState helper: ToStateString and ToTaskState roundtrip ──
|
|
|
|
[Fact]
|
|
public void ToStateString_And_ToTaskState_RoundTrip()
|
|
{
|
|
var states = new[] { TaskState.Backlog, TaskState.InProgress, TaskState.Delegated, TaskState.Review, TaskState.Blocked, TaskState.Done };
|
|
foreach (var state in states)
|
|
{
|
|
var str = state.ToStateString();
|
|
var parsed = str.ToTaskState();
|
|
Assert.Equal(state, parsed);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ToTaskState_DefaultsToBacklog_ForUnknownString()
|
|
{
|
|
Assert.Equal(TaskState.Backlog, "unknown".ToTaskState());
|
|
}
|
|
|
|
// ── TaskStateHelper: CanChangeState (Iris + Bao policy) ──
|
|
|
|
[Fact]
|
|
public void CanChangeState_Iris_CanChangeAnyTask()
|
|
{
|
|
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
|
|
var normalTask = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
|
|
|
|
Assert.True(TaskStateHelper.CanChangeState("iris", agentTask));
|
|
Assert.True(TaskStateHelper.CanChangeState("iris", normalTask));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanChangeState_Bao_CanChangeAnyTask()
|
|
{
|
|
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
|
|
var normalTask = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
|
|
|
|
Assert.True(TaskStateHelper.CanChangeState("bao", agentTask));
|
|
Assert.True(TaskStateHelper.CanChangeState("bao", normalTask));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanChangeState_SubAgents_NeverAllowed()
|
|
{
|
|
var task = new WorkTask { Title = "test", IsAgentTask = false, Source = "bao" };
|
|
|
|
Assert.False(TaskStateHelper.CanChangeState("programmer", task));
|
|
Assert.False(TaskStateHelper.CanChangeState("reviewer", task));
|
|
Assert.False(TaskStateHelper.CanChangeState("architekt", task));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanChangeState_SubAgents_NeverAllowed_EvenForAgentTasks()
|
|
{
|
|
var agentTask = new WorkTask { Title = "test", IsAgentTask = true, Source = "iris" };
|
|
|
|
Assert.False(TaskStateHelper.CanChangeState("programmer", agentTask));
|
|
Assert.False(TaskStateHelper.CanChangeState("reviewer", agentTask));
|
|
Assert.False(TaskStateHelper.CanChangeState("architekt", agentTask));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanChangeState_NexusSystem_IsAllowed()
|
|
{
|
|
var task = new WorkTask { Title = "test", IsAgentTask = false };
|
|
Assert.True(TaskStateHelper.CanChangeState("nexus-system", task));
|
|
|
|
var agentTask = new WorkTask { Title = "test", IsAgentTask = true };
|
|
Assert.True(TaskStateHelper.CanChangeState("nexus-system", agentTask));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanChangeState_UnknownCaller_Rejected()
|
|
{
|
|
var task = new WorkTask { Title = "test", IsAgentTask = false };
|
|
var agentTask = new WorkTask { Title = "test", IsAgentTask = true };
|
|
|
|
Assert.False(TaskStateHelper.CanChangeState("", task));
|
|
Assert.False(TaskStateHelper.CanChangeState("", agentTask));
|
|
Assert.False(TaskStateHelper.CanChangeState("unknown", task));
|
|
Assert.False(TaskStateHelper.CanChangeState(null, task));
|
|
}
|
|
|
|
// ── TaskStateHelper: CanEditContent ──
|
|
|
|
[Fact]
|
|
public void CanEditContent_Iris_IsAllowed()
|
|
{
|
|
Assert.True(TaskStateHelper.CanEditContent("iris"));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanEditContent_Bao_IsAllowed()
|
|
{
|
|
Assert.True(TaskStateHelper.CanEditContent("bao"));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanEditContent_SubAgents_AreAllowed()
|
|
{
|
|
Assert.True(TaskStateHelper.CanEditContent("programmer"));
|
|
Assert.True(TaskStateHelper.CanEditContent("reviewer"));
|
|
Assert.True(TaskStateHelper.CanEditContent("architekt"));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanEditContent_NexusSystem_IsAllowed()
|
|
{
|
|
Assert.True(TaskStateHelper.CanEditContent("nexus-system"));
|
|
}
|
|
|
|
[Fact]
|
|
public void CanEditContent_UnknownCaller_Rejected()
|
|
{
|
|
Assert.False(TaskStateHelper.CanEditContent(""));
|
|
Assert.False(TaskStateHelper.CanEditContent(null));
|
|
Assert.False(TaskStateHelper.CanEditContent(" "));
|
|
}
|
|
}
|