genlayer 0.12.1 → 0.12.2-beta.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.
Files changed (44) hide show
  1. package/.github/workflows/publish-beta.yml +2 -2
  2. package/.github/workflows/publish.yml +2 -2
  3. package/.github/workflows/validate-code.yml +1 -1
  4. package/CHANGELOG.md +6 -0
  5. package/dist/index.js +24736 -108331
  6. package/docker-compose.yml +1 -1
  7. package/esbuild.config.dev.js +18 -0
  8. package/esbuild.config.js +10 -5
  9. package/esbuild.config.prod.js +16 -0
  10. package/eslint.config.js +59 -0
  11. package/package.json +12 -9
  12. package/scripts/postinstall.js +10 -6
  13. package/src/commands/config/getSetReset.ts +25 -18
  14. package/src/commands/contracts/deploy.ts +105 -25
  15. package/src/commands/contracts/index.ts +5 -1
  16. package/src/commands/general/index.ts +10 -4
  17. package/src/commands/general/init.ts +136 -189
  18. package/src/commands/general/start.ts +76 -77
  19. package/src/commands/general/stop.ts +6 -5
  20. package/src/commands/keygen/create.ts +9 -11
  21. package/src/commands/update/index.ts +3 -8
  22. package/src/commands/update/ollama.ts +56 -56
  23. package/src/commands/validators/validators.ts +48 -55
  24. package/src/lib/actions/BaseAction.ts +75 -4
  25. package/src/lib/config/simulator.ts +1 -1
  26. package/src/lib/services/simulator.ts +3 -2
  27. package/tests/actions/create.test.ts +18 -30
  28. package/tests/actions/deploy.test.ts +200 -30
  29. package/tests/actions/getSetReset.test.ts +29 -42
  30. package/tests/actions/init.test.ts +240 -475
  31. package/tests/actions/ollama.test.ts +40 -55
  32. package/tests/actions/start.test.ts +107 -108
  33. package/tests/actions/stop.test.ts +23 -4
  34. package/tests/actions/validators.test.ts +273 -142
  35. package/tests/commands/call.test.ts +4 -1
  36. package/tests/commands/deploy.test.ts +11 -0
  37. package/tests/commands/init.test.ts +11 -12
  38. package/tests/commands/up.test.ts +31 -23
  39. package/tests/commands/update.test.ts +2 -5
  40. package/tests/libs/baseAction.test.ts +175 -0
  41. package/tests/services/simulator.test.ts +15 -0
  42. package/.eslintrc.js +0 -58
  43. package/esbuild.config.dev +0 -16
  44. package/esbuild.config.prod +0 -16
@@ -1,523 +1,288 @@
1
- import {vi, describe, beforeEach, afterEach, test, expect} from "vitest";
1
+ import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
2
2
  import inquirer from "inquirer";
3
- import simulatorService from "../../src/lib/services/simulator";
4
- import { initAction } from "../../src/commands/general/init";
5
- import { tmpdir } from "os";
6
- import {mkdtempSync} from "fs";
7
- import {join} from "path";
8
- import fs from "fs";
9
- import * as dotenv from "dotenv";
10
- import {localnetCompatibleVersion} from "../../src/lib/config/simulator";
3
+ import { InitAction, InitActionOptions } from "../../src/commands/general/init";
4
+ import { SimulatorService } from "../../src/lib/services/simulator";
11
5
  import { OllamaAction } from "../../src/commands/update/ollama";
12
- import { ConfigFileManager } from "../../src/lib/config/ConfigFileManager";
13
6
 
14
-
15
- vi.mock("fs");
16
- vi.mock("dotenv");
17
- vi.mock("../../src/commands/update/ollama")
18
- vi.mock("../../src/lib/config/ConfigFileManager");
19
-
20
-
21
- const tempDir = mkdtempSync(join(tmpdir(), "test-initAction-"));
22
- const defaultActionOptions = { numValidators: 5, branch: "main", location: tempDir, headless: false, resetDb: false, localnetVersion: localnetCompatibleVersion };
23
-
24
- describe("init action", () => {
25
- let error: ReturnType<any>;
26
- let log: ReturnType<any>;
27
- let inquirerPrompt: ReturnType<any>;
28
-
29
- let simServCheckInstallRequirements: ReturnType<any>;
30
- let simServCheckVersionRequirements: ReturnType<any>;
31
- let simServResetDockerContainers: ReturnType<any>;
32
- let simServResetDockerImages: ReturnType<any>;
33
- let simServgetAiProvidersOptions: ReturnType<any>;
34
- let simServRunSimulator: ReturnType<any>;
35
- let simServWaitForSimulator: ReturnType<any>;
36
- let simServDeleteAllValidators: ReturnType<any>;
37
- let simServCreateRandomValidators: ReturnType<any>;
38
- let simServOpenFrontend: ReturnType<any>;
39
- let simGetSimulatorUrl: ReturnType<any>;
40
- let simAddConfigToEnvFile: ReturnType<any>;
7
+ describe("InitAction", () => {
8
+ let initAction: InitAction;
9
+ let inquirerPromptSpy: ReturnType<any>;
10
+ let checkCliVersionSpy: ReturnType<typeof vi.spyOn>;
11
+ let checkInstallRequirementsSpy: ReturnType<typeof vi.spyOn>;
12
+ let checkVersionRequirementsSpy: ReturnType<typeof vi.spyOn>;
13
+ let resetDockerContainersSpy: ReturnType<typeof vi.spyOn>;
14
+ let resetDockerImagesSpy: ReturnType<typeof vi.spyOn>;
15
+ let addConfigToEnvFileSpy: ReturnType<typeof vi.spyOn>;
16
+ let runSimulatorSpy: ReturnType<typeof vi.spyOn>;
17
+ let waitForSimulatorSpy: ReturnType<typeof vi.spyOn>;
18
+ let deleteAllValidatorsSpy: ReturnType<typeof vi.spyOn>;
19
+ let createRandomValidatorsSpy: ReturnType<typeof vi.spyOn>;
20
+ let cleanDatabaseSpy: ReturnType<typeof vi.spyOn>;
21
+ let openFrontendSpy: ReturnType<typeof vi.spyOn>;
22
+ let getFrontendUrlSpy: ReturnType<typeof vi.spyOn>;
23
+ let normalizeLocalnetVersionSpy: ReturnType<typeof vi.spyOn>;
24
+
25
+ const defaultConfig = { defaultOllamaModel: "llama3" };
26
+
27
+ const defaultOptions: InitActionOptions = {
28
+ numValidators: 5,
29
+ headless: false,
30
+ resetDb: false,
31
+ localnetVersion: "v1.0.0",
32
+ };
41
33
 
42
34
  beforeEach(() => {
43
35
  vi.clearAllMocks();
44
-
45
- error = vi.spyOn(console, "error").mockImplementation(() => {});
46
- log = vi.spyOn(console, "log").mockImplementation(() => {});
47
- inquirerPrompt = vi.spyOn(inquirer, "prompt");
48
-
49
- simServCheckInstallRequirements = vi.spyOn(simulatorService, "checkInstallRequirements");
50
- simServCheckVersionRequirements = vi.spyOn(simulatorService, "checkVersionRequirements");
51
- simServResetDockerContainers = vi.spyOn(simulatorService, "resetDockerContainers");
52
- simServResetDockerImages = vi.spyOn(simulatorService, "resetDockerImages");
53
- simServgetAiProvidersOptions = vi.spyOn(simulatorService, "getAiProvidersOptions");
54
- simServRunSimulator = vi.spyOn(simulatorService, "runSimulator");
55
- simServWaitForSimulator = vi.spyOn(simulatorService, "waitForSimulatorToBeReady");
56
- simServDeleteAllValidators = vi.spyOn(simulatorService, "deleteAllValidators");
57
- simServCreateRandomValidators = vi.spyOn(simulatorService, "createRandomValidators");
58
- simServOpenFrontend = vi.spyOn(simulatorService, "openFrontend");
59
- simGetSimulatorUrl = vi.spyOn(simulatorService, "getFrontendUrl")
60
- simAddConfigToEnvFile = vi.spyOn(simulatorService, "addConfigToEnvFile")
61
-
62
- simServCheckVersionRequirements.mockResolvedValue({
63
- node: '',
64
- docker: '',
65
- });
66
- simServCheckInstallRequirements.mockResolvedValue({
67
- git: true,
68
- docker: true,
69
- })
70
- simAddConfigToEnvFile.mockResolvedValue(true);
71
- const mockEnvContent = "FRONTEND_PORT=8080";
72
- const mockEnvConfig = { FRONTEND_PORT: "8080" };
73
- vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
74
- vi.mocked(dotenv.parse).mockReturnValue(mockEnvConfig);
36
+ initAction = new InitAction();
37
+ inquirerPromptSpy = vi.spyOn(inquirer, "prompt");
38
+ vi.spyOn(initAction as any, "startSpinner").mockImplementation(() => {});
39
+ vi.spyOn(initAction as any, "setSpinnerText").mockImplementation(() => {});
40
+ vi.spyOn(initAction as any, "succeedSpinner").mockImplementation(() => {});
41
+ vi.spyOn(initAction as any, "failSpinner").mockImplementation(() => {});
42
+ vi.spyOn(initAction as any, "stopSpinner").mockImplementation(() => {});
43
+ vi.spyOn(initAction as any, "logError").mockImplementation(() => {});
44
+ vi.spyOn(initAction, "getConfig").mockReturnValue(defaultConfig);
45
+ checkCliVersionSpy = vi.spyOn(SimulatorService.prototype, "checkCliVersion").mockResolvedValue(undefined);
46
+ checkInstallRequirementsSpy = vi.spyOn(SimulatorService.prototype, "checkInstallRequirements").mockResolvedValue({ git: true, docker: true });
47
+ checkVersionRequirementsSpy = vi.spyOn(SimulatorService.prototype, "checkVersionRequirements").mockResolvedValue({ node: "", docker: "" });
48
+ resetDockerContainersSpy = vi.spyOn(SimulatorService.prototype, "resetDockerContainers").mockResolvedValue(undefined);
49
+ resetDockerImagesSpy = vi.spyOn(SimulatorService.prototype, "resetDockerImages").mockResolvedValue(undefined);
50
+ addConfigToEnvFileSpy = vi.spyOn(SimulatorService.prototype, "addConfigToEnvFile").mockResolvedValue();
51
+ runSimulatorSpy = vi.spyOn(SimulatorService.prototype, "runSimulator").mockResolvedValue(undefined as any);
52
+ waitForSimulatorSpy = vi.spyOn(SimulatorService.prototype, "waitForSimulatorToBeReady").mockResolvedValue({ initialized: true }) as any;
53
+ deleteAllValidatorsSpy = vi.spyOn(SimulatorService.prototype, "deleteAllValidators").mockResolvedValue(undefined);
54
+ createRandomValidatorsSpy = vi.spyOn(SimulatorService.prototype, "createRandomValidators").mockResolvedValue(undefined) as any;
55
+ cleanDatabaseSpy = vi.spyOn(SimulatorService.prototype, "cleanDatabase").mockResolvedValue(true);
56
+ openFrontendSpy = vi.spyOn(SimulatorService.prototype, "openFrontend").mockResolvedValue(true);
57
+ getFrontendUrlSpy = vi.spyOn(SimulatorService.prototype, "getFrontendUrl").mockReturnValue("http://localhost:8080");
58
+ normalizeLocalnetVersionSpy = vi.spyOn(SimulatorService.prototype, "normalizeLocalnetVersion").mockImplementation((v: string) => v) as any;
75
59
  });
76
60
 
77
61
  afterEach(() => {
78
62
  vi.restoreAllMocks();
79
63
  });
80
64
 
81
- test("if only docker is missing, then the execution fails", async () => {
82
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: false });
83
-
84
- await initAction(defaultActionOptions, simulatorService);
85
-
86
- expect(error).toHaveBeenCalledWith("Docker is not installed. Please install Docker and try again.\n");
87
- });
88
-
89
- test("if check install requirements fail, then the execution aborts", async () => {
90
- simServCheckInstallRequirements.mockRejectedValue(new Error("Error"));
91
-
92
- await initAction(defaultActionOptions, simulatorService);
93
-
94
- expect(error).toHaveBeenCalledWith(new Error("Error"));
95
- });
96
-
97
- test("if both versions are too low, then the execution fails", async () => {
98
- const mockVersionNumber = "99.9.9";
99
- simServCheckVersionRequirements.mockResolvedValue({
100
- node: mockVersionNumber,
101
- docker: mockVersionNumber,
65
+ describe("Successful Execution", () => {
66
+ test("executes the full flow in non-headless mode", async () => {
67
+ inquirerPromptSpy
68
+ .mockResolvedValueOnce({ confirmAction: true })
69
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai", "heuristai"] })
70
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" })
71
+ .mockResolvedValueOnce({ heuristai: "API_KEY_HEURIST" });
72
+ await initAction.execute(defaultOptions);
73
+ expect(checkCliVersionSpy).toHaveBeenCalled();
74
+ expect(checkInstallRequirementsSpy).toHaveBeenCalled();
75
+ expect(checkVersionRequirementsSpy).toHaveBeenCalled();
76
+ expect(resetDockerContainersSpy).toHaveBeenCalled();
77
+ expect(resetDockerImagesSpy).toHaveBeenCalled();
78
+ expect(addConfigToEnvFileSpy).toHaveBeenCalledWith({ OPENAIKEY: "API_KEY_OPENAI", HEURISTAIAPIKEY: "API_KEY_HEURIST" });
79
+ expect(addConfigToEnvFileSpy).toHaveBeenCalledWith({ LOCALNETVERSION: "v1.0.0" });
80
+ expect(runSimulatorSpy).toHaveBeenCalled();
81
+ expect(waitForSimulatorSpy).toHaveBeenCalled();
82
+ expect(deleteAllValidatorsSpy).toHaveBeenCalled();
83
+ expect(createRandomValidatorsSpy).toHaveBeenCalledWith(5, ["openai", "heuristai"]);
84
+ expect(getFrontendUrlSpy).toHaveBeenCalled();
85
+ expect(openFrontendSpy).toHaveBeenCalled();
86
+ expect((initAction as any).succeedSpinner).toHaveBeenCalledWith("GenLayer Localnet initialized successfully! Go to http://localhost:8080 in your browser to access it.");
102
87
  });
103
88
 
104
- await initAction(defaultActionOptions, simulatorService);
105
-
106
- expect(error).toHaveBeenCalledWith(
107
- `Docker version ${mockVersionNumber} or higher is required. Please update Docker and try again.\nNode version ${mockVersionNumber} or higher is required. Please update Node and try again.\n`
108
- );
109
- });
110
-
111
- test("if only docker version is too low, then the execution fails", async () => {
112
- const mockVersionNumber = "99.9.9";
113
- simServCheckVersionRequirements.mockResolvedValue({
114
- docker: mockVersionNumber,
89
+ test("executes correctly in headless mode with DB reset and 'ollama' selected", async () => {
90
+ inquirerPromptSpy
91
+ .mockResolvedValueOnce({ confirmAction: true })
92
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai", "ollama"] })
93
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
94
+ const ollamaUpdateSpy = vi.spyOn(OllamaAction.prototype, "updateModel").mockResolvedValue(undefined);
95
+ const headlessOptions: InitActionOptions = {
96
+ numValidators: 5,
97
+ headless: true,
98
+ resetDb: true,
99
+ localnetVersion: "v1.0.0",
100
+ };
101
+ await initAction.execute(headlessOptions);
102
+ expect(cleanDatabaseSpy).toHaveBeenCalled();
103
+ expect(openFrontendSpy).not.toHaveBeenCalled();
104
+ expect((initAction as any).succeedSpinner).toHaveBeenCalledWith("GenLayer Localnet initialized successfully! ");
105
+ expect(ollamaUpdateSpy).toHaveBeenCalledWith("llama3");
115
106
  });
116
107
 
117
- await initAction(defaultActionOptions, simulatorService);
118
-
119
- expect(error).toHaveBeenCalledWith(
120
- `Docker version ${mockVersionNumber} or higher is required. Please update Docker and try again.\n`
121
- );
122
- });
123
-
124
- test("if only node version is too low, then the execution fails", async () => {
125
- const mockVersionNumber = "99.9.9";
126
- simServCheckVersionRequirements.mockResolvedValue({
127
- node: mockVersionNumber
108
+ test("normalizes localnetVersion if not 'latest'", async () => {
109
+ const customVersion = "custom-v1";
110
+ normalizeLocalnetVersionSpy.mockReturnValue(customVersion);
111
+ inquirerPromptSpy
112
+ .mockResolvedValueOnce({ confirmAction: true })
113
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
114
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
115
+ await initAction.execute({ ...defaultOptions, localnetVersion: customVersion });
116
+ expect(normalizeLocalnetVersionSpy).toHaveBeenCalledWith(customVersion);
117
+ expect(addConfigToEnvFileSpy).toHaveBeenCalledWith({ LOCALNETVERSION: customVersion });
128
118
  });
129
119
 
130
- await initAction(defaultActionOptions, simulatorService);
131
-
132
- expect(error).toHaveBeenCalledWith(
133
- `Node version ${mockVersionNumber} or higher is required. Please update Node and try again.\n`
134
- );
135
- });
136
-
137
- test("if reset is not confirmed, abort", async () => {
138
- inquirerPrompt.mockResolvedValue({ confirmReset: false });
139
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
140
-
141
- await initAction(defaultActionOptions, simulatorService);
142
-
143
- expect(log).toHaveBeenCalledWith("Aborted!");
144
- });
145
-
146
- test("if resetDockerContainers fail, then the execution aborts", async () => {
147
- inquirerPrompt.mockResolvedValue({ confirmReset: true });
148
- simServResetDockerContainers.mockRejectedValue(new Error("Error"));
149
-
150
- await initAction(defaultActionOptions, simulatorService);
151
-
152
- expect(error).toHaveBeenCalledWith(new Error("Error"));
153
- });
154
-
155
- test("should open the frontend if everything went well", async () => {
156
- inquirerPrompt.mockResolvedValue({
157
- confirmReset: true,
158
- confirmDownload: true,
159
- selectedLlmProviders: ["openai", "heuristai"],
160
- openai: "API_KEY1",
161
- heuristai: "API_KEY2",
120
+ test("should set defaultOllamaModel to 'llama3' if not provided in config", async () => {
121
+ vi.spyOn(initAction, "getConfig").mockReturnValue({});
122
+ const writeConfigSpy = vi.spyOn(initAction, "writeConfig").mockImplementation(() => {});
123
+ const ollamaUpdateSpy = vi.spyOn(OllamaAction.prototype, "updateModel").mockResolvedValue(undefined);
124
+ inquirerPromptSpy
125
+ .mockResolvedValueOnce({ confirmAction: true })
126
+ .mockResolvedValueOnce({ selectedLlmProviders: ["ollama"] })
127
+ .mockResolvedValueOnce({ ollama: "API_KEY_OLLAMA" });
128
+ await initAction.execute(defaultOptions);
129
+ expect(writeConfigSpy).toHaveBeenCalledWith("defaultOllamaModel", "llama3");
130
+ expect(ollamaUpdateSpy).toHaveBeenCalledWith("llama3");
162
131
  });
163
- simServgetAiProvidersOptions.mockReturnValue([
164
- { name: "OpenAI", value: "openai" },
165
- { name: "Heurist", value: "heuristai" },
166
- ]);
167
-
168
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
169
-
170
- simServRunSimulator.mockResolvedValue(true);
171
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
172
- simServDeleteAllValidators.mockResolvedValue(true);
173
- simServCreateRandomValidators.mockResolvedValue(true);
174
- simServOpenFrontend.mockResolvedValue(true);
175
- simGetSimulatorUrl.mockResolvedValue('http://localhost:8080/');
176
- simServResetDockerContainers.mockResolvedValue(true);
177
- simServResetDockerImages.mockResolvedValue(true);
178
132
 
179
- await initAction(defaultActionOptions, simulatorService);
180
-
181
- const frontendUrl = simulatorService.getFrontendUrl();
182
- expect(log).toHaveBeenCalledWith(
183
- `GenLayer simulator initialized successfully! Go to ${frontendUrl} in your browser to access it.`
184
- );
185
- });
186
-
187
- test("should open the frontend if everything went well (custom options)", async () => {
188
- inquirerPrompt.mockResolvedValue({
189
- confirmReset: true,
190
- confirmDownload: true,
191
- selectedLlmProviders: ["openai", "heuristai"],
192
- openai: "API_KEY1",
193
- heuristai: "API_KEY2",
133
+ test("validates API key input for configurable provider", async () => {
134
+ inquirerPromptSpy.mockResolvedValueOnce({ confirmAction: true });
135
+ inquirerPromptSpy.mockResolvedValueOnce({ selectedLlmProviders: ["openai"] });
136
+ let capturedQuestion: any;
137
+ inquirerPromptSpy.mockImplementationOnce((questions: any) => {
138
+ capturedQuestion = questions[0];
139
+ return Promise.resolve({ openai: "dummy-key" });
140
+ });
141
+ await initAction.execute(defaultOptions);
142
+ expect(capturedQuestion).toBeDefined();
143
+ const expectedError = `Please enter a valid API Key for OpenAI.`;
144
+ expect(capturedQuestion.validate("")).toBe(expectedError);
145
+ expect(capturedQuestion.validate("non-empty-key")).toBe(true);
194
146
  });
195
- simServgetAiProvidersOptions.mockReturnValue([
196
- { name: "OpenAI", value: "openai" },
197
- { name: "Heurist", value: "heuristai" },
198
- ]);
199
-
200
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
201
-
202
- simServRunSimulator.mockResolvedValue(true);
203
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
204
- simServDeleteAllValidators.mockResolvedValue(true);
205
- simServCreateRandomValidators.mockResolvedValue(true);
206
- simServOpenFrontend.mockResolvedValue(true);
207
- simGetSimulatorUrl.mockResolvedValue('http://localhost:8080/');
208
- simServResetDockerContainers.mockResolvedValue(true);
209
- simServResetDockerImages.mockResolvedValue(true);
210
-
211
- await initAction({...defaultActionOptions, headless: true, resetDb: true, localnetVersion: "v1.0.0"}, simulatorService);
212
147
 
213
- expect(log).toHaveBeenCalledWith(
214
- `GenLayer simulator initialized successfully! `
215
- );
216
- });
217
-
218
- test("should throw an error if validator are not initialized", async () => {
219
- inquirerPrompt.mockResolvedValue({
220
- confirmReset: true,
221
- confirmDownload: true,
222
- selectedLlmProviders: ["openai", "heuristai"],
223
- openai: "API_KEY1",
224
- heuristai: "API_KEY2",
148
+ test("validates LLM provider selection prompt", async () => {
149
+ let capturedQuestion: any;
150
+ inquirerPromptSpy
151
+ .mockResolvedValueOnce({ confirmAction: true })
152
+ .mockImplementationOnce((questions: any) => {
153
+ capturedQuestion = questions[0];
154
+ return Promise.resolve({ selectedLlmProviders: ["openai"] });
155
+ })
156
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
157
+ await initAction.execute(defaultOptions);
158
+ expect(capturedQuestion.validate([])).toBe("You must choose at least one option.");
159
+ expect(capturedQuestion.validate(["openai"])).toBe(true);
225
160
  });
226
- simServgetAiProvidersOptions.mockReturnValue([
227
- { name: "OpenAI", value: "openai" },
228
- { name: "Heurist", value: "heuristai" },
229
- ]);
230
-
231
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
232
-
233
- simServRunSimulator.mockResolvedValue(true);
234
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
235
- simServDeleteAllValidators.mockResolvedValue(true);
236
- simServResetDockerContainers.mockResolvedValue(true);
237
- simServResetDockerImages.mockResolvedValue(true);
238
- simServCreateRandomValidators.mockRejectedValue();
239
- simServOpenFrontend.mockResolvedValue(true);
240
- simServResetDockerContainers.mockResolvedValue(true);
241
- simServResetDockerImages.mockResolvedValue(true);
242
-
243
- await initAction({...defaultActionOptions, headless: true}, simulatorService);
244
-
245
- expect(log).toHaveBeenCalledWith('Initializing validators...');
246
- expect(error).toHaveBeenCalledWith('Unable to initialize the validators.');
247
161
  });
248
162
 
249
- test("if runSimulator fails, then the execution aborts", async () => {
250
- inquirerPrompt.mockResolvedValue({ confirmReset: true, confirmDownload: true, selectedLlmProviders: [] });
251
- simServRunSimulator.mockRejectedValue(new Error("Error"));
252
- simServResetDockerContainers.mockResolvedValue(true);
253
- simServResetDockerImages.mockResolvedValue(true);
254
-
255
- await initAction(defaultActionOptions, simulatorService);
256
-
257
- expect(error).toHaveBeenCalledWith(new Error("Error"));
258
- });
259
-
260
- test("should pull Ollama model if 'ollama' is in providers", async () => {
261
-
262
- inquirerPrompt.mockResolvedValue({
263
- confirmReset: true,
264
- confirmDownload: true,
265
- selectedLlmProviders: ["openai", "heuristai", "ollama"],
266
- openai: "API_KEY1",
267
- heuristai: "API_KEY2",
268
- ollama: "API_KEY3",
163
+ describe("Error Handling", () => {
164
+ test("fails if Docker is not installed", async () => {
165
+ checkInstallRequirementsSpy.mockResolvedValue({ git: true, docker: false });
166
+ await initAction.execute(defaultOptions);
167
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("Docker is not installed. Please install Docker and try again.\n");
269
168
  });
270
- simServgetAiProvidersOptions.mockReturnValue([
271
- { name: "OpenAI", value: "openai" },
272
- { name: "Heurist", value: "heuristai" },
273
- { name: "Ollama", value: "ollama" },
274
- ]);
275
-
276
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
277
-
278
- simServRunSimulator.mockResolvedValue(true);
279
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
280
- simServDeleteAllValidators.mockResolvedValue(true);
281
- simServResetDockerContainers.mockResolvedValue(true);
282
- simServResetDockerImages.mockResolvedValue(true);
283
- vi.mocked(ConfigFileManager.prototype.getConfig).mockReturnValue({});
284
169
 
285
- await initAction(defaultActionOptions, simulatorService);
286
-
287
- expect(log).toHaveBeenCalledWith(`Pulling llama3 from Ollama...`);
288
- expect(OllamaAction.prototype.updateModel).toHaveBeenCalled();
289
- });
290
-
291
- test("should pull Ollama model if 'ollama' is in providers using defaultOllamaModel", async () => {
292
- const ollamaModel = "gemma";
293
-
294
- inquirerPrompt.mockResolvedValue({
295
- confirmReset: true,
296
- confirmDownload: true,
297
- selectedLlmProviders: ["openai", "heuristai", "ollama"],
298
- openai: "API_KEY1",
299
- heuristai: "API_KEY2",
300
- ollama: "API_KEY3",
170
+ test("fails if checkInstallRequirements throws an error", async () => {
171
+ const error = new Error("Install error");
172
+ checkInstallRequirementsSpy.mockRejectedValue(error);
173
+ await initAction.execute(defaultOptions);
174
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", error);
301
175
  });
302
- simServgetAiProvidersOptions.mockReturnValue([
303
- { name: "OpenAI", value: "openai" },
304
- { name: "Heurist", value: "heuristai" },
305
- { name: "Ollama", value: "ollama" },
306
- ]);
307
-
308
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
309
-
310
- simServRunSimulator.mockResolvedValue(true);
311
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
312
- simServDeleteAllValidators.mockResolvedValue(true);
313
- simServResetDockerContainers.mockResolvedValue(true);
314
- simServResetDockerImages.mockResolvedValue(true);
315
- vi.mocked(ConfigFileManager.prototype.getConfig).mockReturnValue({defaultOllamaModel: ollamaModel});
316
-
317
- await initAction(defaultActionOptions, simulatorService);
318
176
 
319
- expect(log).toHaveBeenCalledWith(`Pulling ${ollamaModel} from Ollama...`);
320
- expect(OllamaAction.prototype.updateModel).toHaveBeenCalled();
321
- });
322
-
323
- test("should set defaultOllamaModel to llama 3 if no defaultOllamaModel is provided", async () => {
324
-
325
- inquirerPrompt.mockResolvedValue({
326
- confirmReset: true,
327
- confirmDownload: true,
328
- selectedLlmProviders: ["openai", "heuristai", "ollama"],
329
- openai: "API_KEY1",
330
- heuristai: "API_KEY2",
331
- ollama: "API_KEY3",
177
+ test("fails if version requirements are not met (both docker and node)", async () => {
178
+ const version = "99.9.9";
179
+ checkVersionRequirementsSpy.mockResolvedValue({ docker: version, node: version });
180
+ await initAction.execute(defaultOptions);
181
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith(`Docker version ${version} or higher is required. Please update Docker and try again.\nNode version ${version} or higher is required. Please update Node and try again.\n`);
332
182
  });
333
- simServgetAiProvidersOptions.mockReturnValue([
334
- { name: "OpenAI", value: "openai" },
335
- { name: "Heurist", value: "heuristai" },
336
- { name: "Ollama", value: "ollama" },
337
- ]);
338
-
339
- vi.mocked(ConfigFileManager.prototype.getConfig).mockResolvedValueOnce({})
340
- vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
341
-
342
- simServRunSimulator.mockResolvedValue(true);
343
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
344
- simServDeleteAllValidators.mockResolvedValue(true);
345
- simServResetDockerContainers.mockResolvedValue(true);
346
- simServResetDockerImages.mockResolvedValue(true);
347
- vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({}));
348
-
349
- await initAction(defaultActionOptions, simulatorService);
350
-
351
- expect(ConfigFileManager.prototype.writeConfig).toHaveBeenCalledWith('defaultOllamaModel', 'llama3')
352
- expect(log).toHaveBeenCalledWith(`Pulling llama3 from Ollama...`);
353
- expect(OllamaAction.prototype.updateModel).toHaveBeenCalled();
354
- });
355
-
356
- test("logs error if checkVersionRequirements throws", async () => {
357
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
358
- const errorMsg = new Error("checkVersionRequirements error");
359
- simServCheckVersionRequirements.mockRejectedValueOnce(errorMsg);
360
-
361
- await initAction(defaultActionOptions, simulatorService);
362
-
363
- expect(error).toHaveBeenCalledWith(errorMsg);
364
- });
365
-
366
- test("logs error if resetDockerContainers throws", async () => {
367
- inquirerPrompt.mockResolvedValue({ confirmReset: true });
368
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
369
- const errorMsg = new Error("resetDockerContainers error");
370
- simServResetDockerContainers.mockRejectedValueOnce(errorMsg);
371
-
372
- await initAction(defaultActionOptions, simulatorService);
373
-
374
- expect(error).toHaveBeenCalledWith(errorMsg);
375
- });
376
-
377
- test("prompts for LLM providers and validates that at least one is selected", async () => {
378
- const mockEnvContent = "FRONTEND_PORT=8080";
379
- vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
380
-
381
- inquirerPrompt
382
- .mockResolvedValueOnce({ confirmReset: true })
383
- .mockImplementation((questions: any) => {
384
- if (questions[0].type === "checkbox") {
385
- const validateFunction = questions[0].validate;
386
- expect(validateFunction([])).toBe("You must choose at least one option.");
387
- expect(validateFunction(["openai"])).toBe(true);
388
- return Promise.resolve({ selectedLlmProviders: ["openai"] });
389
- }
390
-
391
- if (questions[0].type === "input") {
392
- const validateFunction = questions[0].validate;
393
- expect(validateFunction("")).toBe("Please enter a valid API Key for OpenAI.");
394
- expect(validateFunction("API_KEY1")).toBe(true);
395
- return Promise.resolve({ openai: "API_KEY1" });
396
- }
397
- });
398
183
 
399
- simServCheckInstallRequirements.mockResolvedValue({ docker: true });
400
- simServResetDockerContainers.mockResolvedValue(true);
401
- simServResetDockerImages.mockResolvedValue(true);
402
- simServRunSimulator.mockResolvedValue(true);
403
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
404
- simServDeleteAllValidators.mockResolvedValue(true);
405
- simServCreateRandomValidators.mockResolvedValue(true);
406
- simServOpenFrontend.mockResolvedValue(true);
407
-
408
- await initAction(defaultActionOptions, simulatorService);
409
- });
410
-
411
-
412
- test("logs error message if simulator fails to initialize with ERROR code", async () => {
413
- inquirerPrompt
414
- .mockResolvedValueOnce({ confirmReset: true })
415
- .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
416
- .mockResolvedValueOnce({ openai: "API_KEY1" });
417
-
418
- simServCheckInstallRequirements.mockResolvedValue({ docker: true });
419
- simServResetDockerContainers.mockResolvedValue(true);
420
- simServResetDockerImages.mockResolvedValue(true);
421
- simServRunSimulator.mockResolvedValue(true);
422
-
423
- simServWaitForSimulator.mockResolvedValue({
424
- initialized: false,
425
- errorCode: "ERROR",
426
- errorMessage: "Simulator failed to initialize due to configuration error.",
184
+ test("fails if version requirement for docker is not met", async () => {
185
+ const version = "99.9.9";
186
+ checkVersionRequirementsSpy.mockResolvedValue({ docker: version });
187
+ await initAction.execute(defaultOptions);
188
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith(`Docker version ${version} or higher is required. Please update Docker and try again.\n`);
427
189
  });
428
190
 
429
- await initAction(defaultActionOptions, simulatorService);
430
-
431
- expect(log).toHaveBeenCalledWith("Simulator failed to initialize due to configuration error.");
432
- expect(error).toHaveBeenCalledWith("Unable to initialize the GenLayer simulator. Please try again.");
433
- });
434
-
435
- test("logs error if runSimulator throws", async () => {
436
- inquirerPrompt.mockResolvedValue({
437
- confirmReset: true,
438
- confirmDownload: true,
439
- selectedLlmProviders: ["openai"],
440
- openai: "API_KEY1",
191
+ test("fails if version requirement for node is not met", async () => {
192
+ const version = "99.9.9";
193
+ checkVersionRequirementsSpy.mockResolvedValue({ node: version });
194
+ await initAction.execute(defaultOptions);
195
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith(`Node version ${version} or higher is required. Please update Node and try again.\n`);
441
196
  });
442
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
443
- simServResetDockerContainers.mockResolvedValue(true);
444
- simServResetDockerImages.mockResolvedValue(true);
445
- const errorMsg = new Error("runSimulator error");
446
- simServRunSimulator.mockRejectedValueOnce(errorMsg);
447
197
 
448
- await initAction(defaultActionOptions, simulatorService);
449
-
450
- expect(error).toHaveBeenCalledWith(errorMsg);
451
- });
452
-
453
- test("logs specific message if waitForSimulatorToBeReady returns TIMEOUT errorCode", async () => {
454
- inquirerPrompt.mockResolvedValue({
455
- confirmReset: true,
456
- confirmDownload: true,
457
- selectedLlmProviders: ["openai"],
458
- openai: "API_KEY1",
459
- });
460
- simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
461
- simServResetDockerContainers.mockResolvedValue(true);
462
- simServResetDockerImages.mockResolvedValue(true);
463
- simServRunSimulator.mockResolvedValue(true);
464
- simServWaitForSimulator.mockResolvedValue({
465
- initialized: false,
466
- errorCode: "TIMEOUT",
467
- errorMessage: "errorMessage",
198
+ test("aborts if user does not confirm reset action", async () => {
199
+ inquirerPromptSpy.mockResolvedValueOnce({ confirmAction: false });
200
+ await initAction.execute(defaultOptions)
201
+ expect((initAction as any).logError).toHaveBeenCalledWith(`Operation aborted!`);
468
202
  });
469
203
 
470
- await initAction(defaultActionOptions, simulatorService);
471
-
472
- expect(error).toHaveBeenCalledWith(
473
- "The simulator is taking too long to initialize. Please try again after the simulator is ready."
474
- );
475
- });
476
-
477
- test("catches and logs error if waitForSimulatorToBeReady throws an exception", async () => {
478
- inquirerPrompt
479
- .mockResolvedValueOnce({ confirmReset: true })
480
- .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
481
- .mockResolvedValueOnce({ openai: "API_KEY1" });
482
-
483
- simServCheckInstallRequirements.mockResolvedValue({ docker: true });
484
- simServResetDockerContainers.mockResolvedValue(true);
485
- simServResetDockerImages.mockResolvedValue(true);
486
- simServRunSimulator.mockResolvedValue(true);
487
-
488
- const errorMsg = new Error("Unexpected simulator error");
489
- simServWaitForSimulator.mockRejectedValueOnce(errorMsg);
204
+ test("fails if resetDockerContainers throws an error", async () => {
205
+ inquirerPromptSpy.mockResolvedValueOnce({ confirmAction: true });
206
+ resetDockerContainersSpy.mockRejectedValue(new Error("Container reset error"));
207
+ await initAction.execute(defaultOptions);
208
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", new Error("Container reset error"));
209
+ });
490
210
 
491
- await initAction(defaultActionOptions, simulatorService);
211
+ test("fails if runSimulator throws an error", async () => {
212
+ inquirerPromptSpy
213
+ .mockResolvedValueOnce({ confirmAction: true })
214
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
215
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
216
+ runSimulatorSpy.mockRejectedValue(new Error("Run simulator error"));
217
+ await initAction.execute(defaultOptions);
218
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", new Error("Run simulator error"));
219
+ });
492
220
 
493
- expect(error).toHaveBeenCalledWith(errorMsg);
494
- });
221
+ test("fails if waitForSimulatorToBeReady returns ERROR code", async () => {
222
+ inquirerPromptSpy
223
+ .mockResolvedValueOnce({ confirmAction: true })
224
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
225
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
226
+ waitForSimulatorSpy.mockResolvedValue({ initialized: false, errorCode: "ERROR", errorMessage: "Initialization failed" });
227
+ await initAction.execute(defaultOptions);
228
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("Unable to initialize the GenLayer Localnet: Initialization failed");
229
+ });
495
230
 
496
- test("catches and logs error if openFrontend throws an exception", async () => {
497
- const mockEnvContent = "FRONTEND_PORT=8080";
498
- vi.mocked(fs.readFileSync).mockReturnValue(mockEnvContent);
231
+ test("fails if waitForSimulatorToBeReady returns TIMEOUT code", async () => {
232
+ inquirerPromptSpy
233
+ .mockResolvedValueOnce({ confirmAction: true })
234
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
235
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
236
+ waitForSimulatorSpy.mockResolvedValue({ initialized: false, errorCode: "TIMEOUT", errorMessage: "Timeout" });
237
+ await initAction.execute(defaultOptions);
238
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("The localnet is taking too long to initialize. Please try again after the localnet is ready.");
239
+ });
499
240
 
500
- inquirerPrompt
501
- .mockResolvedValueOnce({ confirmReset: true })
502
- .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
503
- .mockResolvedValueOnce({ openai: "API_KEY1" });
241
+ test("fails if deleteAllValidators throws an error", async () => {
242
+ inquirerPromptSpy
243
+ .mockResolvedValueOnce({ confirmAction: true })
244
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
245
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
246
+ deleteAllValidatorsSpy.mockRejectedValue(new Error("Validator deletion error"));
247
+ await initAction.execute(defaultOptions);
248
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", expect.any(Error));
249
+ });
504
250
 
505
- simServCheckInstallRequirements.mockResolvedValue({ docker: true });
506
- simServResetDockerContainers.mockResolvedValue(true);
507
- simServResetDockerImages.mockResolvedValue(true);
508
- simServRunSimulator.mockResolvedValue(true);
509
- simServWaitForSimulator.mockResolvedValue({ initialized: true });
510
- simServDeleteAllValidators.mockResolvedValue(true);
511
- simServCreateRandomValidators.mockResolvedValue(true);
251
+ test("fails if createRandomValidators throws an error", async () => {
252
+ inquirerPromptSpy
253
+ .mockResolvedValueOnce({ confirmAction: true })
254
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
255
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
256
+ createRandomValidatorsSpy.mockRejectedValue(new Error("Validator creation error"));
257
+ await initAction.execute(defaultOptions);
258
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", Error("Validator creation error"));
259
+ });
512
260
 
513
- const errorMsg = new Error("Failed to open frontend");
514
- simServOpenFrontend.mockImplementationOnce(() => {
515
- throw errorMsg;
261
+ test("fails if cleanDatabase throws an error when resetDb is true", async () => {
262
+ inquirerPromptSpy
263
+ .mockResolvedValueOnce({ confirmAction: true })
264
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
265
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
266
+ cleanDatabaseSpy.mockRejectedValue(new Error("Database error"));
267
+ const optionsWithResetDb: InitActionOptions = { ...defaultOptions, resetDb: true };
268
+ await initAction.execute(optionsWithResetDb);
269
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", new Error("Database error"));
516
270
  });
517
271
 
518
- await initAction(defaultActionOptions, simulatorService);
272
+ test("fails if openFrontend throws an error", async () => {
273
+ inquirerPromptSpy
274
+ .mockResolvedValueOnce({ confirmAction: true })
275
+ .mockResolvedValueOnce({ selectedLlmProviders: ["openai"] })
276
+ .mockResolvedValueOnce({ openai: "API_KEY_OPENAI" });
277
+ openFrontendSpy.mockRejectedValue(new Error("Frontend error"));
278
+ await initAction.execute(defaultOptions);
279
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", new Error("Frontend error"));
280
+ });
519
281
 
520
- expect(error).toHaveBeenCalledWith(errorMsg);
282
+ test("catches and logs unexpected errors", async () => {
283
+ inquirerPromptSpy.mockRejectedValueOnce(new Error("Unexpected prompt error"));
284
+ await initAction.execute(defaultOptions);
285
+ expect((initAction as any).failSpinner).toHaveBeenCalledWith("An error occurred during initialization.", new Error("Unexpected prompt error"));
286
+ });
521
287
  });
522
-
523
288
  });