test(03-01): add failing tests for agent registry service
- 23 unit tests covering registration, heartbeat, lifecycle, queries, commands - Domain types: AgentInfo, AgentState, AgentCommand, CommandStatus, CommandType - AgentEventListener interface for SSE bridge - AgentRegistryService stub with UnsupportedOperationException Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Immutable record representing a command to be pushed to an agent.
|
||||
*
|
||||
* @param id unique command identifier (UUID)
|
||||
* @param type command type
|
||||
* @param payload raw JSON payload
|
||||
* @param targetAgentId target agent identifier
|
||||
* @param createdAt when the command was created
|
||||
* @param status current delivery status
|
||||
*/
|
||||
public record AgentCommand(
|
||||
String id,
|
||||
CommandType type,
|
||||
String payload,
|
||||
String targetAgentId,
|
||||
Instant createdAt,
|
||||
CommandStatus status
|
||||
) {
|
||||
|
||||
public AgentCommand withStatus(CommandStatus newStatus) {
|
||||
return new AgentCommand(id, type, payload, targetAgentId, createdAt, newStatus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
/**
|
||||
* Listener interface for agent registry events.
|
||||
* <p>
|
||||
* Defined in the core module so the registry service can notify listeners
|
||||
* without depending on Spring or SSE classes. The app module provides the
|
||||
* implementation that bridges to the SSE connection manager.
|
||||
*/
|
||||
public interface AgentEventListener {
|
||||
|
||||
/**
|
||||
* Called when a new command is ready to be delivered to an agent.
|
||||
*
|
||||
* @param agentId the target agent identifier
|
||||
* @param command the command to deliver
|
||||
*/
|
||||
void onCommandReady(String agentId, AgentCommand command);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Immutable record representing a registered agent's current state.
|
||||
* <p>
|
||||
* Stored in a {@link java.util.concurrent.ConcurrentHashMap} and atomically swapped
|
||||
* via {@code computeIfPresent} for thread-safe state transitions. Wither-style methods
|
||||
* return new instances with the specified field changed.
|
||||
*
|
||||
* @param id agent-provided persistent identifier
|
||||
* @param name human-readable agent name
|
||||
* @param group logical grouping (e.g., "order-service-prod")
|
||||
* @param version agent software version
|
||||
* @param routeIds list of Camel route IDs managed by this agent
|
||||
* @param capabilities agent-declared capabilities (free-form)
|
||||
* @param state current lifecycle state
|
||||
* @param registeredAt when the agent first registered (or re-registered)
|
||||
* @param lastHeartbeat last heartbeat timestamp
|
||||
* @param staleTransitionTime when the agent transitioned to STALE (null if not STALE/DEAD)
|
||||
*/
|
||||
public record AgentInfo(
|
||||
String id,
|
||||
String name,
|
||||
String group,
|
||||
String version,
|
||||
List<String> routeIds,
|
||||
Map<String, Object> capabilities,
|
||||
AgentState state,
|
||||
Instant registeredAt,
|
||||
Instant lastHeartbeat,
|
||||
Instant staleTransitionTime
|
||||
) {
|
||||
|
||||
public AgentInfo withState(AgentState newState) {
|
||||
return new AgentInfo(id, name, group, version, routeIds, capabilities,
|
||||
newState, registeredAt, lastHeartbeat, staleTransitionTime);
|
||||
}
|
||||
|
||||
public AgentInfo withLastHeartbeat(Instant newLastHeartbeat) {
|
||||
return new AgentInfo(id, name, group, version, routeIds, capabilities,
|
||||
state, registeredAt, newLastHeartbeat, staleTransitionTime);
|
||||
}
|
||||
|
||||
public AgentInfo withRegisteredAt(Instant newRegisteredAt) {
|
||||
return new AgentInfo(id, name, group, version, routeIds, capabilities,
|
||||
state, newRegisteredAt, lastHeartbeat, staleTransitionTime);
|
||||
}
|
||||
|
||||
public AgentInfo withStaleTransitionTime(Instant newStaleTransitionTime) {
|
||||
return new AgentInfo(id, name, group, version, routeIds, capabilities,
|
||||
state, registeredAt, lastHeartbeat, newStaleTransitionTime);
|
||||
}
|
||||
|
||||
public AgentInfo withMetadata(String name, String group, String version,
|
||||
List<String> routeIds, Map<String, Object> capabilities) {
|
||||
return new AgentInfo(id, name, group, version, routeIds, capabilities,
|
||||
state, registeredAt, lastHeartbeat, staleTransitionTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* In-memory agent registry managing agent lifecycle, heartbeats, and commands.
|
||||
* <p>
|
||||
* Plain class (no Spring annotations) -- wired as a bean by the app module.
|
||||
* Stub implementation for TDD RED phase.
|
||||
*/
|
||||
public class AgentRegistryService {
|
||||
|
||||
private final long staleThresholdMs;
|
||||
private final long deadThresholdMs;
|
||||
private final long commandExpiryMs;
|
||||
|
||||
public AgentRegistryService(long staleThresholdMs, long deadThresholdMs, long commandExpiryMs) {
|
||||
this.staleThresholdMs = staleThresholdMs;
|
||||
this.deadThresholdMs = deadThresholdMs;
|
||||
this.commandExpiryMs = commandExpiryMs;
|
||||
}
|
||||
|
||||
public AgentInfo register(String id, String name, String group, String version,
|
||||
List<String> routeIds, Map<String, Object> capabilities) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public boolean heartbeat(String id) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void transitionState(String id, AgentState newState) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void checkLifecycle() {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public AgentInfo findById(String id) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public List<AgentInfo> findAll() {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public List<AgentInfo> findByState(AgentState state) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public AgentCommand addCommand(String agentId, CommandType type, String payload) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public boolean acknowledgeCommand(String agentId, String commandId) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public List<AgentCommand> findPendingCommands(String agentId) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void markDelivered(String agentId, String commandId) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void expireOldCommands() {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void setEventListener(AgentEventListener listener) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
/**
|
||||
* Lifecycle states for a connected agent.
|
||||
*/
|
||||
public enum AgentState {
|
||||
LIVE,
|
||||
STALE,
|
||||
DEAD
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
/**
|
||||
* Delivery status of a command pushed to an agent.
|
||||
*/
|
||||
public enum CommandStatus {
|
||||
PENDING,
|
||||
DELIVERED,
|
||||
ACKNOWLEDGED,
|
||||
EXPIRED
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
/**
|
||||
* Types of commands that can be pushed to agents.
|
||||
*/
|
||||
public enum CommandType {
|
||||
CONFIG_UPDATE,
|
||||
DEEP_TRACE,
|
||||
REPLAY
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package com.cameleer3.server.core.agent;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class AgentRegistryServiceTest {
|
||||
|
||||
// Thresholds: 90s stale, 300s dead, 60s command expiry
|
||||
private AgentRegistryService registry;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
registry = new AgentRegistryService(90_000, 300_000, 60_000);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Registration {
|
||||
|
||||
@Test
|
||||
void registerNewAgent_createsWithLiveState() {
|
||||
AgentInfo agent = registry.register("agent-1", "Order Agent", "order-svc",
|
||||
"1.0.0", List.of("route1", "route2"), Map.of("feature", "tracing"));
|
||||
|
||||
assertThat(agent).isNotNull();
|
||||
assertThat(agent.id()).isEqualTo("agent-1");
|
||||
assertThat(agent.name()).isEqualTo("Order Agent");
|
||||
assertThat(agent.group()).isEqualTo("order-svc");
|
||||
assertThat(agent.version()).isEqualTo("1.0.0");
|
||||
assertThat(agent.routeIds()).containsExactly("route1", "route2");
|
||||
assertThat(agent.capabilities()).containsEntry("feature", "tracing");
|
||||
assertThat(agent.state()).isEqualTo(AgentState.LIVE);
|
||||
assertThat(agent.registeredAt()).isNotNull();
|
||||
assertThat(agent.lastHeartbeat()).isNotNull();
|
||||
assertThat(agent.staleTransitionTime()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void reRegisterSameId_updatesMetadataAndTransitionsToLive() {
|
||||
registry.register("agent-1", "Old Name", "old-group",
|
||||
"1.0.0", List.of("route1"), Map.of());
|
||||
|
||||
AgentInfo updated = registry.register("agent-1", "New Name", "new-group",
|
||||
"2.0.0", List.of("route1", "route2"), Map.of("new", "cap"));
|
||||
|
||||
assertThat(updated.id()).isEqualTo("agent-1");
|
||||
assertThat(updated.name()).isEqualTo("New Name");
|
||||
assertThat(updated.group()).isEqualTo("new-group");
|
||||
assertThat(updated.version()).isEqualTo("2.0.0");
|
||||
assertThat(updated.routeIds()).containsExactly("route1", "route2");
|
||||
assertThat(updated.capabilities()).containsEntry("new", "cap");
|
||||
assertThat(updated.state()).isEqualTo(AgentState.LIVE);
|
||||
assertThat(updated.staleTransitionTime()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void reRegisterSameId_updatesRegisteredAtAndLastHeartbeat() {
|
||||
AgentInfo first = registry.register("agent-1", "Name", "group",
|
||||
"1.0.0", List.of(), Map.of());
|
||||
Instant firstRegisteredAt = first.registeredAt();
|
||||
|
||||
AgentInfo second = registry.register("agent-1", "Name", "group",
|
||||
"1.0.0", List.of(), Map.of());
|
||||
|
||||
assertThat(second.registeredAt()).isAfterOrEqualTo(firstRegisteredAt);
|
||||
assertThat(second.lastHeartbeat()).isAfterOrEqualTo(first.lastHeartbeat());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Heartbeat {
|
||||
|
||||
@Test
|
||||
void heartbeatKnownAgent_returnsTrue() {
|
||||
registry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
|
||||
boolean result = registry.heartbeat("agent-1");
|
||||
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void heartbeatKnownAgent_updatesLastHeartbeat() {
|
||||
registry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
Instant before = registry.findById("agent-1").lastHeartbeat();
|
||||
|
||||
registry.heartbeat("agent-1");
|
||||
|
||||
AgentInfo after = registry.findById("agent-1");
|
||||
assertThat(after.lastHeartbeat()).isAfterOrEqualTo(before);
|
||||
}
|
||||
|
||||
@Test
|
||||
void heartbeatUnknownAgent_returnsFalse() {
|
||||
boolean result = registry.heartbeat("unknown-agent");
|
||||
|
||||
assertThat(result).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void heartbeatStaleAgent_transitionsToLive() {
|
||||
registry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
registry.transitionState("agent-1", AgentState.STALE);
|
||||
|
||||
assertThat(registry.findById("agent-1").state()).isEqualTo(AgentState.STALE);
|
||||
|
||||
registry.heartbeat("agent-1");
|
||||
|
||||
assertThat(registry.findById("agent-1").state()).isEqualTo(AgentState.LIVE);
|
||||
assertThat(registry.findById("agent-1").staleTransitionTime()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class LifecycleTransitions {
|
||||
|
||||
@Test
|
||||
void liveAgentBeyondStaleThreshold_transitionsToStale() {
|
||||
// Use very short thresholds for test
|
||||
AgentRegistryService shortRegistry = new AgentRegistryService(1, 300_000, 60_000);
|
||||
shortRegistry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
|
||||
// Wait briefly to exceed 1ms threshold
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
|
||||
shortRegistry.checkLifecycle();
|
||||
|
||||
AgentInfo agent = shortRegistry.findById("agent-1");
|
||||
assertThat(agent.state()).isEqualTo(AgentState.STALE);
|
||||
assertThat(agent.staleTransitionTime()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void staleAgentBeyondDeadThreshold_transitionsToDead() {
|
||||
// Use very short thresholds for test: 1ms stale, 1ms dead
|
||||
AgentRegistryService shortRegistry = new AgentRegistryService(1, 1, 60_000);
|
||||
shortRegistry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
shortRegistry.checkLifecycle(); // LIVE -> STALE
|
||||
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
shortRegistry.checkLifecycle(); // STALE -> DEAD
|
||||
|
||||
assertThat(shortRegistry.findById("agent-1").state()).isEqualTo(AgentState.DEAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deadAgentRemainsDead() {
|
||||
AgentRegistryService shortRegistry = new AgentRegistryService(1, 1, 60_000);
|
||||
shortRegistry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
shortRegistry.checkLifecycle();
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
shortRegistry.checkLifecycle();
|
||||
|
||||
assertThat(shortRegistry.findById("agent-1").state()).isEqualTo(AgentState.DEAD);
|
||||
|
||||
// Additional lifecycle check should not change state
|
||||
shortRegistry.checkLifecycle();
|
||||
assertThat(shortRegistry.findById("agent-1").state()).isEqualTo(AgentState.DEAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void transitionState_setsStaleTransitionTimeWhenGoingStale() {
|
||||
registry.register("agent-1", "Name", "group", "1.0.0", List.of(), Map.of());
|
||||
|
||||
registry.transitionState("agent-1", AgentState.STALE);
|
||||
|
||||
AgentInfo agent = registry.findById("agent-1");
|
||||
assertThat(agent.state()).isEqualTo(AgentState.STALE);
|
||||
assertThat(agent.staleTransitionTime()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Queries {
|
||||
|
||||
@Test
|
||||
void findAll_returnsAllAgents() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
registry.register("agent-2", "A2", "g", "1.0", List.of(), Map.of());
|
||||
|
||||
List<AgentInfo> all = registry.findAll();
|
||||
|
||||
assertThat(all).hasSize(2);
|
||||
assertThat(all).extracting(AgentInfo::id).containsExactlyInAnyOrder("agent-1", "agent-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findByState_filtersCorrectly() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
registry.register("agent-2", "A2", "g", "1.0", List.of(), Map.of());
|
||||
registry.transitionState("agent-2", AgentState.STALE);
|
||||
|
||||
List<AgentInfo> live = registry.findByState(AgentState.LIVE);
|
||||
List<AgentInfo> stale = registry.findByState(AgentState.STALE);
|
||||
|
||||
assertThat(live).hasSize(1).extracting(AgentInfo::id).containsExactly("agent-1");
|
||||
assertThat(stale).hasSize(1).extracting(AgentInfo::id).containsExactly("agent-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findById_unknownReturnsNull() {
|
||||
AgentInfo result = registry.findById("nonexistent");
|
||||
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findById_knownReturnsAgent() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
|
||||
AgentInfo result = registry.findById("agent-1");
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.id()).isEqualTo("agent-1");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Commands {
|
||||
|
||||
@Test
|
||||
void addCommand_createsPendingCommand() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
|
||||
AgentCommand cmd = registry.addCommand("agent-1", CommandType.CONFIG_UPDATE, "{\"key\":\"val\"}");
|
||||
|
||||
assertThat(cmd).isNotNull();
|
||||
assertThat(cmd.id()).isNotNull();
|
||||
assertThat(cmd.type()).isEqualTo(CommandType.CONFIG_UPDATE);
|
||||
assertThat(cmd.payload()).isEqualTo("{\"key\":\"val\"}");
|
||||
assertThat(cmd.targetAgentId()).isEqualTo("agent-1");
|
||||
assertThat(cmd.status()).isEqualTo(CommandStatus.PENDING);
|
||||
assertThat(cmd.createdAt()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void addCommand_notifiesEventListener() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
|
||||
AtomicReference<AgentCommand> received = new AtomicReference<>();
|
||||
registry.setEventListener((agentId, command) -> received.set(command));
|
||||
|
||||
AgentCommand cmd = registry.addCommand("agent-1", CommandType.DEEP_TRACE, "{}");
|
||||
|
||||
assertThat(received.get()).isNotNull();
|
||||
assertThat(received.get().id()).isEqualTo(cmd.id());
|
||||
}
|
||||
|
||||
@Test
|
||||
void acknowledgeCommand_transitionsStatus() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
AgentCommand cmd = registry.addCommand("agent-1", CommandType.REPLAY, "{}");
|
||||
|
||||
boolean acked = registry.acknowledgeCommand("agent-1", cmd.id());
|
||||
|
||||
assertThat(acked).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acknowledgeCommand_unknownReturnsFalse() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
|
||||
boolean acked = registry.acknowledgeCommand("agent-1", "nonexistent-cmd");
|
||||
|
||||
assertThat(acked).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findPendingCommands_returnsOnlyPending() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
AgentCommand cmd1 = registry.addCommand("agent-1", CommandType.CONFIG_UPDATE, "{}");
|
||||
AgentCommand cmd2 = registry.addCommand("agent-1", CommandType.DEEP_TRACE, "{}");
|
||||
registry.acknowledgeCommand("agent-1", cmd1.id());
|
||||
|
||||
List<AgentCommand> pending = registry.findPendingCommands("agent-1");
|
||||
|
||||
assertThat(pending).hasSize(1);
|
||||
assertThat(pending.get(0).id()).isEqualTo(cmd2.id());
|
||||
}
|
||||
|
||||
@Test
|
||||
void markDelivered_updatesStatus() {
|
||||
registry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
AgentCommand cmd = registry.addCommand("agent-1", CommandType.CONFIG_UPDATE, "{}");
|
||||
|
||||
registry.markDelivered("agent-1", cmd.id());
|
||||
|
||||
// After marking delivered, the command should no longer be PENDING
|
||||
List<AgentCommand> pending = registry.findPendingCommands("agent-1");
|
||||
assertThat(pending).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void expireOldCommands_removesExpiredPendingCommands() {
|
||||
// Use 1ms expiry for test
|
||||
AgentRegistryService shortRegistry = new AgentRegistryService(90_000, 300_000, 1);
|
||||
shortRegistry.register("agent-1", "A1", "g", "1.0", List.of(), Map.of());
|
||||
shortRegistry.addCommand("agent-1", CommandType.CONFIG_UPDATE, "{}");
|
||||
|
||||
try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
|
||||
|
||||
shortRegistry.expireOldCommands();
|
||||
|
||||
List<AgentCommand> pending = shortRegistry.findPendingCommands("agent-1");
|
||||
assertThat(pending).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void findPendingCommands_emptyForUnknownAgent() {
|
||||
List<AgentCommand> pending = registry.findPendingCommands("unknown");
|
||||
|
||||
assertThat(pending).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user