kiwivm-cli 0.1.0 → 0.2.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/README.md +62 -36
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +370 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/commands/admin.test.ts +135 -22
- package/src/commands/admin.ts +57 -19
- package/src/commands/backup.test.ts +26 -23
- package/src/commands/backup.ts +13 -15
- package/src/commands/help.test.ts +27 -7
- package/src/commands/help.ts +61 -26
- package/src/commands/info.test.ts +47 -43
- package/src/commands/info.ts +11 -13
- package/src/commands/iso.test.ts +58 -0
- package/src/commands/iso.ts +21 -0
- package/src/commands/migrate.test.ts +105 -0
- package/src/commands/migrate.ts +38 -0
- package/src/commands/network.test.ts +107 -30
- package/src/commands/network.ts +56 -18
- package/src/commands/power.test.ts +58 -40
- package/src/commands/power.ts +27 -16
- package/src/commands/shell.test.ts +66 -0
- package/src/commands/shell.ts +25 -0
- package/src/commands/snapshot.test.ts +141 -71
- package/src/commands/snapshot.ts +85 -33
- package/src/commands/stats.test.ts +81 -0
- package/src/commands/stats.ts +25 -0
- package/src/commands/system.test.ts +109 -40
- package/src/commands/system.ts +55 -23
- package/src/index.test.ts +435 -148
- package/src/index.ts +129 -57
- package/src/types.ts +57 -1
- package/dist/admin-fOud1ZmX.mjs +0 -15
- package/dist/admin-fOud1ZmX.mjs.map +0 -1
- package/dist/backup-D1UJ4aap.mjs +0 -12
- package/dist/backup-D1UJ4aap.mjs.map +0 -1
- package/dist/help-Dk-WApoi.mjs +0 -40
- package/dist/help-Dk-WApoi.mjs.map +0 -1
- package/dist/info-DKExtFYH.mjs +0 -13
- package/dist/info-DKExtFYH.mjs.map +0 -1
- package/dist/monitoring-BSuv8fj9.mjs +0 -13
- package/dist/monitoring-BSuv8fj9.mjs.map +0 -1
- package/dist/network-1ycEIJqT.mjs +0 -15
- package/dist/network-1ycEIJqT.mjs.map +0 -1
- package/dist/power-CDg0Mx1A.mjs +0 -14
- package/dist/power-CDg0Mx1A.mjs.map +0 -1
- package/dist/snapshot-LO_ufoj5.mjs +0 -23
- package/dist/snapshot-LO_ufoj5.mjs.map +0 -1
- package/dist/system-Bl-dsqX9.mjs +0 -21
- package/dist/system-Bl-dsqX9.mjs.map +0 -1
- package/src/commands/monitoring.test.ts +0 -82
- package/src/commands/monitoring.ts +0 -20
package/src/commands/network.ts
CHANGED
|
@@ -1,24 +1,62 @@
|
|
|
1
1
|
import type { KiwiVMClient } from "../client.ts";
|
|
2
2
|
|
|
3
|
-
export async function
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export async function rdnsSet(
|
|
4
|
+
args: string[],
|
|
5
|
+
_flags: Record<string, string>,
|
|
6
6
|
client: KiwiVMClient,
|
|
7
7
|
): Promise<unknown> {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return client.call("ipv6/delete", { ip: flags["ip"] });
|
|
13
|
-
case "private-list":
|
|
14
|
-
return client.call("privateIp/getAvailableIps");
|
|
15
|
-
case "private-assign":
|
|
16
|
-
return client.call("privateIp/assign", { ip: flags["ip"] });
|
|
17
|
-
case "private-delete":
|
|
18
|
-
return client.call("privateIp/delete", { ip: flags["ip"] });
|
|
19
|
-
default:
|
|
20
|
-
throw new Error(
|
|
21
|
-
`Unknown network action: ${action}. Valid: ipv6-add, ipv6-delete, private-list, private-assign, private-delete`,
|
|
22
|
-
);
|
|
8
|
+
const ip = args[0];
|
|
9
|
+
const ptr = args[1];
|
|
10
|
+
if (!ip || !ptr) {
|
|
11
|
+
throw new Error("rdns set requires both <ip> and <ptr> arguments");
|
|
23
12
|
}
|
|
13
|
+
return client.call("setPTR", { ip, ptr });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function ipv6Add(
|
|
17
|
+
_args: string[],
|
|
18
|
+
_flags: Record<string, string>,
|
|
19
|
+
client: KiwiVMClient,
|
|
20
|
+
): Promise<unknown> {
|
|
21
|
+
return client.call("ipv6/add");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function ipv6Delete(
|
|
25
|
+
args: string[],
|
|
26
|
+
_flags: Record<string, string>,
|
|
27
|
+
client: KiwiVMClient,
|
|
28
|
+
): Promise<unknown> {
|
|
29
|
+
const ip = args[0];
|
|
30
|
+
if (!ip) {
|
|
31
|
+
throw new Error("ipv6 delete requires a <subnet> argument");
|
|
32
|
+
}
|
|
33
|
+
return client.call("ipv6/delete", { ip });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function privateIpList(
|
|
37
|
+
_args: string[],
|
|
38
|
+
_flags: Record<string, string>,
|
|
39
|
+
client: KiwiVMClient,
|
|
40
|
+
): Promise<unknown> {
|
|
41
|
+
return client.call("privateIp/getAvailableIps");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function privateIpAssign(
|
|
45
|
+
args: string[],
|
|
46
|
+
_flags: Record<string, string>,
|
|
47
|
+
client: KiwiVMClient,
|
|
48
|
+
): Promise<unknown> {
|
|
49
|
+
return client.call("privateIp/assign", { ip: args[0] });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function privateIpDelete(
|
|
53
|
+
args: string[],
|
|
54
|
+
_flags: Record<string, string>,
|
|
55
|
+
client: KiwiVMClient,
|
|
56
|
+
): Promise<unknown> {
|
|
57
|
+
const ip = args[0];
|
|
58
|
+
if (!ip) {
|
|
59
|
+
throw new Error("private-ip delete requires an <ip> argument");
|
|
60
|
+
}
|
|
61
|
+
return client.call("privateIp/delete", { ip });
|
|
24
62
|
}
|
|
@@ -1,68 +1,86 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import type { KiwiVMClient } from "../client.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { kill, restart, start, stop } from "./power.ts";
|
|
4
4
|
|
|
5
5
|
function mockClient() {
|
|
6
6
|
const call = vi.fn();
|
|
7
7
|
return { client: { call } as unknown as KiwiVMClient, call };
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
describe("power
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
describe("power handlers", () => {
|
|
11
|
+
describe("start", () => {
|
|
12
|
+
it("calls client.call('start')", async () => {
|
|
13
|
+
const { client, call } = mockClient();
|
|
14
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
const result = await start([], {}, client);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
it("stop calls client.call('stop')", async () => {
|
|
22
|
-
const { client, call } = mockClient();
|
|
23
|
-
call.mockResolvedValueOnce({ error: 0 });
|
|
18
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("start");
|
|
19
|
+
expect(result).toEqual({ error: 0 });
|
|
20
|
+
});
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
it("propagates errors from the client", async () => {
|
|
23
|
+
const { client, call } = mockClient();
|
|
24
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
await expect(start([], {}, client)).rejects.toThrow("API failure");
|
|
27
|
+
});
|
|
29
28
|
});
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
describe("stop", () => {
|
|
31
|
+
it("calls client.call('stop')", async () => {
|
|
32
|
+
const { client, call } = mockClient();
|
|
33
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
34
|
+
|
|
35
|
+
const result = await stop([], {}, client);
|
|
36
|
+
|
|
37
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("stop");
|
|
38
|
+
expect(result).toEqual({ error: 0 });
|
|
39
|
+
});
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
it("propagates errors from the client", async () => {
|
|
42
|
+
const { client, call } = mockClient();
|
|
43
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
await expect(stop([], {}, client)).rejects.toThrow("API failure");
|
|
46
|
+
});
|
|
39
47
|
});
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
describe("restart", () => {
|
|
50
|
+
it("calls client.call('restart')", async () => {
|
|
51
|
+
const { client, call } = mockClient();
|
|
52
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
const result = await restart([], {}, client);
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("restart");
|
|
57
|
+
expect(result).toEqual({ error: 0 });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("propagates errors from the client", async () => {
|
|
61
|
+
const { client, call } = mockClient();
|
|
62
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
63
|
+
|
|
64
|
+
await expect(restart([], {}, client)).rejects.toThrow("API failure");
|
|
65
|
+
});
|
|
49
66
|
});
|
|
50
67
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
describe("kill", () => {
|
|
69
|
+
it("calls client.call('kill')", async () => {
|
|
70
|
+
const { client, call } = mockClient();
|
|
71
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
55
72
|
|
|
56
|
-
|
|
73
|
+
const result = await kill([], {}, client);
|
|
57
74
|
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("kill");
|
|
76
|
+
expect(result).toEqual({ error: 0 });
|
|
77
|
+
});
|
|
60
78
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
call.mockRejectedValueOnce(apiError);
|
|
79
|
+
it("propagates errors from the client", async () => {
|
|
80
|
+
const { client, call } = mockClient();
|
|
81
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
65
82
|
|
|
66
|
-
|
|
83
|
+
await expect(kill([], {}, client)).rejects.toThrow("API failure");
|
|
84
|
+
});
|
|
67
85
|
});
|
|
68
86
|
});
|
package/src/commands/power.ts
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import type { KiwiVMClient } from "../client.ts";
|
|
2
2
|
|
|
3
|
-
export async function
|
|
4
|
-
|
|
3
|
+
export async function start(
|
|
4
|
+
_args: string[],
|
|
5
5
|
_flags: Record<string, string>,
|
|
6
6
|
client: KiwiVMClient,
|
|
7
7
|
): Promise<unknown> {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
return client.call("start");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function stop(
|
|
12
|
+
_args: string[],
|
|
13
|
+
_flags: Record<string, string>,
|
|
14
|
+
client: KiwiVMClient,
|
|
15
|
+
): Promise<unknown> {
|
|
16
|
+
return client.call("stop");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function restart(
|
|
20
|
+
_args: string[],
|
|
21
|
+
_flags: Record<string, string>,
|
|
22
|
+
client: KiwiVMClient,
|
|
23
|
+
): Promise<unknown> {
|
|
24
|
+
return client.call("restart");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function kill(
|
|
28
|
+
_args: string[],
|
|
29
|
+
_flags: Record<string, string>,
|
|
30
|
+
client: KiwiVMClient,
|
|
31
|
+
): Promise<unknown> {
|
|
32
|
+
return client.call("kill");
|
|
22
33
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { KiwiVMClient } from "../client.ts";
|
|
3
|
+
import { exec, script } from "./shell.ts";
|
|
4
|
+
|
|
5
|
+
function mockClient() {
|
|
6
|
+
const call = vi.fn();
|
|
7
|
+
return { client: { call } as unknown as KiwiVMClient, call };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("shell handlers", () => {
|
|
11
|
+
describe("exec", () => {
|
|
12
|
+
it("calls basicShell/exec with command from args", async () => {
|
|
13
|
+
const { client, call } = mockClient();
|
|
14
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
15
|
+
|
|
16
|
+
const result = await exec(["uptime"], {}, client);
|
|
17
|
+
|
|
18
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("basicShell/exec", {
|
|
19
|
+
command: "uptime",
|
|
20
|
+
});
|
|
21
|
+
expect(result).toEqual({ error: 0 });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("throws when no command provided", async () => {
|
|
25
|
+
const { client } = mockClient();
|
|
26
|
+
|
|
27
|
+
await expect(exec([], {}, client)).rejects.toThrow("command");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("propagates errors from the client", async () => {
|
|
31
|
+
const { client, call } = mockClient();
|
|
32
|
+
call.mockRejectedValueOnce(new Error("Exec failed"));
|
|
33
|
+
|
|
34
|
+
await expect(exec(["uptime"], {}, client)).rejects.toThrow("Exec failed");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("script", () => {
|
|
39
|
+
it("calls shellScript/exec with script from args", async () => {
|
|
40
|
+
const { client, call } = mockClient();
|
|
41
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
42
|
+
|
|
43
|
+
const result = await script(["apt update"], {}, client);
|
|
44
|
+
|
|
45
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("shellScript/exec", {
|
|
46
|
+
script: "apt update",
|
|
47
|
+
});
|
|
48
|
+
expect(result).toEqual({ error: 0 });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("throws when no script provided", async () => {
|
|
52
|
+
const { client } = mockClient();
|
|
53
|
+
|
|
54
|
+
await expect(script([], {}, client)).rejects.toThrow("script");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("propagates errors from the client", async () => {
|
|
58
|
+
const { client, call } = mockClient();
|
|
59
|
+
call.mockRejectedValueOnce(new Error("Script failed"));
|
|
60
|
+
|
|
61
|
+
await expect(script(["apt update"], {}, client)).rejects.toThrow(
|
|
62
|
+
"Script failed",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { KiwiVMClient } from "../client.ts";
|
|
2
|
+
|
|
3
|
+
export async function exec(
|
|
4
|
+
args: string[],
|
|
5
|
+
_flags: Record<string, string>,
|
|
6
|
+
client: KiwiVMClient,
|
|
7
|
+
): Promise<unknown> {
|
|
8
|
+
const command = args[0];
|
|
9
|
+
if (!command) {
|
|
10
|
+
throw new Error("shell exec requires a <command> argument");
|
|
11
|
+
}
|
|
12
|
+
return client.call("basicShell/exec", { command });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function script(
|
|
16
|
+
args: string[],
|
|
17
|
+
_flags: Record<string, string>,
|
|
18
|
+
client: KiwiVMClient,
|
|
19
|
+
): Promise<unknown> {
|
|
20
|
+
const scriptContent = args[0];
|
|
21
|
+
if (!scriptContent) {
|
|
22
|
+
throw new Error("shell script requires a <script> argument");
|
|
23
|
+
}
|
|
24
|
+
return client.call("shellScript/exec", { script: scriptContent });
|
|
25
|
+
}
|
|
@@ -1,44 +1,23 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import type { KiwiVMClient } from "../client.ts";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
create,
|
|
5
|
+
deleteSnapshot,
|
|
6
|
+
exportSnapshot,
|
|
7
|
+
importSnapshot,
|
|
8
|
+
list,
|
|
9
|
+
restore,
|
|
10
|
+
sticky,
|
|
11
|
+
} from "./snapshot.ts";
|
|
4
12
|
|
|
5
13
|
function mockClient() {
|
|
6
14
|
const call = vi.fn();
|
|
7
15
|
return { client: { call } as unknown as KiwiVMClient, call };
|
|
8
16
|
}
|
|
9
17
|
|
|
10
|
-
describe("snapshot
|
|
11
|
-
describe("create", () => {
|
|
12
|
-
it("calls snapshot/create with description flag", async () => {
|
|
13
|
-
const { client, call } = mockClient();
|
|
14
|
-
call.mockResolvedValueOnce({ error: 0 });
|
|
15
|
-
|
|
16
|
-
const result = await run(
|
|
17
|
-
"create",
|
|
18
|
-
{ description: "pre-upgrade" },
|
|
19
|
-
client,
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
expect(client.call).toHaveBeenCalledExactlyOnceWith("snapshot/create", {
|
|
23
|
-
description: "pre-upgrade",
|
|
24
|
-
});
|
|
25
|
-
expect(result).toEqual({ error: 0 });
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("calls snapshot/create without description when flag is omitted", async () => {
|
|
29
|
-
const { client, call } = mockClient();
|
|
30
|
-
call.mockResolvedValueOnce({ error: 0 });
|
|
31
|
-
|
|
32
|
-
await run("create", {}, client);
|
|
33
|
-
|
|
34
|
-
expect(client.call).toHaveBeenCalledExactlyOnceWith("snapshot/create", {
|
|
35
|
-
description: undefined,
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
18
|
+
describe("snapshot handlers", () => {
|
|
40
19
|
describe("list", () => {
|
|
41
|
-
it("calls snapshot/list", async () => {
|
|
20
|
+
it("calls client.call('snapshot/list')", async () => {
|
|
42
21
|
const { client, call } = mockClient();
|
|
43
22
|
const snapshots = {
|
|
44
23
|
error: 0,
|
|
@@ -58,102 +37,193 @@ describe("snapshot command", () => {
|
|
|
58
37
|
};
|
|
59
38
|
call.mockResolvedValueOnce(snapshots);
|
|
60
39
|
|
|
61
|
-
const result = await
|
|
40
|
+
const result = await list([], {}, client);
|
|
62
41
|
|
|
63
|
-
expect(
|
|
42
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/list");
|
|
64
43
|
expect(result).toEqual(snapshots);
|
|
65
44
|
});
|
|
45
|
+
|
|
46
|
+
it("propagates errors from the client", async () => {
|
|
47
|
+
const { client, call } = mockClient();
|
|
48
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
49
|
+
|
|
50
|
+
await expect(list([], {}, client)).rejects.toThrow("API failure");
|
|
51
|
+
});
|
|
66
52
|
});
|
|
67
53
|
|
|
68
|
-
describe("
|
|
69
|
-
it("calls snapshot/
|
|
54
|
+
describe("create", () => {
|
|
55
|
+
it("calls snapshot/create with description flag", async () => {
|
|
56
|
+
const { client, call } = mockClient();
|
|
57
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
58
|
+
|
|
59
|
+
const result = await create([], { desc: "pre-upgrade" }, client);
|
|
60
|
+
|
|
61
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/create", {
|
|
62
|
+
description: "pre-upgrade",
|
|
63
|
+
});
|
|
64
|
+
expect(result).toEqual({ error: 0 });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("calls snapshot/create with description undefined when flag omitted", async () => {
|
|
70
68
|
const { client, call } = mockClient();
|
|
71
69
|
call.mockResolvedValueOnce({ error: 0 });
|
|
72
70
|
|
|
73
|
-
await
|
|
71
|
+
await create([], {}, client);
|
|
74
72
|
|
|
75
|
-
expect(
|
|
73
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/create", {
|
|
74
|
+
description: undefined,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("propagates errors from the client", async () => {
|
|
79
|
+
const { client, call } = mockClient();
|
|
80
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
81
|
+
|
|
82
|
+
await expect(create([], {}, client)).rejects.toThrow("API failure");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("deleteSnapshot", () => {
|
|
87
|
+
it("calls snapshot/delete with snapshot token from args", async () => {
|
|
88
|
+
const { client, call } = mockClient();
|
|
89
|
+
call.mockResolvedValueOnce({ error: 0 });
|
|
90
|
+
|
|
91
|
+
await deleteSnapshot(["snap1"], {}, client);
|
|
92
|
+
|
|
93
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/delete", {
|
|
76
94
|
snapshot: "snap1",
|
|
77
95
|
});
|
|
78
96
|
});
|
|
97
|
+
|
|
98
|
+
it("throws when no snapshot token provided", async () => {
|
|
99
|
+
const { client } = mockClient();
|
|
100
|
+
|
|
101
|
+
await expect(deleteSnapshot([], {}, client)).rejects.toThrow(/token/);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("propagates errors from the client", async () => {
|
|
105
|
+
const { client, call } = mockClient();
|
|
106
|
+
call.mockRejectedValueOnce(new Error("Snapshot not found"));
|
|
107
|
+
|
|
108
|
+
await expect(deleteSnapshot(["nonexistent"], {}, client)).rejects.toThrow(
|
|
109
|
+
"Snapshot not found",
|
|
110
|
+
);
|
|
111
|
+
});
|
|
79
112
|
});
|
|
80
113
|
|
|
81
114
|
describe("restore", () => {
|
|
82
|
-
it("calls snapshot/restore with snapshot
|
|
115
|
+
it("calls snapshot/restore with snapshot token from args", async () => {
|
|
83
116
|
const { client, call } = mockClient();
|
|
84
117
|
call.mockResolvedValueOnce({ error: 0 });
|
|
85
118
|
|
|
86
|
-
await
|
|
119
|
+
await restore(["snap1"], {}, client);
|
|
87
120
|
|
|
88
|
-
expect(
|
|
121
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/restore", {
|
|
89
122
|
snapshot: "snap1",
|
|
90
123
|
});
|
|
91
124
|
});
|
|
125
|
+
|
|
126
|
+
it("propagates errors from the client", async () => {
|
|
127
|
+
const { client, call } = mockClient();
|
|
128
|
+
call.mockRejectedValueOnce(new Error("Snapshot not found"));
|
|
129
|
+
|
|
130
|
+
await expect(restore(["nonexistent"], {}, client)).rejects.toThrow(
|
|
131
|
+
"Snapshot not found",
|
|
132
|
+
);
|
|
133
|
+
});
|
|
92
134
|
});
|
|
93
135
|
|
|
94
136
|
describe("sticky", () => {
|
|
95
|
-
it("calls snapshot/toggleSticky with
|
|
137
|
+
it("calls snapshot/toggleSticky with sticky=1 when --on flag set", async () => {
|
|
96
138
|
const { client, call } = mockClient();
|
|
97
139
|
call.mockResolvedValueOnce({ error: 0 });
|
|
98
140
|
|
|
99
|
-
await
|
|
141
|
+
await sticky(["snap1"], { on: "1" }, client);
|
|
100
142
|
|
|
101
|
-
expect(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
);
|
|
143
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/toggleSticky", {
|
|
144
|
+
snapshot: "snap1",
|
|
145
|
+
sticky: 1,
|
|
146
|
+
});
|
|
105
147
|
});
|
|
106
148
|
|
|
107
|
-
it("
|
|
149
|
+
it("calls snapshot/toggleSticky with sticky=0 when --off flag set", async () => {
|
|
108
150
|
const { client, call } = mockClient();
|
|
109
151
|
call.mockResolvedValueOnce({ error: 0 });
|
|
110
152
|
|
|
111
|
-
await
|
|
153
|
+
await sticky(["snap1"], { off: "1" }, client);
|
|
112
154
|
|
|
113
|
-
expect(
|
|
114
|
-
|
|
115
|
-
|
|
155
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/toggleSticky", {
|
|
156
|
+
snapshot: "snap1",
|
|
157
|
+
sticky: 0,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("throws when neither --on nor --off flag provided", async () => {
|
|
162
|
+
const { client } = mockClient();
|
|
163
|
+
|
|
164
|
+
await expect(sticky(["snap1"], {}, client)).rejects.toThrow("--on");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("propagates errors from the client", async () => {
|
|
168
|
+
const { client, call } = mockClient();
|
|
169
|
+
call.mockRejectedValueOnce(new Error("API failure"));
|
|
170
|
+
|
|
171
|
+
await expect(sticky(["snap1"], { on: "1" }, client)).rejects.toThrow(
|
|
172
|
+
"API failure",
|
|
116
173
|
);
|
|
117
174
|
});
|
|
118
175
|
});
|
|
119
176
|
|
|
120
|
-
describe("
|
|
121
|
-
it("calls snapshot/export with snapshot
|
|
177
|
+
describe("exportSnapshot", () => {
|
|
178
|
+
it("calls snapshot/export with snapshot token from args", async () => {
|
|
122
179
|
const { client, call } = mockClient();
|
|
123
180
|
call.mockResolvedValueOnce({ error: 0 });
|
|
124
181
|
|
|
125
|
-
await
|
|
182
|
+
await exportSnapshot(["snap1"], {}, client);
|
|
126
183
|
|
|
127
|
-
expect(
|
|
184
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/export", {
|
|
128
185
|
snapshot: "snap1",
|
|
129
186
|
});
|
|
130
187
|
});
|
|
188
|
+
|
|
189
|
+
it("propagates errors from the client", async () => {
|
|
190
|
+
const { client, call } = mockClient();
|
|
191
|
+
call.mockRejectedValueOnce(new Error("Export failed"));
|
|
192
|
+
|
|
193
|
+
await expect(exportSnapshot(["snap1"], {}, client)).rejects.toThrow(
|
|
194
|
+
"Export failed",
|
|
195
|
+
);
|
|
196
|
+
});
|
|
131
197
|
});
|
|
132
198
|
|
|
133
|
-
describe("
|
|
134
|
-
it("calls snapshot/import with sourceVeid and sourceToken", async () => {
|
|
199
|
+
describe("importSnapshot", () => {
|
|
200
|
+
it("calls snapshot/import with sourceVeid and sourceToken from args", async () => {
|
|
135
201
|
const { client, call } = mockClient();
|
|
136
202
|
call.mockResolvedValueOnce({ error: 0 });
|
|
137
203
|
|
|
138
|
-
await
|
|
139
|
-
"import",
|
|
140
|
-
{ sourceVeid: "67890", sourceToken: "abc123" },
|
|
141
|
-
client,
|
|
142
|
-
);
|
|
204
|
+
await importSnapshot(["67890", "abc123"], {}, client);
|
|
143
205
|
|
|
144
|
-
expect(
|
|
206
|
+
expect(call).toHaveBeenCalledExactlyOnceWith("snapshot/import", {
|
|
145
207
|
sourceVeid: "67890",
|
|
146
208
|
sourceToken: "abc123",
|
|
147
209
|
});
|
|
148
210
|
});
|
|
149
|
-
});
|
|
150
211
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
212
|
+
it("throws when only sourceVeid provided (missing token)", async () => {
|
|
213
|
+
const { client } = mockClient();
|
|
214
|
+
|
|
215
|
+
await expect(importSnapshot(["67890"], {}, client)).rejects.toThrow(
|
|
216
|
+
/token/i,
|
|
217
|
+
);
|
|
218
|
+
});
|
|
154
219
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
220
|
+
it("propagates errors from the client", async () => {
|
|
221
|
+
const { client, call } = mockClient();
|
|
222
|
+
call.mockRejectedValueOnce(new Error("Import failed"));
|
|
223
|
+
|
|
224
|
+
await expect(
|
|
225
|
+
importSnapshot(["67890", "abc123"], {}, client),
|
|
226
|
+
).rejects.toThrow("Import failed");
|
|
227
|
+
});
|
|
158
228
|
});
|
|
159
229
|
});
|