@masonator/coolify-mcp 0.1.3 → 0.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.
- package/dist/__tests__/coolify-client.test.js +137 -398
- package/dist/__tests__/mcp-server.test.js +24 -26
- package/dist/__tests__/resources/application-resources.test.js +6 -9
- package/dist/__tests__/resources/database-resources.test.js +30 -34
- package/dist/__tests__/resources/deployment-resources.test.js +19 -20
- package/dist/__tests__/resources/service-resources.test.js +36 -41
- package/dist/index.js +4 -6
- package/dist/lib/coolify-client.js +1 -5
- package/dist/lib/mcp-server.d.ts +2 -2
- package/dist/lib/mcp-server.js +542 -509
- package/dist/lib/resource.js +3 -7
- package/dist/resources/application-resources.js +6 -10
- package/dist/resources/database-resources.js +6 -10
- package/dist/resources/deployment-resources.js +5 -9
- package/dist/resources/index.js +4 -20
- package/dist/resources/service-resources.js +6 -10
- package/dist/types/coolify.js +1 -2
- package/package.json +17 -8
|
@@ -1,469 +1,208 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const coolify_client_js_1 = require("../lib/coolify-client.js");
|
|
4
|
-
// Mock fetch globally
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { CoolifyClient } from '../lib/coolify-client.js';
|
|
5
3
|
const mockFetch = jest.fn();
|
|
6
|
-
global.fetch = mockFetch;
|
|
7
4
|
describe('CoolifyClient', () => {
|
|
8
5
|
let client;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
const mockServers = [
|
|
7
|
+
{
|
|
8
|
+
id: 1,
|
|
9
|
+
uuid: 'test-uuid',
|
|
10
|
+
name: 'test-server',
|
|
11
|
+
status: 'running',
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
const mockServerInfo = {
|
|
15
|
+
id: 1,
|
|
16
|
+
uuid: 'test-uuid',
|
|
17
|
+
name: 'test-server',
|
|
18
|
+
status: 'running',
|
|
19
|
+
};
|
|
20
|
+
const mockServerResources = {
|
|
21
|
+
resources: [
|
|
20
22
|
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
status: 'running',
|
|
24
|
-
version: '1.0.0',
|
|
25
|
-
resources: {
|
|
26
|
-
cpu: 50,
|
|
27
|
-
memory: 60,
|
|
28
|
-
disk: 70,
|
|
29
|
-
},
|
|
23
|
+
name: 'memory',
|
|
24
|
+
value: '2GB',
|
|
30
25
|
},
|
|
31
26
|
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
status: 'stopped',
|
|
35
|
-
version: '1.0.0',
|
|
36
|
-
resources: {
|
|
37
|
-
cpu: 0,
|
|
38
|
-
memory: 0,
|
|
39
|
-
disk: 70,
|
|
40
|
-
},
|
|
27
|
+
name: 'disk',
|
|
28
|
+
value: '20GB',
|
|
41
29
|
},
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
const mockService = {
|
|
33
|
+
id: 1,
|
|
34
|
+
uuid: 'test-uuid',
|
|
35
|
+
name: 'test-service',
|
|
36
|
+
type: 'code-server',
|
|
37
|
+
status: 'running',
|
|
38
|
+
created_at: '2024-01-01',
|
|
39
|
+
updated_at: '2024-01-01',
|
|
40
|
+
};
|
|
41
|
+
const errorResponse = {
|
|
42
|
+
message: 'Resource not found',
|
|
43
|
+
};
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
mockFetch.mockClear();
|
|
46
|
+
global.fetch = mockFetch;
|
|
47
|
+
client = new CoolifyClient({
|
|
48
|
+
baseUrl: 'http://localhost:3000',
|
|
49
|
+
accessToken: 'test-api-key',
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('listServers', () => {
|
|
53
|
+
it('should return a list of servers', async () => {
|
|
54
|
+
mockFetch.mockImplementationOnce(async () => ({
|
|
45
55
|
ok: true,
|
|
46
56
|
json: async () => mockServers,
|
|
47
|
-
});
|
|
48
|
-
const result = await client.listServers();
|
|
49
|
-
expect(result).toEqual(mockServers);
|
|
50
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers', expect.objectContaining({
|
|
51
|
-
headers: expect.objectContaining({
|
|
52
|
-
Authorization: 'Bearer test-token',
|
|
53
|
-
'Content-Type': 'application/json',
|
|
54
|
-
}),
|
|
55
57
|
}));
|
|
58
|
+
const servers = await client.listServers();
|
|
59
|
+
expect(servers).toEqual(mockServers);
|
|
60
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers', {
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
Authorization: 'Bearer test-api-key',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
56
66
|
});
|
|
57
|
-
it('should handle
|
|
58
|
-
|
|
59
|
-
error: 'Unauthorized',
|
|
60
|
-
status: 401,
|
|
61
|
-
message: 'Invalid token',
|
|
62
|
-
};
|
|
63
|
-
mockFetch.mockResolvedValueOnce({
|
|
67
|
+
it('should handle errors', async () => {
|
|
68
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
64
69
|
ok: false,
|
|
65
70
|
json: async () => errorResponse,
|
|
66
|
-
});
|
|
67
|
-
await expect(client.listServers()).rejects.toThrow('
|
|
71
|
+
}));
|
|
72
|
+
await expect(client.listServers()).rejects.toThrow('Resource not found');
|
|
68
73
|
});
|
|
69
74
|
});
|
|
70
75
|
describe('getServer', () => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
name: 'test-server',
|
|
74
|
-
status: 'running',
|
|
75
|
-
version: '1.0.0',
|
|
76
|
-
resources: {
|
|
77
|
-
cpu: 50,
|
|
78
|
-
memory: 60,
|
|
79
|
-
disk: 70,
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
it('should fetch server info successfully', async () => {
|
|
83
|
-
mockFetch.mockResolvedValueOnce({
|
|
76
|
+
it('should get server info', async () => {
|
|
77
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
84
78
|
ok: true,
|
|
85
79
|
json: async () => mockServerInfo,
|
|
86
|
-
});
|
|
87
|
-
const result = await client.getServer('test-
|
|
80
|
+
}));
|
|
81
|
+
const result = await client.getServer('test-uuid');
|
|
88
82
|
expect(result).toEqual(mockServerInfo);
|
|
89
|
-
expect(mockFetch).toHaveBeenCalledWith('http://
|
|
90
|
-
headers:
|
|
91
|
-
Authorization: 'Bearer test-token',
|
|
83
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers/test-uuid', {
|
|
84
|
+
headers: {
|
|
92
85
|
'Content-Type': 'application/json',
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
96
|
-
it('should handle error responses', async () => {
|
|
97
|
-
const errorResponse = {
|
|
98
|
-
error: 'Not Found',
|
|
99
|
-
status: 404,
|
|
100
|
-
message: 'Server not found',
|
|
101
|
-
};
|
|
102
|
-
mockFetch.mockResolvedValueOnce({
|
|
103
|
-
ok: false,
|
|
104
|
-
json: async () => errorResponse,
|
|
86
|
+
Authorization: 'Bearer test-api-key',
|
|
87
|
+
},
|
|
105
88
|
});
|
|
106
|
-
await expect(client.getServer('invalid-id')).rejects.toThrow('Server not found');
|
|
107
89
|
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const mockServerResources = [
|
|
111
|
-
{
|
|
112
|
-
id: 1,
|
|
113
|
-
uuid: 'test-id',
|
|
114
|
-
name: 'test-app',
|
|
115
|
-
type: 'application',
|
|
116
|
-
created_at: '2024-03-19T12:00:00Z',
|
|
117
|
-
updated_at: '2024-03-19T12:00:00Z',
|
|
118
|
-
status: 'running:healthy',
|
|
119
|
-
},
|
|
120
|
-
];
|
|
121
|
-
it('should fetch server resources successfully', async () => {
|
|
122
|
-
mockFetch.mockResolvedValueOnce({
|
|
123
|
-
ok: true,
|
|
124
|
-
json: async () => mockServerResources,
|
|
125
|
-
});
|
|
126
|
-
const result = await client.getServerResources('test-id');
|
|
127
|
-
expect(result).toEqual(mockServerResources);
|
|
128
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-id/resources', expect.objectContaining({
|
|
129
|
-
headers: expect.objectContaining({
|
|
130
|
-
Authorization: 'Bearer test-token',
|
|
131
|
-
'Content-Type': 'application/json',
|
|
132
|
-
}),
|
|
133
|
-
}));
|
|
134
|
-
});
|
|
135
|
-
it('should handle error responses', async () => {
|
|
136
|
-
const errorResponse = {
|
|
137
|
-
error: 'Server Error',
|
|
138
|
-
status: 500,
|
|
139
|
-
message: 'Internal server error',
|
|
140
|
-
};
|
|
141
|
-
mockFetch.mockResolvedValueOnce({
|
|
90
|
+
it('should handle errors', async () => {
|
|
91
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
142
92
|
ok: false,
|
|
143
93
|
json: async () => errorResponse,
|
|
144
|
-
});
|
|
145
|
-
await expect(client.getServerResources('test-id')).rejects.toThrow('Internal server error');
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
test('getServer returns server info', async () => {
|
|
149
|
-
const mockResponse = {
|
|
150
|
-
uuid: 'test-uuid',
|
|
151
|
-
name: 'test-server',
|
|
152
|
-
status: 'running',
|
|
153
|
-
version: '1.0.0',
|
|
154
|
-
resources: {
|
|
155
|
-
cpu: 50,
|
|
156
|
-
memory: 60,
|
|
157
|
-
disk: 70,
|
|
158
|
-
},
|
|
159
|
-
};
|
|
160
|
-
mockFetch.mockResolvedValueOnce({
|
|
161
|
-
ok: true,
|
|
162
|
-
json: () => Promise.resolve(mockResponse),
|
|
163
|
-
});
|
|
164
|
-
const server = await client.getServer('test-uuid');
|
|
165
|
-
expect(server).toEqual(mockResponse);
|
|
166
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-uuid', expect.objectContaining({
|
|
167
|
-
headers: {
|
|
168
|
-
Authorization: 'Bearer test-token',
|
|
169
|
-
'Content-Type': 'application/json',
|
|
170
|
-
},
|
|
171
|
-
}));
|
|
172
|
-
});
|
|
173
|
-
test('getServerResources returns server resources', async () => {
|
|
174
|
-
const mockResponse = [
|
|
175
|
-
{
|
|
176
|
-
id: 1,
|
|
177
|
-
uuid: 'test-uuid',
|
|
178
|
-
name: 'test-app',
|
|
179
|
-
type: 'application',
|
|
180
|
-
created_at: '2025-03-05T13:41:12.000Z',
|
|
181
|
-
updated_at: '2025-03-05T13:41:12.000Z',
|
|
182
|
-
status: 'running:healthy',
|
|
183
|
-
},
|
|
184
|
-
];
|
|
185
|
-
mockFetch.mockResolvedValueOnce({
|
|
186
|
-
ok: true,
|
|
187
|
-
json: () => Promise.resolve(mockResponse),
|
|
188
|
-
});
|
|
189
|
-
const resources = await client.getServerResources('test-uuid');
|
|
190
|
-
expect(resources).toEqual(mockResponse);
|
|
191
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/servers/test-uuid/resources', expect.objectContaining({
|
|
192
|
-
headers: {
|
|
193
|
-
Authorization: 'Bearer test-token',
|
|
194
|
-
'Content-Type': 'application/json',
|
|
195
|
-
},
|
|
196
|
-
}));
|
|
197
|
-
});
|
|
198
|
-
describe('Environment Management', () => {
|
|
199
|
-
const mockEnvironment = {
|
|
200
|
-
id: 1,
|
|
201
|
-
uuid: 'jw0gwo4sowkoowswssk0gkc4',
|
|
202
|
-
name: 'production',
|
|
203
|
-
project_uuid: 'ikokwc8sk00wk8sg8gkwoscw',
|
|
204
|
-
created_at: '2025-02-11T11:37:33.000000Z',
|
|
205
|
-
updated_at: '2025-02-11T11:37:33.000000Z',
|
|
206
|
-
};
|
|
207
|
-
beforeEach(() => {
|
|
208
|
-
mockFetch.mockClear();
|
|
209
|
-
});
|
|
210
|
-
describe('getProjectEnvironment', () => {
|
|
211
|
-
it('should fetch environment by project UUID and name/UUID successfully', async () => {
|
|
212
|
-
mockFetch.mockResolvedValueOnce({
|
|
213
|
-
ok: true,
|
|
214
|
-
json: () => Promise.resolve(mockEnvironment),
|
|
215
|
-
});
|
|
216
|
-
const result = await client.getProjectEnvironment('ikokwc8sk00wk8sg8gkwoscw', 'production');
|
|
217
|
-
expect(result).toEqual(mockEnvironment);
|
|
218
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/projects/ikokwc8sk00wk8sg8gkwoscw/production', expect.objectContaining({
|
|
219
|
-
headers: expect.objectContaining({
|
|
220
|
-
Authorization: 'Bearer test-token',
|
|
221
|
-
'Content-Type': 'application/json',
|
|
222
|
-
}),
|
|
223
|
-
}));
|
|
224
|
-
});
|
|
225
|
-
it('should handle not found error', async () => {
|
|
226
|
-
const errorResponse = {
|
|
227
|
-
error: 'Not Found',
|
|
228
|
-
status: 404,
|
|
229
|
-
message: 'Environment not found',
|
|
230
|
-
};
|
|
231
|
-
mockFetch.mockResolvedValueOnce({
|
|
232
|
-
ok: false,
|
|
233
|
-
json: () => Promise.resolve(errorResponse),
|
|
234
|
-
});
|
|
235
|
-
await expect(client.getProjectEnvironment('invalid-project', 'invalid-env')).rejects.toThrow('Environment not found');
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
describe('deployApplication', () => {
|
|
240
|
-
it('should deploy an application', async () => {
|
|
241
|
-
const mockDeployment = {
|
|
242
|
-
id: 1,
|
|
243
|
-
uuid: 'test-deployment-uuid',
|
|
244
|
-
application_uuid: 'test-app-uuid',
|
|
245
|
-
status: 'running',
|
|
246
|
-
created_at: '2024-03-20T12:00:00Z',
|
|
247
|
-
updated_at: '2024-03-20T12:00:00Z',
|
|
248
|
-
};
|
|
249
|
-
mockFetch.mockResolvedValueOnce({
|
|
250
|
-
ok: true,
|
|
251
|
-
json: () => Promise.resolve(mockDeployment),
|
|
252
|
-
});
|
|
253
|
-
const result = await client.deployApplication('test-app-uuid');
|
|
254
|
-
expect(result).toEqual(mockDeployment);
|
|
255
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/applications/test-app-uuid/deploy', expect.objectContaining({
|
|
256
|
-
method: 'POST',
|
|
257
|
-
headers: expect.objectContaining({
|
|
258
|
-
Authorization: 'Bearer test-token',
|
|
259
|
-
'Content-Type': 'application/json',
|
|
260
|
-
}),
|
|
261
94
|
}));
|
|
262
|
-
|
|
263
|
-
it('should handle errors when deploying an application', async () => {
|
|
264
|
-
const errorResponse = {
|
|
265
|
-
error: 'Error',
|
|
266
|
-
status: 500,
|
|
267
|
-
message: 'Failed to deploy application',
|
|
268
|
-
};
|
|
269
|
-
mockFetch.mockResolvedValueOnce({
|
|
270
|
-
ok: false,
|
|
271
|
-
json: () => Promise.resolve(errorResponse),
|
|
272
|
-
});
|
|
273
|
-
await expect(client.deployApplication('test-app-uuid')).rejects.toThrow('Failed to deploy application');
|
|
95
|
+
await expect(client.getServer('test-uuid')).rejects.toThrow('Resource not found');
|
|
274
96
|
});
|
|
275
97
|
});
|
|
276
|
-
describe('
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
uuid: 'test-db-uuid',
|
|
280
|
-
name: 'test-db',
|
|
281
|
-
description: 'Test database',
|
|
282
|
-
type: 'postgresql',
|
|
283
|
-
status: 'running',
|
|
284
|
-
created_at: '2024-03-06T12:00:00Z',
|
|
285
|
-
updated_at: '2024-03-06T12:00:00Z',
|
|
286
|
-
is_public: false,
|
|
287
|
-
image: 'postgres:latest',
|
|
288
|
-
postgres_user: 'postgres',
|
|
289
|
-
postgres_password: 'test123',
|
|
290
|
-
postgres_db: 'testdb',
|
|
291
|
-
};
|
|
292
|
-
beforeEach(() => {
|
|
293
|
-
mockFetch.mockClear();
|
|
294
|
-
});
|
|
295
|
-
it('should list databases', async () => {
|
|
296
|
-
mockFetch.mockResolvedValueOnce({
|
|
98
|
+
describe('getServerResources', () => {
|
|
99
|
+
it('should get server resources', async () => {
|
|
100
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
297
101
|
ok: true,
|
|
298
|
-
json: () =>
|
|
299
|
-
});
|
|
300
|
-
const result = await client.listDatabases();
|
|
301
|
-
expect(result).toEqual([mockDatabase]);
|
|
302
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases', expect.objectContaining({
|
|
303
|
-
headers: {
|
|
304
|
-
'Content-Type': 'application/json',
|
|
305
|
-
Authorization: 'Bearer test-token',
|
|
306
|
-
},
|
|
102
|
+
json: async () => mockServerResources,
|
|
307
103
|
}));
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
mockFetch.
|
|
311
|
-
ok: true,
|
|
312
|
-
json: () => Promise.resolve(mockDatabase),
|
|
313
|
-
});
|
|
314
|
-
const result = await client.getDatabase('test-db-uuid');
|
|
315
|
-
expect(result).toEqual(mockDatabase);
|
|
316
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid', expect.objectContaining({
|
|
104
|
+
const result = await client.getServerResources('test-uuid');
|
|
105
|
+
expect(result).toEqual(mockServerResources);
|
|
106
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/servers/test-uuid/resources', {
|
|
317
107
|
headers: {
|
|
318
108
|
'Content-Type': 'application/json',
|
|
319
|
-
Authorization: 'Bearer test-
|
|
109
|
+
Authorization: 'Bearer test-api-key',
|
|
320
110
|
},
|
|
321
|
-
}));
|
|
322
|
-
});
|
|
323
|
-
it('should update database', async () => {
|
|
324
|
-
const updateData = {
|
|
325
|
-
name: 'updated-db',
|
|
326
|
-
description: 'Updated description',
|
|
327
|
-
};
|
|
328
|
-
mockFetch.mockResolvedValueOnce({
|
|
329
|
-
ok: true,
|
|
330
|
-
json: () => Promise.resolve({ ...mockDatabase, ...updateData }),
|
|
331
111
|
});
|
|
332
|
-
const result = await client.updateDatabase('test-db-uuid', updateData);
|
|
333
|
-
expect(result).toEqual({ ...mockDatabase, ...updateData });
|
|
334
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid', expect.objectContaining({
|
|
335
|
-
method: 'PATCH',
|
|
336
|
-
body: JSON.stringify(updateData),
|
|
337
|
-
headers: {
|
|
338
|
-
'Content-Type': 'application/json',
|
|
339
|
-
Authorization: 'Bearer test-token',
|
|
340
|
-
},
|
|
341
|
-
}));
|
|
342
112
|
});
|
|
343
|
-
it('should
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
json: () => Promise.resolve(mockResponse),
|
|
348
|
-
});
|
|
349
|
-
const result = await client.deleteDatabase('test-db-uuid', {
|
|
350
|
-
deleteConfigurations: true,
|
|
351
|
-
deleteVolumes: true,
|
|
352
|
-
});
|
|
353
|
-
expect(result).toEqual(mockResponse);
|
|
354
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/databases/test-db-uuid?delete_configurations=true&delete_volumes=true', expect.objectContaining({
|
|
355
|
-
method: 'DELETE',
|
|
356
|
-
headers: {
|
|
357
|
-
'Content-Type': 'application/json',
|
|
358
|
-
Authorization: 'Bearer test-token',
|
|
359
|
-
},
|
|
113
|
+
it('should handle errors', async () => {
|
|
114
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
115
|
+
ok: false,
|
|
116
|
+
json: async () => errorResponse,
|
|
360
117
|
}));
|
|
361
|
-
|
|
362
|
-
it('should handle database errors', async () => {
|
|
363
|
-
const errorMessage = 'Database not found';
|
|
364
|
-
mockFetch.mockRejectedValue(new Error(errorMessage));
|
|
365
|
-
await expect(client.getDatabase('invalid-uuid')).rejects.toThrow(errorMessage);
|
|
118
|
+
await expect(client.getServerResources('test-uuid')).rejects.toThrow('Resource not found');
|
|
366
119
|
});
|
|
367
120
|
});
|
|
368
|
-
describe('
|
|
369
|
-
const mockService = {
|
|
370
|
-
id: 1,
|
|
371
|
-
uuid: 'test-service-uuid',
|
|
372
|
-
name: 'test-service',
|
|
373
|
-
description: 'Test service',
|
|
374
|
-
type: 'code-server',
|
|
375
|
-
status: 'running',
|
|
376
|
-
created_at: '2024-03-06T12:00:00Z',
|
|
377
|
-
updated_at: '2024-03-06T12:00:00Z',
|
|
378
|
-
project_uuid: 'test-project-uuid',
|
|
379
|
-
environment_name: 'production',
|
|
380
|
-
environment_uuid: 'test-env-uuid',
|
|
381
|
-
server_uuid: 'test-server-uuid',
|
|
382
|
-
domains: ['test-service.example.com'],
|
|
383
|
-
};
|
|
384
|
-
beforeEach(() => {
|
|
385
|
-
mockFetch.mockClear();
|
|
386
|
-
});
|
|
121
|
+
describe('listServices', () => {
|
|
387
122
|
it('should list services', async () => {
|
|
388
|
-
mockFetch.
|
|
123
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
389
124
|
ok: true,
|
|
390
125
|
json: () => Promise.resolve([mockService]),
|
|
391
|
-
});
|
|
126
|
+
}));
|
|
392
127
|
const result = await client.listServices();
|
|
393
128
|
expect(result).toEqual([mockService]);
|
|
394
|
-
expect(mockFetch).toHaveBeenCalledWith('http://
|
|
129
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services', {
|
|
395
130
|
headers: {
|
|
396
131
|
'Content-Type': 'application/json',
|
|
397
|
-
Authorization: 'Bearer test-
|
|
132
|
+
Authorization: 'Bearer test-api-key',
|
|
398
133
|
},
|
|
399
|
-
})
|
|
134
|
+
});
|
|
400
135
|
});
|
|
401
|
-
|
|
402
|
-
|
|
136
|
+
});
|
|
137
|
+
describe('getService', () => {
|
|
138
|
+
it('should get service info', async () => {
|
|
139
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
403
140
|
ok: true,
|
|
404
141
|
json: () => Promise.resolve(mockService),
|
|
405
|
-
});
|
|
406
|
-
const result = await client.getService('test-
|
|
142
|
+
}));
|
|
143
|
+
const result = await client.getService('test-uuid');
|
|
407
144
|
expect(result).toEqual(mockService);
|
|
408
|
-
expect(mockFetch).toHaveBeenCalledWith('http://
|
|
145
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services/test-uuid', {
|
|
409
146
|
headers: {
|
|
410
147
|
'Content-Type': 'application/json',
|
|
411
|
-
Authorization: 'Bearer test-
|
|
148
|
+
Authorization: 'Bearer test-api-key',
|
|
412
149
|
},
|
|
413
|
-
})
|
|
150
|
+
});
|
|
414
151
|
});
|
|
415
|
-
|
|
152
|
+
});
|
|
153
|
+
describe('createService', () => {
|
|
154
|
+
it('should create a service', async () => {
|
|
155
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
156
|
+
ok: true,
|
|
157
|
+
json: () => Promise.resolve({
|
|
158
|
+
uuid: 'test-uuid',
|
|
159
|
+
domains: ['test.com'],
|
|
160
|
+
}),
|
|
161
|
+
}));
|
|
416
162
|
const createData = {
|
|
417
|
-
type: 'code-server',
|
|
418
163
|
name: 'test-service',
|
|
419
|
-
|
|
420
|
-
project_uuid: '
|
|
421
|
-
|
|
422
|
-
server_uuid: '
|
|
423
|
-
instant_deploy: true,
|
|
424
|
-
};
|
|
425
|
-
const mockResponse = {
|
|
426
|
-
uuid: 'test-service-uuid',
|
|
427
|
-
domains: ['test-service.example.com'],
|
|
164
|
+
type: 'code-server',
|
|
165
|
+
project_uuid: 'project-uuid',
|
|
166
|
+
environment_uuid: 'env-uuid',
|
|
167
|
+
server_uuid: 'server-uuid',
|
|
428
168
|
};
|
|
429
|
-
mockFetch.mockResolvedValueOnce({
|
|
430
|
-
ok: true,
|
|
431
|
-
json: () => Promise.resolve(mockResponse),
|
|
432
|
-
});
|
|
433
169
|
const result = await client.createService(createData);
|
|
434
|
-
expect(result).toEqual(
|
|
435
|
-
|
|
170
|
+
expect(result).toEqual({
|
|
171
|
+
uuid: 'test-uuid',
|
|
172
|
+
domains: ['test.com'],
|
|
173
|
+
});
|
|
174
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services', {
|
|
436
175
|
method: 'POST',
|
|
437
|
-
body: JSON.stringify(createData),
|
|
438
176
|
headers: {
|
|
439
177
|
'Content-Type': 'application/json',
|
|
440
|
-
Authorization: 'Bearer test-
|
|
178
|
+
Authorization: 'Bearer test-api-key',
|
|
441
179
|
},
|
|
442
|
-
|
|
180
|
+
body: JSON.stringify(createData),
|
|
181
|
+
});
|
|
443
182
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
183
|
+
});
|
|
184
|
+
describe('deleteService', () => {
|
|
185
|
+
it('should delete a service', async () => {
|
|
186
|
+
mockFetch.mockImplementationOnce(() => Promise.resolve({
|
|
447
187
|
ok: true,
|
|
448
|
-
json: () => Promise.resolve(
|
|
449
|
-
});
|
|
450
|
-
const result = await client.deleteService('test-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
});
|
|
454
|
-
expect(result).toEqual(mockResponse);
|
|
455
|
-
expect(mockFetch).toHaveBeenCalledWith('http://test.coolify.io/api/v1/services/test-service-uuid?delete_configurations=true&delete_volumes=true', expect.objectContaining({
|
|
188
|
+
json: () => Promise.resolve({ message: 'Service deleted' }),
|
|
189
|
+
}));
|
|
190
|
+
const result = await client.deleteService('test-uuid');
|
|
191
|
+
expect(result).toEqual({ message: 'Service deleted' });
|
|
192
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/services/test-uuid', {
|
|
456
193
|
method: 'DELETE',
|
|
457
194
|
headers: {
|
|
458
195
|
'Content-Type': 'application/json',
|
|
459
|
-
Authorization: 'Bearer test-
|
|
196
|
+
Authorization: 'Bearer test-api-key',
|
|
460
197
|
},
|
|
461
|
-
})
|
|
198
|
+
});
|
|
462
199
|
});
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
200
|
+
});
|
|
201
|
+
describe('error handling', () => {
|
|
202
|
+
it('should handle network errors', async () => {
|
|
203
|
+
const errorMessage = 'Network error';
|
|
204
|
+
mockFetch.mockImplementationOnce(() => Promise.reject(new Error(errorMessage)));
|
|
205
|
+
await expect(client.listServers()).rejects.toThrow(errorMessage);
|
|
467
206
|
});
|
|
468
207
|
});
|
|
469
208
|
});
|