genlayer 0.2.0 → 0.3.0
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/CHANGELOG.md +7 -0
- package/dist/index.js +30856 -24164
- package/esbuild.config.dev +1 -0
- package/esbuild.config.prod +1 -0
- package/package.json +3 -1
- package/src/commands/general/init.ts +3 -3
- package/src/commands/general/start.ts +3 -3
- package/src/lib/clients/system.ts +1 -45
- package/src/lib/config/simulator.ts +1 -6
- package/src/lib/services/simulator.ts +29 -26
- package/tests/actions/init.test.ts +75 -1
- package/tests/actions/start.test.ts +14 -0
- package/tests/libs/system.test.ts +1 -76
- package/tests/services/simulator.test.ts +152 -49
package/esbuild.config.dev
CHANGED
package/esbuild.config.prod
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genlayer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "GenLayer Command Line Tool",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"homepage": "https://github.com/yeagerai/genlayer-cli#readme",
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@release-it/conventional-changelog": "^8.0.1",
|
|
37
|
+
"@types/dockerode": "^3.3.31",
|
|
37
38
|
"@types/inquirer": "^9.0.7",
|
|
38
39
|
"@types/node": "^20.12.7",
|
|
39
40
|
"@types/sinon": "^17.0.3",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
},
|
|
56
57
|
"dependencies": {
|
|
57
58
|
"commander": "^12.0.0",
|
|
59
|
+
"dockerode": "^4.0.2",
|
|
58
60
|
"dotenv": "^16.4.5",
|
|
59
61
|
"inquirer": "^9.2.19",
|
|
60
62
|
"node-fetch": "^2.7.0",
|
|
@@ -226,9 +226,9 @@ export async function initAction(options: InitActionOptions, simulatorService: I
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
// Simulator ready
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
);
|
|
229
|
+
let successMessage = "GenLayer simulator initialized successfully! "
|
|
230
|
+
successMessage += options.headless ? '' : `Go to ${simulatorService.getFrontendUrl()} in your browser to access it.`;
|
|
231
|
+
console.log(successMessage);
|
|
232
232
|
try {
|
|
233
233
|
if(!options.headless){
|
|
234
234
|
await simulatorService.openFrontend();
|
|
@@ -98,9 +98,9 @@ export async function startAction(options: StartActionOptions, simulatorService:
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// Simulator ready
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
101
|
+
let successMessage = "GenLayer simulator initialized successfully! "
|
|
102
|
+
successMessage += headless ? '' : `Go to ${simulatorService.getFrontendUrl()} in your browser to access it.`;
|
|
103
|
+
console.log(successMessage);
|
|
104
104
|
try {
|
|
105
105
|
if(!headless) {
|
|
106
106
|
await simulatorService.openFrontend();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import util from "node:util";
|
|
2
|
-
import {ChildProcess,
|
|
2
|
+
import {ChildProcess, exec} from "child_process";
|
|
3
3
|
import open from "open";
|
|
4
4
|
|
|
5
5
|
import {RunningPlatform, AVAILABLE_PLATFORMS} from "../config/simulator";
|
|
@@ -68,47 +68,3 @@ export async function getVersion(toolName: string): Promise<string> {
|
|
|
68
68
|
|
|
69
69
|
return "";
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
export async function listDockerContainers(): Promise<string[]> {
|
|
73
|
-
try {
|
|
74
|
-
const dockerResponse = await util.promisify(exec)("docker ps -a --format '{{.Names}}'");
|
|
75
|
-
const dockerContainers = dockerResponse.stdout.split("\n");
|
|
76
|
-
return dockerContainers;
|
|
77
|
-
} catch (error) {
|
|
78
|
-
throw new Error("Error listing Docker containers.");
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export async function listDockerImages(): Promise<string[]> {
|
|
83
|
-
try {
|
|
84
|
-
const dockerResponse = await util.promisify(exec)("docker images --format '{{.Repository}}'");
|
|
85
|
-
const dockerImages = dockerResponse.stdout.split("\n");
|
|
86
|
-
return dockerImages;
|
|
87
|
-
} catch (error) {
|
|
88
|
-
throw new Error("Error listing Docker images.");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function stopDockerContainer(containerName: string): Promise<void> {
|
|
93
|
-
try {
|
|
94
|
-
await util.promisify(exec)(`docker stop ${containerName}`);
|
|
95
|
-
} catch (error) {
|
|
96
|
-
throw new Error(`Error stopping Docker container ${containerName}.`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export async function removeDockerContainer(containerName: string) {
|
|
101
|
-
try {
|
|
102
|
-
await util.promisify(exec)(`docker rm ${containerName}`);
|
|
103
|
-
} catch (error) {
|
|
104
|
-
throw new Error(`Error removing container ${containerName}.`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export async function removeDockerImage(imageName: string) {
|
|
109
|
-
try {
|
|
110
|
-
await util.promisify(exec)(`docker rmi ${imageName}`);
|
|
111
|
-
} catch (error) {
|
|
112
|
-
throw new Error(`Error removing image ${imageName}.`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
export const DEFAULT_JSON_RPC_URL = "http://localhost:4000/api";
|
|
2
2
|
export const DEFAULT_REPO_GH_URL = "https://github.com/yeagerai/genlayer-simulator.git";
|
|
3
|
-
export const DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX = "genlayer-simulator-";
|
|
3
|
+
export const DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX = "/genlayer-simulator-";
|
|
4
4
|
export const DEFAULT_RUN_SIMULATOR_COMMAND = (simulatorLocation: string, options: string) => ({
|
|
5
5
|
darwin: `osascript -e 'tell application "Terminal" to do script "cd ${simulatorLocation} && docker compose build && docker compose up ${options}"'`,
|
|
6
6
|
win32: `start cmd.exe /c "cd /d ${simulatorLocation} && docker compose build && docker compose up && pause ${options}"`,
|
|
7
7
|
linux: `nohup bash -c 'cd ${simulatorLocation} && docker compose build && docker compose up -d ${options}'`,
|
|
8
8
|
});
|
|
9
|
-
export const DEFAULT_PULL_OLLAMA_COMMAND = (simulatorLocation: string) => ({
|
|
10
|
-
darwin: `cd ${simulatorLocation} && docker exec ollama ollama pull llama3`,
|
|
11
|
-
win32: `cd /d ${simulatorLocation} && docker exec ollama ollama pull llama3`,
|
|
12
|
-
linux: `cd ${simulatorLocation} && docker exec ollama ollama pull llama3`,
|
|
13
|
-
});
|
|
14
9
|
export const DEFAULT_RUN_DOCKER_COMMAND = {
|
|
15
10
|
darwin: "open -a Docker",
|
|
16
11
|
win32: 'start "" "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe"',
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Docker from "dockerode"
|
|
1
2
|
import * as fs from "fs";
|
|
2
3
|
import * as dotenv from "dotenv";
|
|
3
4
|
import * as path from "path";
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX,
|
|
10
11
|
DEFAULT_RUN_SIMULATOR_COMMAND,
|
|
11
12
|
DEFAULT_RUN_DOCKER_COMMAND,
|
|
12
|
-
DEFAULT_PULL_OLLAMA_COMMAND,
|
|
13
13
|
STARTING_TIMEOUT_WAIT_CYLCE,
|
|
14
14
|
STARTING_TIMEOUT_ATTEMPTS,
|
|
15
15
|
AI_PROVIDERS_CONFIG,
|
|
@@ -21,11 +21,6 @@ import {
|
|
|
21
21
|
getVersion,
|
|
22
22
|
executeCommand,
|
|
23
23
|
openUrl,
|
|
24
|
-
listDockerContainers,
|
|
25
|
-
stopDockerContainer,
|
|
26
|
-
removeDockerContainer,
|
|
27
|
-
listDockerImages,
|
|
28
|
-
removeDockerImage,
|
|
29
24
|
} from "../clients/system";
|
|
30
25
|
import {MissingRequirementError} from "../errors/missingRequirement";
|
|
31
26
|
|
|
@@ -36,17 +31,20 @@ import {
|
|
|
36
31
|
} from "../interfaces/ISimulatorService";
|
|
37
32
|
import {VersionRequiredError} from "../errors/versionRequired";
|
|
38
33
|
|
|
34
|
+
|
|
39
35
|
function sleep(millliseconds: number): Promise<void> {
|
|
40
36
|
return new Promise(resolve => setTimeout(resolve, millliseconds));
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
export class SimulatorService implements ISimulatorService {
|
|
44
40
|
private composeOptions: string
|
|
41
|
+
private docker: Docker;
|
|
45
42
|
public simulatorLocation: string;
|
|
46
43
|
|
|
47
44
|
constructor() {
|
|
48
45
|
this.simulatorLocation = "";
|
|
49
46
|
this.composeOptions = "";
|
|
47
|
+
this.docker = new Docker();
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
public setSimulatorLocation(location: string): void {
|
|
@@ -122,7 +120,7 @@ export class SimulatorService implements ISimulatorService {
|
|
|
122
120
|
|
|
123
121
|
if (requirementsInstalled.docker) {
|
|
124
122
|
try {
|
|
125
|
-
await
|
|
123
|
+
await this.docker.ping()
|
|
126
124
|
} catch (error: any) {
|
|
127
125
|
await executeCommand(DEFAULT_RUN_DOCKER_COMMAND);
|
|
128
126
|
}
|
|
@@ -205,8 +203,10 @@ export class SimulatorService implements ISimulatorService {
|
|
|
205
203
|
}
|
|
206
204
|
|
|
207
205
|
public async pullOllamaModel(): Promise<boolean> {
|
|
208
|
-
const
|
|
209
|
-
await
|
|
206
|
+
const ollamaContainer = this.docker.getContainer("ollama");
|
|
207
|
+
await ollamaContainer.exec({
|
|
208
|
+
Cmd: ["ollama", "pull", "llama3"],
|
|
209
|
+
});
|
|
210
210
|
return true;
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -287,30 +287,33 @@ export class SimulatorService implements ISimulatorService {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
public async resetDockerContainers(): Promise<boolean> {
|
|
290
|
-
const containers = await
|
|
291
|
-
const genlayerContainers = containers.filter(
|
|
292
|
-
container.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
stopDockerContainer(container),
|
|
296
|
-
);
|
|
297
|
-
await Promise.all(containersStopPromises);
|
|
298
|
-
|
|
299
|
-
const containersRemovePromises = genlayerContainers.map((container: string) =>
|
|
300
|
-
removeDockerContainer(container),
|
|
290
|
+
const containers = await this.docker.listContainers({ all: true });
|
|
291
|
+
const genlayerContainers = containers.filter(container =>
|
|
292
|
+
container.Names.some(name =>
|
|
293
|
+
name.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX)
|
|
294
|
+
)
|
|
301
295
|
);
|
|
302
|
-
await Promise.all(containersRemovePromises);
|
|
303
296
|
|
|
297
|
+
for (const containerInfo of genlayerContainers) {
|
|
298
|
+
const container = this.docker.getContainer(containerInfo.Id);
|
|
299
|
+
if (containerInfo.State === "running") {
|
|
300
|
+
await container.stop();
|
|
301
|
+
}
|
|
302
|
+
await container.remove();
|
|
303
|
+
}
|
|
304
304
|
return true;
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
public async resetDockerImages(): Promise<boolean> {
|
|
308
|
-
const images = await
|
|
309
|
-
const genlayerImages = images.filter(
|
|
310
|
-
image.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX)
|
|
308
|
+
const images = await this.docker.listImages();
|
|
309
|
+
const genlayerImages = images.filter(image =>
|
|
310
|
+
image.RepoTags?.some(tag => tag.startsWith(DOCKER_IMAGES_AND_CONTAINERS_NAME_PREFIX))
|
|
311
311
|
);
|
|
312
|
-
|
|
313
|
-
|
|
312
|
+
|
|
313
|
+
for (const imageInfo of genlayerImages) {
|
|
314
|
+
const image = this.docker.getImage(imageInfo.Id);
|
|
315
|
+
await image.remove({force: true});
|
|
316
|
+
}
|
|
314
317
|
|
|
315
318
|
return true;
|
|
316
319
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {vi, describe, beforeEach, afterEach, test, expect} from "vitest";
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import simulatorService from "../../src/lib/services/simulator";
|
|
4
4
|
import { initAction } from "../../src/commands/general/init";
|
|
@@ -50,6 +50,15 @@ describe("init action", () => {
|
|
|
50
50
|
simServCreateRandomValidators = vi.spyOn(simulatorService, "createRandomValidators");
|
|
51
51
|
simServOpenFrontend = vi.spyOn(simulatorService, "openFrontend");
|
|
52
52
|
simGetSimulatorUrl = vi.spyOn(simulatorService, "getFrontendUrl")
|
|
53
|
+
|
|
54
|
+
simServCheckVersionRequirements.mockResolvedValue({
|
|
55
|
+
node: '',
|
|
56
|
+
docker: '',
|
|
57
|
+
});
|
|
58
|
+
simServCheckInstallRequirements.mockResolvedValue({
|
|
59
|
+
git: true,
|
|
60
|
+
docker: true,
|
|
61
|
+
})
|
|
53
62
|
});
|
|
54
63
|
|
|
55
64
|
afterEach(() => {
|
|
@@ -168,6 +177,8 @@ describe("init action", () => {
|
|
|
168
177
|
simServCreateRandomValidators.mockResolvedValue(true);
|
|
169
178
|
simServOpenFrontend.mockResolvedValue(true);
|
|
170
179
|
simGetSimulatorUrl.mockResolvedValue('http://localhost:8080/');
|
|
180
|
+
simServResetDockerContainers.mockResolvedValue(true);
|
|
181
|
+
simServResetDockerImages.mockResolvedValue(true);
|
|
171
182
|
|
|
172
183
|
await initAction(defaultActionOptions, simulatorService);
|
|
173
184
|
|
|
@@ -177,9 +188,68 @@ describe("init action", () => {
|
|
|
177
188
|
);
|
|
178
189
|
});
|
|
179
190
|
|
|
191
|
+
test("should open the frontend if everything went well (headless mode)", async () => {
|
|
192
|
+
inquirerPrompt.mockResolvedValue({
|
|
193
|
+
confirmReset: true,
|
|
194
|
+
confirmDownload: true,
|
|
195
|
+
selectedLlmProviders: ["openai", "heuristai"],
|
|
196
|
+
openai: "API_KEY1",
|
|
197
|
+
heuristai: "API_KEY2",
|
|
198
|
+
});
|
|
199
|
+
simServgetAiProvidersOptions.mockReturnValue([
|
|
200
|
+
{ name: "OpenAI", value: "openai" },
|
|
201
|
+
{ name: "Heurist", value: "heuristai" },
|
|
202
|
+
]);
|
|
203
|
+
simServConfigSimulator.mockResolvedValue(true);
|
|
204
|
+
simServRunSimulator.mockResolvedValue(true);
|
|
205
|
+
simServWaitForSimulator.mockResolvedValue({ initialized: true });
|
|
206
|
+
simServPullOllamaModel.mockResolvedValue(true);
|
|
207
|
+
simServDeleteAllValidators.mockResolvedValue(true);
|
|
208
|
+
simServCreateRandomValidators.mockResolvedValue(true);
|
|
209
|
+
simServOpenFrontend.mockResolvedValue(true);
|
|
210
|
+
simGetSimulatorUrl.mockResolvedValue('http://localhost:8080/');
|
|
211
|
+
simServResetDockerContainers.mockResolvedValue(true);
|
|
212
|
+
simServResetDockerImages.mockResolvedValue(true);
|
|
213
|
+
|
|
214
|
+
await initAction({...defaultActionOptions, headless: true}, simulatorService);
|
|
215
|
+
|
|
216
|
+
expect(log).toHaveBeenCalledWith(
|
|
217
|
+
`GenLayer simulator initialized successfully! `
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("should throw an error if validator are not initialized", async () => {
|
|
222
|
+
inquirerPrompt.mockResolvedValue({
|
|
223
|
+
confirmReset: true,
|
|
224
|
+
confirmDownload: true,
|
|
225
|
+
selectedLlmProviders: ["openai", "heuristai"],
|
|
226
|
+
openai: "API_KEY1",
|
|
227
|
+
heuristai: "API_KEY2",
|
|
228
|
+
});
|
|
229
|
+
simServgetAiProvidersOptions.mockReturnValue([
|
|
230
|
+
{ name: "OpenAI", value: "openai" },
|
|
231
|
+
{ name: "Heurist", value: "heuristai" },
|
|
232
|
+
]);
|
|
233
|
+
simServConfigSimulator.mockResolvedValue(true);
|
|
234
|
+
simServRunSimulator.mockResolvedValue(true);
|
|
235
|
+
simServWaitForSimulator.mockResolvedValue({ initialized: true });
|
|
236
|
+
simServPullOllamaModel.mockResolvedValue(true);
|
|
237
|
+
simServDeleteAllValidators.mockResolvedValue(true);
|
|
238
|
+
simServCreateRandomValidators.mockRejectedValue();
|
|
239
|
+
simServOpenFrontend.mockResolvedValue(true);
|
|
240
|
+
|
|
241
|
+
await initAction({...defaultActionOptions, headless: true}, simulatorService);
|
|
242
|
+
|
|
243
|
+
expect(log).toHaveBeenCalledWith('Initializing validators...');
|
|
244
|
+
expect(error).toHaveBeenCalledWith('Unable to initialize the validators.');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
|
|
180
248
|
test("if configSimulator fails, then the execution aborts", async () => {
|
|
181
249
|
inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true, selectedLlmProviders: [] });
|
|
182
250
|
simServConfigSimulator.mockRejectedValue(new Error("Error"));
|
|
251
|
+
simServResetDockerContainers.mockResolvedValue(true);
|
|
252
|
+
simServResetDockerImages.mockResolvedValue(true);
|
|
183
253
|
|
|
184
254
|
await initAction(defaultActionOptions, simulatorService);
|
|
185
255
|
|
|
@@ -189,6 +259,8 @@ describe("init action", () => {
|
|
|
189
259
|
test("if runSimulator fails, then the execution aborts", async () => {
|
|
190
260
|
inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true, selectedLlmProviders: [] });
|
|
191
261
|
simServRunSimulator.mockRejectedValue(new Error("Error"));
|
|
262
|
+
simServResetDockerContainers.mockResolvedValue(true);
|
|
263
|
+
simServResetDockerImages.mockResolvedValue(true);
|
|
192
264
|
|
|
193
265
|
await initAction(defaultActionOptions, simulatorService);
|
|
194
266
|
|
|
@@ -214,6 +286,8 @@ describe("init action", () => {
|
|
|
214
286
|
simServWaitForSimulator.mockResolvedValue({ initialized: true });
|
|
215
287
|
simServPullOllamaModel.mockResolvedValue(true);
|
|
216
288
|
simServDeleteAllValidators.mockResolvedValue(true);
|
|
289
|
+
simServResetDockerContainers.mockResolvedValue(true);
|
|
290
|
+
simServResetDockerImages.mockResolvedValue(true);
|
|
217
291
|
|
|
218
292
|
await initAction(defaultActionOptions, simulatorService);
|
|
219
293
|
|
|
@@ -59,6 +59,20 @@ describe("startAction - Additional Tests", () => {
|
|
|
59
59
|
expect(simulatorService.openFrontend).toHaveBeenCalled();
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
test("runs successfully with default options and keeps existing validators (headless)", async () => {
|
|
63
|
+
await startAction({...defaultOptions, headless: true}, simulatorService);
|
|
64
|
+
|
|
65
|
+
expect(simulatorService.updateSimulator).toHaveBeenCalledWith("main");
|
|
66
|
+
expect(simulatorService.runSimulator).toHaveBeenCalled();
|
|
67
|
+
expect(simulatorService.waitForSimulatorToBeReady).toHaveBeenCalled();
|
|
68
|
+
|
|
69
|
+
expect(logSpy).toHaveBeenCalledWith("Starting GenLayer simulator keeping the existing validators");
|
|
70
|
+
expect(logSpy).toHaveBeenCalledWith("Updating GenLayer Simulator...");
|
|
71
|
+
expect(logSpy).toHaveBeenCalledWith("Running the GenLayer Simulator...");
|
|
72
|
+
expect(logSpy).toHaveBeenCalledWith("Simulator is running!");
|
|
73
|
+
expect(logSpy).toHaveBeenCalledWith("GenLayer simulator initialized successfully! ");
|
|
74
|
+
});
|
|
75
|
+
|
|
62
76
|
test("logs error and stops if updateSimulator fails", async () => {
|
|
63
77
|
const errorMsg = new Error("updateSimulator error");
|
|
64
78
|
(simulatorService.updateSimulator as Mock).mockRejectedValueOnce(errorMsg);
|
|
@@ -4,12 +4,7 @@ import {
|
|
|
4
4
|
checkCommand,
|
|
5
5
|
executeCommand,
|
|
6
6
|
openUrl,
|
|
7
|
-
getVersion
|
|
8
|
-
listDockerContainers,
|
|
9
|
-
listDockerImages,
|
|
10
|
-
stopDockerContainer,
|
|
11
|
-
removeDockerContainer,
|
|
12
|
-
removeDockerImage
|
|
7
|
+
getVersion
|
|
13
8
|
} from "../../src/lib/clients/system";
|
|
14
9
|
import { MissingRequirementError } from "../../src/lib/errors/missingRequirement";
|
|
15
10
|
import open from "open";
|
|
@@ -59,48 +54,6 @@ describe("System Functions - Success Paths", () => {
|
|
|
59
54
|
expect(result.stdout).toBe("echo linux");
|
|
60
55
|
platformSpy.mockRestore();
|
|
61
56
|
});
|
|
62
|
-
|
|
63
|
-
test("listDockerContainers retrieves a list of containers", async () => {
|
|
64
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.resolve({
|
|
65
|
-
stdout: "container1\ncontainer2",
|
|
66
|
-
stderr: ""
|
|
67
|
-
}));
|
|
68
|
-
const containers = await listDockerContainers();
|
|
69
|
-
expect(containers).toEqual(["container1", "container2"]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("listDockerImages retrieves a list of images", async () => {
|
|
73
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.resolve({
|
|
74
|
-
stdout: "image1\nimage2",
|
|
75
|
-
stderr: ""
|
|
76
|
-
}));
|
|
77
|
-
const images = await listDockerImages();
|
|
78
|
-
expect(images).toEqual(["image1", "image2"]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("stopDockerContainer stops a container", async () => {
|
|
82
|
-
const containerId = "container123";
|
|
83
|
-
const execMock = vi.fn().mockResolvedValue({ stdout: "", stderr: "" });
|
|
84
|
-
vi.mocked(util.promisify).mockReturnValue(execMock);
|
|
85
|
-
await stopDockerContainer(containerId);
|
|
86
|
-
expect(execMock).toHaveBeenCalledWith(`docker stop ${containerId}`);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test("removeDockerContainer removes a container", async () => {
|
|
90
|
-
const containerId = "container123";
|
|
91
|
-
const execMock = vi.fn().mockResolvedValue({ stdout: "", stderr: "" });
|
|
92
|
-
vi.mocked(util.promisify).mockReturnValue(execMock);
|
|
93
|
-
await removeDockerContainer(containerId);
|
|
94
|
-
expect(execMock).toHaveBeenCalledWith(`docker rm ${containerId}`);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("removeDockerImage removes an image", async () => {
|
|
98
|
-
const imageId = "image123";
|
|
99
|
-
const execMock = vi.fn().mockResolvedValue({ stdout: "", stderr: "" });
|
|
100
|
-
vi.mocked(util.promisify).mockReturnValue(execMock);
|
|
101
|
-
await removeDockerImage(imageId);
|
|
102
|
-
expect(execMock).toHaveBeenCalledWith(`docker rmi ${imageId}`);
|
|
103
|
-
});
|
|
104
57
|
});
|
|
105
58
|
|
|
106
59
|
describe("System Functions - Error Paths", () => {
|
|
@@ -153,34 +106,6 @@ describe("System Functions - Error Paths", () => {
|
|
|
153
106
|
"echo")).rejects.toThrow("Execution failed");
|
|
154
107
|
});
|
|
155
108
|
|
|
156
|
-
test("stopDockerContainer throws an error if stopping fails", async () => {
|
|
157
|
-
const containerId = "container123";
|
|
158
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("")));
|
|
159
|
-
await expect(stopDockerContainer(containerId)).rejects.toThrow("Error stopping Docker container container123");
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test("removeDockerContainer throws an error if removal fails", async () => {
|
|
163
|
-
const containerId = "container123";
|
|
164
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("")));
|
|
165
|
-
await expect(removeDockerContainer(containerId)).rejects.toThrow("Error removing container container123.");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("removeDockerImage throws an error if image removal fails", async () => {
|
|
169
|
-
const imageId = "image123";
|
|
170
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("")));
|
|
171
|
-
await expect(removeDockerImage(imageId)).rejects.toThrow("Error removing image image123.");
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test("throws error when command fails", async () => {
|
|
175
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("")));
|
|
176
|
-
await expect(listDockerContainers()).rejects.toThrow("Error listing Docker containers.");
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("throws error when command fails", async () => {
|
|
180
|
-
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("")));
|
|
181
|
-
await expect(listDockerImages()).rejects.toThrow("Error listing Docker images.");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
109
|
test("throws error when command execution fails", async () => {
|
|
185
110
|
vi.mocked(util.promisify).mockReturnValueOnce(() => Promise.reject(new Error("Execution error.")));
|
|
186
111
|
await expect(executeCommand({
|