195 lines
8.5 KiB
C#
195 lines
8.5 KiB
C#
using System.Text.Json.Nodes;
|
|
using Nexus.Api.Models;
|
|
using Nexus.Api.Services;
|
|
|
|
namespace Nexus.Api.Tests;
|
|
|
|
/// <summary>
|
|
/// Minimal live-RPC test double for consumers that only need the OpenClaw
|
|
/// agent/session inventory. Unsupported control-plane calls fail loudly so a
|
|
/// test cannot accidentally fall back to a fabricated legacy source.
|
|
/// </summary>
|
|
internal sealed class StubOpenClawControlService : IOpenClawControlService
|
|
{
|
|
public StubOpenClawControlService(
|
|
IReadOnlyList<OpenClawAgentDto>? agents = null,
|
|
IReadOnlyList<OpenClawSessionDto>? sessions = null,
|
|
bool connected = true)
|
|
{
|
|
Agents = agents ??
|
|
[
|
|
Agent("iris", "Iris", "openai/gpt-5.5", "/workspace/iris"),
|
|
Agent("product-owner", "Product Owner", "openai/gpt-5.5", "/workspace-po"),
|
|
Agent("programmer", "Programmer", "openai/gpt-5.4", "/workspace/programmer"),
|
|
Agent("programmer-fast", "Programmer Fast", "openai/gpt-5.3-codex-spark", "/workspace/programmer-fast"),
|
|
Agent("reviewer", "Reviewer", "openai/gpt-5.5", "/workspace/reviewer"),
|
|
Agent("architekt", "Architekt", "openai/gpt-5.5", "/workspace/architekt")
|
|
];
|
|
Sessions = sessions ?? [];
|
|
Connected = connected;
|
|
}
|
|
|
|
public IReadOnlyList<OpenClawAgentDto> Agents { get; }
|
|
public IReadOnlyList<OpenClawSessionDto> Sessions { get; }
|
|
public bool Connected { get; }
|
|
|
|
public OpenClawConnectionDto GetConnection()
|
|
=> new(
|
|
State: Connected ? "connected" : "disconnected",
|
|
Configured: true,
|
|
CredentialConfigured: true,
|
|
Connected: Connected,
|
|
Endpoint: "ws://openclaw-gateway:18789",
|
|
GatewayVersion: "2026.7.1",
|
|
RequiredVersion: "2026.7.1",
|
|
VersionPinned: true,
|
|
VersionMatches: true,
|
|
ProtocolVersion: 4,
|
|
GrantedScopes: ["operator.read"],
|
|
AdvertisedEvents: [],
|
|
LastConnectedAt: Connected ? DateTimeOffset.UtcNow : null,
|
|
LastEventAt: Connected ? DateTimeOffset.UtcNow : null,
|
|
ReconnectAttempts: 0,
|
|
Message: null,
|
|
Recovery: null,
|
|
CheckedAt: DateTimeOffset.UtcNow);
|
|
|
|
public Task<OpenClawCollectionDto<OpenClawAgentDto>> GetAgentsAsync(
|
|
CancellationToken cancellationToken = default)
|
|
=> Task.FromResult(Collection(Agents));
|
|
|
|
public Task<OpenClawCollectionDto<OpenClawSessionDto>> GetSessionsAsync(
|
|
int limit = 100,
|
|
CancellationToken cancellationToken = default)
|
|
=> Task.FromResult(Collection<OpenClawSessionDto>(
|
|
Sessions.Take(limit).ToArray()));
|
|
|
|
public IReadOnlyList<OpenClawCapabilityDto> GetCapabilities() => [];
|
|
public Task<OpenClawOverviewDto> GetOverviewAsync(CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawOverviewDto>();
|
|
public Task<OpenClawCollectionDto<OpenClawTaskDto>> GetTasksAsync(
|
|
int limit = 100,
|
|
string? cursor = null,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawTaskDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawCronJobDto>> GetCronJobsAsync(
|
|
int limit = 100,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawCronJobDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawCronJobDto>> GetCronJobsAsync(
|
|
bool includeDisabled,
|
|
int limit = 100,
|
|
string? cursor = null,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawCronJobDto>>();
|
|
public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> GetCronJobAsync(
|
|
string jobId,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawCronRunDto>> GetCronRunsAsync(
|
|
string jobId,
|
|
int limit = 100,
|
|
string? cursor = null,
|
|
string? runId = null,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawCronRunDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawApprovalDto>> GetApprovalsAsync(
|
|
int limit = 100,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawApprovalDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawActivityDto>> GetActivityAsync(
|
|
int limit = 100,
|
|
string? cursor = null,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawActivityDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawModelDto>> GetModelsAsync(
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawModelDto>>();
|
|
public Task<OpenClawCollectionDto<OpenClawModelAuthProviderDto>> GetModelAuthStatusAsync(
|
|
bool refresh = false,
|
|
CancellationToken cancellationToken = default)
|
|
=> Unsupported<OpenClawCollectionDto<OpenClawModelAuthProviderDto>>();
|
|
public Task<OpenClawOperationDto<OpenClawTaskDto>> CancelTaskAsync(
|
|
string taskId,
|
|
string? reason,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<OpenClawTaskDto>>();
|
|
public Task<OpenClawOperationDto<object>> AbortSessionAsync(
|
|
string sessionKey,
|
|
string? runId,
|
|
bool clearQueued,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<object>>();
|
|
public Task<OpenClawOperationDto<object>> PatchSessionModelAsync(
|
|
string sessionKey,
|
|
string model,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<object>>();
|
|
public Task<OpenClawOperationDto<object>> RunCronJobAsync(
|
|
string jobId,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<object>>();
|
|
public Task<OpenClawOperationDto<object>> RunCronJobAsync(
|
|
string jobId,
|
|
string? expectedHash,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<object>>();
|
|
public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> CreateCronJobAsync(
|
|
CreateOpenClawCronJobRequest request,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
|
|
public Task<OpenClawOperationDto<OpenClawCronJobDetailDto>> PatchCronJobAsync(
|
|
string jobId,
|
|
JsonObject patch,
|
|
string? expectedHash,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<OpenClawCronJobDetailDto>>();
|
|
public Task<OpenClawOperationDto<object>> DeleteCronJobAsync(
|
|
string jobId,
|
|
string? expectedHash = null,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<object>>();
|
|
public Task<OpenClawOperationDto<OpenClawApprovalDto>> ResolveApprovalAsync(
|
|
string approvalId,
|
|
string kind,
|
|
string decision,
|
|
CancellationToken cancellationToken = default,
|
|
OpenClawInvocationContext? invocationContext = null)
|
|
=> Unsupported<OpenClawOperationDto<OpenClawApprovalDto>>();
|
|
|
|
private static OpenClawAgentDto Agent(
|
|
string id,
|
|
string name,
|
|
string model,
|
|
string workspace)
|
|
=> new(
|
|
Id: id,
|
|
Name: name,
|
|
Description: null,
|
|
Model: model,
|
|
Provider: "openai",
|
|
Workspace: workspace,
|
|
Status: "ready");
|
|
|
|
private static OpenClawCollectionDto<T> Collection<T>(IReadOnlyList<T> items)
|
|
=> new(
|
|
State: "ready",
|
|
Items: items,
|
|
NextCursor: null,
|
|
Message: null,
|
|
Recovery: null,
|
|
CheckedAt: DateTimeOffset.UtcNow);
|
|
|
|
private static Task<T> Unsupported<T>()
|
|
=> Task.FromException<T>(new NotSupportedException(
|
|
"This test double only supports live agent and session inventory."));
|
|
}
|