agenthub-multiagent-mcp 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,208 +1,223 @@
1
- /**
2
- * Integration tests for AgentHub API client
3
- *
4
- * These tests require the AgentHub server to be running on localhost:8787
5
- * Run: cd server && go run ./cmd/agenthub serve --port 8787
6
- */
7
-
8
- import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest";
9
- import { ApiClient } from "./client.js";
10
-
11
- const TEST_URL = process.env.AGENTHUB_URL || "http://localhost:8787";
12
- const TEST_API_KEY = process.env.AGENTHUB_API_KEY || "test-key-123";
13
-
14
- describe("ApiClient Integration", () => {
15
- let client: ApiClient;
16
- let testAgentId: string;
17
- let testChannelName: string;
18
-
19
- beforeAll(() => {
20
- client = new ApiClient(TEST_URL, TEST_API_KEY);
21
- testAgentId = `test-agent-${Date.now()}`;
22
- testChannelName = `test-channel-${Date.now()}`;
23
- });
24
-
25
- afterAll(async () => {
26
- // Cleanup - disconnect agent
27
- try {
28
- await client.disconnect(testAgentId);
29
- } catch {
30
- // Ignore cleanup errors
31
- }
32
- });
33
-
34
- describe("Agent Operations", () => {
35
- it("should register an agent", async () => {
36
- const result = await client.registerAgent(testAgentId, "Test Agent");
37
-
38
- expect(result.agent_id).toBe(testAgentId);
39
- expect(result.registered_at).toBeDefined();
40
- });
41
-
42
- it("should get agent details", async () => {
43
- const agent = await client.getAgent(testAgentId);
44
-
45
- expect(agent.id).toBe(testAgentId);
46
- expect(agent.name).toBe("Test Agent");
47
- expect(agent.status).toBe("online");
48
- });
49
-
50
- it("should list agents", async () => {
51
- const result = await client.listAgents();
52
-
53
- expect(result.agents).toBeDefined();
54
- expect(result.total).toBeGreaterThan(0);
55
-
56
- const testAgent = result.agents.find((a) => a.id === testAgentId);
57
- expect(testAgent).toBeDefined();
58
- });
59
-
60
- it("should filter agents by status", async () => {
61
- const result = await client.listAgents("online");
62
-
63
- expect(result.agents).toBeDefined();
64
- for (const agent of result.agents) {
65
- expect(agent.status).toBe("online");
66
- }
67
- });
68
-
69
- it("should start work", async () => {
70
- const result = await client.startWork(testAgentId, "Running tests", "TestProject");
71
-
72
- expect(result.acknowledged).toBe(true);
73
- });
74
-
75
- it("should send heartbeat", async () => {
76
- const result = await client.heartbeat(testAgentId, "busy");
77
-
78
- expect(result.acknowledged).toBe(true);
79
- expect(result.timestamp).toBeDefined();
80
- });
81
- });
82
-
83
- describe("Channel Operations", () => {
84
- let secondAgentId: string;
85
-
86
- beforeAll(async () => {
87
- secondAgentId = `test-agent-2-${Date.now()}`;
88
- await client.registerAgent(secondAgentId, "Test Agent 2");
89
- });
90
-
91
- afterAll(async () => {
92
- try {
93
- await client.disconnect(secondAgentId);
94
- } catch {
95
- // Ignore cleanup errors
96
- }
97
- });
98
-
99
- it("should list channels", async () => {
100
- const result = await client.listChannels();
101
-
102
- expect(result.channels).toBeDefined();
103
- expect(typeof result.total).toBe("number");
104
- });
105
-
106
- it("should join channel", async () => {
107
- // First ensure channel exists by trying to join
108
- // If the channel doesn't exist, this will fail - we need to create it first
109
- // But we don't have a createChannel method in the client
110
-
111
- // For this test, we assume the channel exists or the server auto-creates
112
- // Skip this test if the channel doesn't exist
113
- try {
114
- const result = await client.joinChannel(testChannelName, testAgentId);
115
- expect(result.subscribed).toBe(true);
116
- } catch (e) {
117
- // Channel might not exist, skip
118
- console.log("Channel join test skipped - channel may not exist");
119
- }
120
- });
121
- });
122
-
123
- describe("Message Operations", () => {
124
- let secondAgentId: string;
125
- let messageId: string;
126
-
127
- beforeAll(async () => {
128
- secondAgentId = `test-agent-msg-${Date.now()}`;
129
- await client.registerAgent(secondAgentId, "Test Agent Msg");
130
- });
131
-
132
- afterAll(async () => {
133
- try {
134
- await client.disconnect(secondAgentId);
135
- } catch {
136
- // Ignore cleanup errors
137
- }
138
- });
139
-
140
- it("should send a direct message", async () => {
141
- const result = await client.sendMessage({
142
- from_agent: testAgentId,
143
- to_agent: secondAgentId,
144
- type: "task",
145
- subject: "Test Message",
146
- body: "This is a test message",
147
- priority: "normal",
148
- });
149
-
150
- expect(result.message_id).toBeDefined();
151
- expect(result.status).toBe("pending");
152
- messageId = result.message_id;
153
- });
154
-
155
- it("should get inbox messages", async () => {
156
- const result = await client.getInbox(secondAgentId);
157
-
158
- expect(result.messages).toBeDefined();
159
- expect(result.total).toBeGreaterThan(0);
160
-
161
- const testMessage = result.messages.find((m) => m.id === messageId);
162
- expect(testMessage).toBeDefined();
163
- expect(testMessage?.subject).toBe("Test Message");
164
- });
165
-
166
- it("should mark message as read", async () => {
167
- // First need to mark as delivered
168
- const patchUrl = `${TEST_URL}/messages/${messageId}/status`;
169
- await fetch(patchUrl, {
170
- method: "PATCH",
171
- headers: {
172
- "Content-Type": "application/json",
173
- "X-API-Key": TEST_API_KEY,
174
- },
175
- body: JSON.stringify({ status: "delivered" }),
176
- });
177
-
178
- const result = await client.markRead(messageId);
179
-
180
- expect(result.updated).toBe(true);
181
- });
182
-
183
- it("should send a broadcast message", async () => {
184
- const result = await client.sendMessage({
185
- from_agent: testAgentId,
186
- broadcast: true,
187
- type: "status",
188
- subject: "Broadcast Test",
189
- body: "This is a broadcast",
190
- });
191
-
192
- expect(result.message_id).toBeDefined();
193
- expect(result.status).toBe("pending");
194
- });
195
- });
196
-
197
- describe("Error Handling", () => {
198
- it("should throw error for non-existent agent", async () => {
199
- await expect(client.getAgent("non-existent-agent-xyz")).rejects.toThrow();
200
- });
201
-
202
- it("should throw error for duplicate registration", async () => {
203
- await expect(
204
- client.registerAgent(testAgentId, "Duplicate Agent")
205
- ).rejects.toThrow(/already registered/i);
206
- });
207
- });
208
- });
1
+ /**
2
+ * Integration tests for AgentHub API client
3
+ *
4
+ * These tests require the AgentHub server to be running on localhost:8787
5
+ * Run: cd server && go run ./cmd/agenthub serve --port 8787
6
+ *
7
+ * Set AGENTHUB_INTEGRATION_TESTS=1 to run these tests
8
+ */
9
+
10
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
11
+ import { ApiClient } from "./client.js";
12
+
13
+ const TEST_URL = process.env.AGENTHUB_URL || "http://localhost:8787";
14
+ const TEST_API_KEY = process.env.AGENTHUB_API_KEY || "test-key-123";
15
+ const RUN_INTEGRATION = process.env.AGENTHUB_INTEGRATION_TESTS === "1";
16
+
17
+ // Helper to check if server is reachable
18
+ async function isServerReachable(): Promise<boolean> {
19
+ try {
20
+ const response = await fetch(`${TEST_URL}/health`, {
21
+ signal: AbortSignal.timeout(2000)
22
+ });
23
+ return response.ok;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ describe.skipIf(!RUN_INTEGRATION)("ApiClient Integration", () => {
30
+ let client: ApiClient;
31
+ let testAgentId: string;
32
+ let testChannelName: string;
33
+
34
+ beforeAll(() => {
35
+ client = new ApiClient(TEST_URL, TEST_API_KEY);
36
+ testAgentId = `test-agent-${Date.now()}`;
37
+ testChannelName = `test-channel-${Date.now()}`;
38
+ });
39
+
40
+ afterAll(async () => {
41
+ // Cleanup - disconnect agent
42
+ try {
43
+ await client.disconnect(testAgentId);
44
+ } catch {
45
+ // Ignore cleanup errors
46
+ }
47
+ });
48
+
49
+ describe("Agent Operations", () => {
50
+ it("should register an agent", async () => {
51
+ const result = await client.registerAgent(testAgentId, "Test Agent");
52
+
53
+ expect(result.agent_id).toBe(testAgentId);
54
+ expect(result.registered_at).toBeDefined();
55
+ });
56
+
57
+ it("should get agent details", async () => {
58
+ const agent = await client.getAgent(testAgentId);
59
+
60
+ expect(agent.id).toBe(testAgentId);
61
+ expect(agent.name).toBe("Test Agent");
62
+ expect(agent.status).toBe("online");
63
+ });
64
+
65
+ it("should list agents", async () => {
66
+ const result = await client.listAgents();
67
+
68
+ expect(result.agents).toBeDefined();
69
+ expect(result.total).toBeGreaterThan(0);
70
+
71
+ const testAgent = result.agents.find((a) => a.id === testAgentId);
72
+ expect(testAgent).toBeDefined();
73
+ });
74
+
75
+ it("should filter agents by status", async () => {
76
+ const result = await client.listAgents("online");
77
+
78
+ expect(result.agents).toBeDefined();
79
+ for (const agent of result.agents) {
80
+ expect(agent.status).toBe("online");
81
+ }
82
+ });
83
+
84
+ it("should start work", async () => {
85
+ const result = await client.startWork(testAgentId, "Running tests", "TestProject");
86
+
87
+ expect(result.acknowledged).toBe(true);
88
+ });
89
+
90
+ it("should send heartbeat", async () => {
91
+ const result = await client.heartbeat(testAgentId, "busy");
92
+
93
+ expect(result.acknowledged).toBe(true);
94
+ expect(result.timestamp).toBeDefined();
95
+ });
96
+ });
97
+
98
+ describe("Channel Operations", () => {
99
+ let secondAgentId: string;
100
+
101
+ beforeAll(async () => {
102
+ secondAgentId = `test-agent-2-${Date.now()}`;
103
+ await client.registerAgent(secondAgentId, "Test Agent 2");
104
+ });
105
+
106
+ afterAll(async () => {
107
+ try {
108
+ await client.disconnect(secondAgentId);
109
+ } catch {
110
+ // Ignore cleanup errors
111
+ }
112
+ });
113
+
114
+ it("should list channels", async () => {
115
+ const result = await client.listChannels();
116
+
117
+ expect(result.channels).toBeDefined();
118
+ expect(typeof result.total).toBe("number");
119
+ });
120
+
121
+ it("should join channel", async () => {
122
+ // First ensure channel exists by trying to join
123
+ // If the channel doesn't exist, this will fail - we need to create it first
124
+ // But we don't have a createChannel method in the client
125
+
126
+ // For this test, we assume the channel exists or the server auto-creates
127
+ // Skip this test if the channel doesn't exist
128
+ try {
129
+ const result = await client.joinChannel(testChannelName, testAgentId);
130
+ expect(result.subscribed).toBe(true);
131
+ } catch (e) {
132
+ // Channel might not exist, skip
133
+ console.log("Channel join test skipped - channel may not exist");
134
+ }
135
+ });
136
+ });
137
+
138
+ describe("Message Operations", () => {
139
+ let secondAgentId: string;
140
+ let messageId: string;
141
+
142
+ beforeAll(async () => {
143
+ secondAgentId = `test-agent-msg-${Date.now()}`;
144
+ await client.registerAgent(secondAgentId, "Test Agent Msg");
145
+ });
146
+
147
+ afterAll(async () => {
148
+ try {
149
+ await client.disconnect(secondAgentId);
150
+ } catch {
151
+ // Ignore cleanup errors
152
+ }
153
+ });
154
+
155
+ it("should send a direct message", async () => {
156
+ const result = await client.sendMessage({
157
+ from_agent: testAgentId,
158
+ to_agent: secondAgentId,
159
+ type: "task",
160
+ subject: "Test Message",
161
+ body: "This is a test message",
162
+ priority: "normal",
163
+ });
164
+
165
+ expect(result.message_id).toBeDefined();
166
+ expect(result.status).toBe("pending");
167
+ messageId = result.message_id;
168
+ });
169
+
170
+ it("should get inbox messages", async () => {
171
+ const result = await client.getInbox(secondAgentId);
172
+
173
+ expect(result.messages).toBeDefined();
174
+ expect(result.total).toBeGreaterThan(0);
175
+
176
+ const testMessage = result.messages.find((m) => m.id === messageId);
177
+ expect(testMessage).toBeDefined();
178
+ expect(testMessage?.subject).toBe("Test Message");
179
+ });
180
+
181
+ it("should mark message as read", async () => {
182
+ // First need to mark as delivered
183
+ const patchUrl = `${TEST_URL}/messages/${messageId}/status`;
184
+ await fetch(patchUrl, {
185
+ method: "PATCH",
186
+ headers: {
187
+ "Content-Type": "application/json",
188
+ "X-API-Key": TEST_API_KEY,
189
+ },
190
+ body: JSON.stringify({ status: "delivered" }),
191
+ });
192
+
193
+ const result = await client.markRead(messageId);
194
+
195
+ expect(result.updated).toBe(true);
196
+ });
197
+
198
+ it("should send a broadcast message", async () => {
199
+ const result = await client.sendMessage({
200
+ from_agent: testAgentId,
201
+ broadcast: true,
202
+ type: "status",
203
+ subject: "Broadcast Test",
204
+ body: "This is a broadcast",
205
+ });
206
+
207
+ expect(result.message_id).toBeDefined();
208
+ expect(result.status).toBe("pending");
209
+ });
210
+ });
211
+
212
+ describe("Error Handling", () => {
213
+ it("should throw error for non-existent agent", async () => {
214
+ await expect(client.getAgent("non-existent-agent-xyz")).rejects.toThrow();
215
+ });
216
+
217
+ it("should throw error for duplicate registration", async () => {
218
+ await expect(
219
+ client.registerAgent(testAgentId, "Duplicate Agent")
220
+ ).rejects.toThrow(/already registered/i);
221
+ });
222
+ });
223
+ });