cisco-perfmon 1.6.0 → 2.0.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/.github/workflows/release.yml +15 -0
- package/README.md +354 -53
- package/bin/cisco-perfmon.js +2 -0
- package/cli/commands/collect.js +48 -0
- package/cli/commands/config.js +85 -0
- package/cli/commands/describe.js +43 -0
- package/cli/commands/doctor.js +115 -0
- package/cli/commands/list-instances.js +39 -0
- package/cli/commands/list-objects.js +45 -0
- package/cli/commands/session.js +162 -0
- package/cli/commands/watch.js +163 -0
- package/cli/formatters/csv.js +10 -0
- package/cli/formatters/json.js +5 -0
- package/cli/formatters/table.js +25 -0
- package/cli/formatters/toon.js +6 -0
- package/cli/index.js +40 -0
- package/cli/utils/audit.js +30 -0
- package/cli/utils/config.js +112 -0
- package/cli/utils/connection.js +36 -0
- package/cli/utils/output.js +28 -0
- package/main.js +6 -7
- package/package.json +13 -2
- package/skills/cisco-perfmon-cli/SKILL.md +176 -0
- package/test/cli/config.test.js +196 -0
- package/test/cli/connection.test.js +151 -0
- package/test/cli/formatters.test.js +144 -0
- package/test/cli/watch.test.js +76 -0
- package/test/unit.js +24 -0
- package/types/index.d.ts +5 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const assert = require("assert");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
|
|
6
|
+
let passed = 0, failed = 0, total = 0;
|
|
7
|
+
function describe(name, fn) { console.log(` ${name}`); fn(); }
|
|
8
|
+
function it(name, fn) {
|
|
9
|
+
total++;
|
|
10
|
+
try { fn(); console.log(` \u2713 ${name}`); passed++; }
|
|
11
|
+
catch (e) { console.log(` \u2717 ${name}: ${e.message}`); failed++; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "cisco-perfmon-test-conn-"));
|
|
15
|
+
process.env.CISCO_PERFMON_CONFIG_DIR = tmpDir;
|
|
16
|
+
|
|
17
|
+
const { saveConfig } = require("../../cli/utils/config.js");
|
|
18
|
+
const { resolveConfig } = require("../../cli/utils/connection.js");
|
|
19
|
+
|
|
20
|
+
// Save env vars to restore later
|
|
21
|
+
const savedHost = process.env.CUCM_HOST;
|
|
22
|
+
const savedHostname = process.env.CUCM_HOSTNAME;
|
|
23
|
+
const savedUsername = process.env.CUCM_USERNAME;
|
|
24
|
+
const savedPassword = process.env.CUCM_PASSWORD;
|
|
25
|
+
|
|
26
|
+
function clearEnv() {
|
|
27
|
+
delete process.env.CUCM_HOST;
|
|
28
|
+
delete process.env.CUCM_HOSTNAME;
|
|
29
|
+
delete process.env.CUCM_USERNAME;
|
|
30
|
+
delete process.env.CUCM_PASSWORD;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function restoreEnv() {
|
|
34
|
+
if (savedHost !== undefined) process.env.CUCM_HOST = savedHost; else delete process.env.CUCM_HOST;
|
|
35
|
+
if (savedHostname !== undefined) process.env.CUCM_HOSTNAME = savedHostname; else delete process.env.CUCM_HOSTNAME;
|
|
36
|
+
if (savedUsername !== undefined) process.env.CUCM_USERNAME = savedUsername; else delete process.env.CUCM_USERNAME;
|
|
37
|
+
if (savedPassword !== undefined) process.env.CUCM_PASSWORD = savedPassword; else delete process.env.CUCM_PASSWORD;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("resolveConfig — throws when nothing configured", () => {
|
|
41
|
+
it("throws when no flags, env, or config exist", () => {
|
|
42
|
+
clearEnv();
|
|
43
|
+
saveConfig({ activeCluster: null, clusters: {} });
|
|
44
|
+
assert.throws(() => resolveConfig({}), /No cluster configured/);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("resolveConfig — config file source", () => {
|
|
49
|
+
it("reads from config file when no flags or env set", () => {
|
|
50
|
+
clearEnv();
|
|
51
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "config-host", username: "config-user", password: "config-pass" } } });
|
|
52
|
+
const result = resolveConfig({});
|
|
53
|
+
assert.strictEqual(result.host, "config-host");
|
|
54
|
+
assert.strictEqual(result.username, "config-user");
|
|
55
|
+
assert.strictEqual(result.password, "config-pass");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("includes insecure from config", () => {
|
|
59
|
+
clearEnv();
|
|
60
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "h", username: "u", password: "p", insecure: true } } });
|
|
61
|
+
const result = resolveConfig({});
|
|
62
|
+
assert.strictEqual(result.insecure, true);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("resolveConfig — env vars override config", () => {
|
|
67
|
+
it("CUCM_HOST overrides config host", () => {
|
|
68
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "config-host", username: "config-user", password: "config-pass" } } });
|
|
69
|
+
clearEnv();
|
|
70
|
+
process.env.CUCM_HOST = "env-host";
|
|
71
|
+
process.env.CUCM_USERNAME = "env-user";
|
|
72
|
+
process.env.CUCM_PASSWORD = "env-pass";
|
|
73
|
+
const result = resolveConfig({});
|
|
74
|
+
assert.strictEqual(result.host, "env-host");
|
|
75
|
+
assert.strictEqual(result.username, "env-user");
|
|
76
|
+
assert.strictEqual(result.password, "env-pass");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("CUCM_HOSTNAME also works as host env var", () => {
|
|
80
|
+
clearEnv();
|
|
81
|
+
process.env.CUCM_HOSTNAME = "hostname-env";
|
|
82
|
+
process.env.CUCM_USERNAME = "u";
|
|
83
|
+
process.env.CUCM_PASSWORD = "p";
|
|
84
|
+
saveConfig({ activeCluster: null, clusters: {} });
|
|
85
|
+
const result = resolveConfig({});
|
|
86
|
+
assert.strictEqual(result.host, "hostname-env");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("resolveConfig — flags override env and config", () => {
|
|
91
|
+
it("flag values take highest precedence", () => {
|
|
92
|
+
clearEnv();
|
|
93
|
+
process.env.CUCM_HOST = "env-host";
|
|
94
|
+
process.env.CUCM_USERNAME = "env-user";
|
|
95
|
+
process.env.CUCM_PASSWORD = "env-pass";
|
|
96
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "config-host", username: "config-user", password: "config-pass" } } });
|
|
97
|
+
const result = resolveConfig({ host: "flag-host", username: "flag-user", password: "flag-pass" });
|
|
98
|
+
assert.strictEqual(result.host, "flag-host");
|
|
99
|
+
assert.strictEqual(result.username, "flag-user");
|
|
100
|
+
assert.strictEqual(result.password, "flag-pass");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("flags can partially override (mix sources)", () => {
|
|
104
|
+
clearEnv();
|
|
105
|
+
process.env.CUCM_USERNAME = "env-user";
|
|
106
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "config-host", username: "config-user", password: "config-pass" } } });
|
|
107
|
+
const result = resolveConfig({ host: "flag-host" });
|
|
108
|
+
assert.strictEqual(result.host, "flag-host");
|
|
109
|
+
assert.strictEqual(result.username, "env-user");
|
|
110
|
+
assert.strictEqual(result.password, "config-pass");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("resolveConfig — named cluster override", () => {
|
|
115
|
+
it("uses --cluster flag to select a specific cluster", () => {
|
|
116
|
+
clearEnv();
|
|
117
|
+
saveConfig({
|
|
118
|
+
activeCluster: "prod",
|
|
119
|
+
clusters: {
|
|
120
|
+
prod: { host: "prod-host", username: "prod-user", password: "prod-pass" },
|
|
121
|
+
lab: { host: "lab-host", username: "lab-user", password: "lab-pass" },
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
const result = resolveConfig({ cluster: "lab" });
|
|
125
|
+
assert.strictEqual(result.host, "lab-host");
|
|
126
|
+
assert.strictEqual(result.username, "lab-user");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("resolveConfig — insecure defaults to false", () => {
|
|
131
|
+
it("insecure is false when not set anywhere", () => {
|
|
132
|
+
clearEnv();
|
|
133
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "h", username: "u", password: "p" } } });
|
|
134
|
+
const result = resolveConfig({});
|
|
135
|
+
assert.strictEqual(result.insecure, false);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("insecure flag overrides config", () => {
|
|
139
|
+
clearEnv();
|
|
140
|
+
saveConfig({ activeCluster: "lab", clusters: { lab: { host: "h", username: "u", password: "p" } } });
|
|
141
|
+
const result = resolveConfig({ insecure: true });
|
|
142
|
+
assert.strictEqual(result.insecure, true);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Restore env and cleanup
|
|
147
|
+
restoreEnv();
|
|
148
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
149
|
+
|
|
150
|
+
console.log(`\n connection.test.js: ${total} tests, ${passed} passed, ${failed} failed`);
|
|
151
|
+
if (failed > 0) process.exit(1);
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const assert = require("assert");
|
|
2
|
+
|
|
3
|
+
let passed = 0, failed = 0, total = 0;
|
|
4
|
+
function describe(name, fn) { console.log(` ${name}`); fn(); }
|
|
5
|
+
function it(name, fn) {
|
|
6
|
+
total++;
|
|
7
|
+
try { fn(); console.log(` \u2713 ${name}`); passed++; }
|
|
8
|
+
catch (e) { console.log(` \u2717 ${name}: ${e.message}`); failed++; }
|
|
9
|
+
}
|
|
10
|
+
async function itAsync(name, fn) {
|
|
11
|
+
total++;
|
|
12
|
+
try { await fn(); console.log(` \u2713 ${name}`); passed++; }
|
|
13
|
+
catch (e) { console.log(` \u2717 ${name}: ${e.message}`); failed++; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const formatTable = require("../../cli/formatters/table.js");
|
|
17
|
+
const formatJson = require("../../cli/formatters/json.js");
|
|
18
|
+
const formatCsv = require("../../cli/formatters/csv.js");
|
|
19
|
+
const formatToon = require("../../cli/formatters/toon.js");
|
|
20
|
+
|
|
21
|
+
const sampleList = [
|
|
22
|
+
{ object: "Cisco CallManager", counter: "CallsActive", instance: "", value: "5", cstatus: "1" },
|
|
23
|
+
{ object: "Cisco CallManager", counter: "CallsInProgress", instance: "", value: "12", cstatus: "1" },
|
|
24
|
+
];
|
|
25
|
+
const sampleItem = { object: "Cisco CallManager", counter: "CallsActive", instance: "", value: "5", cstatus: "1" };
|
|
26
|
+
|
|
27
|
+
(async () => {
|
|
28
|
+
describe("table formatter", () => {
|
|
29
|
+
it("produces string output for an array", () => {
|
|
30
|
+
const result = formatTable(sampleList);
|
|
31
|
+
assert.strictEqual(typeof result, "string");
|
|
32
|
+
assert.ok(result.length > 0, "Output should not be empty");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("includes column headers from object keys", () => {
|
|
36
|
+
const result = formatTable(sampleList);
|
|
37
|
+
assert.ok(result.includes("object"), "Should contain 'object' header");
|
|
38
|
+
assert.ok(result.includes("counter"), "Should contain 'counter' header");
|
|
39
|
+
assert.ok(result.includes("value"), "Should contain 'value' header");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("includes data values", () => {
|
|
43
|
+
const result = formatTable(sampleList);
|
|
44
|
+
assert.ok(result.includes("CallsActive"), "Should contain counter name");
|
|
45
|
+
assert.ok(result.includes("Cisco CallManager"), "Should contain object name");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("includes row count in output", () => {
|
|
49
|
+
const result = formatTable(sampleList);
|
|
50
|
+
assert.ok(result.includes("2 results found"), "Should show result count");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("shows singular 'result' for single-item array", () => {
|
|
54
|
+
const result = formatTable([sampleItem]);
|
|
55
|
+
assert.ok(result.includes("1 result found"), "Should show singular result");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("produces key-value output for a single object", () => {
|
|
59
|
+
const result = formatTable(sampleItem);
|
|
60
|
+
assert.strictEqual(typeof result, "string");
|
|
61
|
+
assert.ok(result.includes("CallsActive"), "Should contain item value");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("returns 'No results found' for empty array", () => {
|
|
65
|
+
const result = formatTable([]);
|
|
66
|
+
assert.strictEqual(result, "No results found");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("handles null/undefined values gracefully", () => {
|
|
70
|
+
const result = formatTable([{ object: "test", counter: null, value: undefined }]);
|
|
71
|
+
assert.strictEqual(typeof result, "string");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("json formatter", () => {
|
|
76
|
+
it("produces valid JSON for an array", () => {
|
|
77
|
+
const result = formatJson(sampleList);
|
|
78
|
+
const parsed = JSON.parse(result);
|
|
79
|
+
assert.ok(Array.isArray(parsed), "Parsed result should be an array");
|
|
80
|
+
assert.strictEqual(parsed.length, 2);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("produces valid JSON for a single item", () => {
|
|
84
|
+
const result = formatJson(sampleItem);
|
|
85
|
+
const parsed = JSON.parse(result);
|
|
86
|
+
assert.strictEqual(parsed.counter, "CallsActive");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("output is pretty-printed with 2-space indent", () => {
|
|
90
|
+
const result = formatJson(sampleItem);
|
|
91
|
+
assert.ok(result.includes(" "), "Should contain 2-space indentation");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("preserves all fields", () => {
|
|
95
|
+
const result = formatJson(sampleItem);
|
|
96
|
+
const parsed = JSON.parse(result);
|
|
97
|
+
assert.strictEqual(parsed.object, "Cisco CallManager");
|
|
98
|
+
assert.strictEqual(parsed.value, "5");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("csv formatter", () => {
|
|
103
|
+
it("produces CSV with headers for an array", () => {
|
|
104
|
+
const result = formatCsv(sampleList);
|
|
105
|
+
const lines = result.trim().split("\n");
|
|
106
|
+
assert.ok(lines.length >= 3, "Should have header + 2 data rows");
|
|
107
|
+
assert.ok(lines[0].includes("object"), "First line should contain header 'object'");
|
|
108
|
+
assert.ok(lines[0].includes("counter"), "First line should contain header 'counter'");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("produces CSV for a single item (wrapped in array)", () => {
|
|
112
|
+
const result = formatCsv(sampleItem);
|
|
113
|
+
const lines = result.trim().split("\n");
|
|
114
|
+
assert.ok(lines.length >= 2, "Should have header + 1 data row");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("returns empty string for empty array", () => {
|
|
118
|
+
const result = formatCsv([]);
|
|
119
|
+
assert.strictEqual(result, "");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("includes data values in rows", () => {
|
|
123
|
+
const result = formatCsv(sampleList);
|
|
124
|
+
assert.ok(result.includes("CallsActive"), "Should contain counter name");
|
|
125
|
+
assert.ok(result.includes("Cisco CallManager"), "Should contain object name");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
console.log(` toon formatter`);
|
|
130
|
+
await itAsync("produces string output", async () => {
|
|
131
|
+
const result = await formatToon(sampleItem);
|
|
132
|
+
assert.strictEqual(typeof result, "string");
|
|
133
|
+
assert.ok(result.length > 0, "Output should not be empty");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await itAsync("handles array input", async () => {
|
|
137
|
+
const result = await formatToon(sampleList);
|
|
138
|
+
assert.strictEqual(typeof result, "string");
|
|
139
|
+
assert.ok(result.length > 0, "Output should not be empty");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
console.log(`\n formatters.test.js: ${total} tests, ${passed} passed, ${failed} failed`);
|
|
143
|
+
if (failed > 0) process.exit(1);
|
|
144
|
+
})();
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const assert = require("assert");
|
|
2
|
+
|
|
3
|
+
let passed = 0, failed = 0, total = 0;
|
|
4
|
+
function describe(name, fn) { console.log(` ${name}`); fn(); }
|
|
5
|
+
function it(name, fn) {
|
|
6
|
+
total++;
|
|
7
|
+
try { fn(); console.log(` \u2713 ${name}`); passed++; }
|
|
8
|
+
catch (e) { console.log(` \u2717 ${name}: ${e.message}`); failed++; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// The watch module exports sparkline after self-registration
|
|
12
|
+
const watchModule = require("../../cli/commands/watch.js");
|
|
13
|
+
const sparkline = watchModule.sparkline;
|
|
14
|
+
|
|
15
|
+
describe("sparkline", () => {
|
|
16
|
+
it("returns empty string for empty array", () => {
|
|
17
|
+
assert.strictEqual(sparkline([]), "");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns a single block for a single value", () => {
|
|
21
|
+
const result = sparkline([5]);
|
|
22
|
+
assert.strictEqual(result.length, 1);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns string with length equal to input length", () => {
|
|
26
|
+
const result = sparkline([1, 2, 3, 4, 5]);
|
|
27
|
+
assert.strictEqual(result.length, 5);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("uses lowest block for minimum and highest for maximum", () => {
|
|
31
|
+
const result = sparkline([0, 100]);
|
|
32
|
+
// First char should be lowest block, second should be highest
|
|
33
|
+
assert.strictEqual(result[0], "\u2581");
|
|
34
|
+
assert.strictEqual(result[1], "\u2588");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("produces all same blocks for constant values", () => {
|
|
38
|
+
const result = sparkline([50, 50, 50, 50]);
|
|
39
|
+
// All same value => range is 0 => formula uses range=1, all map to same block
|
|
40
|
+
const chars = new Set(result.split(""));
|
|
41
|
+
assert.strictEqual(chars.size, 1, "All blocks should be the same for constant values");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("produces ascending blocks for ascending values", () => {
|
|
45
|
+
const result = sparkline([0, 1, 2, 3, 4, 5, 6, 7]);
|
|
46
|
+
// Each character should be >= the previous
|
|
47
|
+
for (let i = 1; i < result.length; i++) {
|
|
48
|
+
assert.ok(result.charCodeAt(i) >= result.charCodeAt(i - 1),
|
|
49
|
+
`Character at ${i} should be >= character at ${i - 1}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("handles negative values", () => {
|
|
54
|
+
const result = sparkline([-10, -5, 0, 5, 10]);
|
|
55
|
+
assert.strictEqual(result.length, 5);
|
|
56
|
+
assert.strictEqual(result[0], "\u2581");
|
|
57
|
+
assert.strictEqual(result[4], "\u2588");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("handles floating point values", () => {
|
|
61
|
+
const result = sparkline([0.1, 0.5, 0.9]);
|
|
62
|
+
assert.strictEqual(result.length, 3);
|
|
63
|
+
assert.strictEqual(typeof result, "string");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("only uses valid sparkline block characters", () => {
|
|
67
|
+
const validChars = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
68
|
+
const result = sparkline([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
|
|
69
|
+
for (const ch of result) {
|
|
70
|
+
assert.ok(validChars.includes(ch), `Character "${ch}" should be a valid sparkline block`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log(`\n watch.test.js: ${total} tests, ${passed} passed, ${failed} failed`);
|
|
76
|
+
if (failed > 0) process.exit(1);
|
package/test/unit.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const { readdirSync } = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
const testDir = path.join(__dirname, "cli");
|
|
6
|
+
const files = readdirSync(testDir).filter(f => f.endsWith(".test.js"));
|
|
7
|
+
|
|
8
|
+
let passed = 0;
|
|
9
|
+
let failed = 0;
|
|
10
|
+
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
try {
|
|
13
|
+
console.log(`\nRunning ${file}...`);
|
|
14
|
+
execSync(`node ${path.join(testDir, file)}`, { stdio: "inherit" });
|
|
15
|
+
passed++;
|
|
16
|
+
} catch {
|
|
17
|
+
failed++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(`\n================================`);
|
|
22
|
+
console.log(` Results: ${passed + failed} files, ${passed} passed, ${failed} failed`);
|
|
23
|
+
console.log(`================================`);
|
|
24
|
+
process.exitCode = failed > 0 ? 1 : 0;
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface PerfmonOptions {
|
|
2
|
+
/** Max number of retries on network/HTTP errors. Defaults to PM_RETRY env var or 3. */
|
|
3
|
+
retries?: number;
|
|
4
|
+
/** Delay in ms between retries. Defaults to PM_RETRY_DELAY env var or 5000. */
|
|
5
|
+
retryDelay?: number;
|
|
2
6
|
Cookie?: string;
|
|
3
|
-
[key: string]: string | undefined;
|
|
7
|
+
[key: string]: string | number | undefined;
|
|
4
8
|
}
|
|
5
9
|
|
|
6
10
|
export interface PerfmonResult {
|