badgr-cli 1.0.23 → 1.0.25
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/package.json +1 -1
- package/src/badgr.js +19 -19
- package/src/commands/run.js +10 -11
- package/src/commands/serve.js +8 -9
- package/src/commands/test-run.js +48 -6
- package/tests/commands.test.js +29 -16
package/package.json
CHANGED
package/src/badgr.js
CHANGED
|
@@ -17,27 +17,27 @@ const HELP = `
|
|
|
17
17
|
${chalk.bold('badgr')} — run or serve GPU workloads from one command
|
|
18
18
|
|
|
19
19
|
${chalk.bold('COMMANDS')}
|
|
20
|
-
${chalk.cyan('badgr login')}
|
|
21
|
-
${chalk.cyan('badgr run <command>')}
|
|
22
|
-
${chalk.cyan('badgr serve <model>')}
|
|
23
|
-
${chalk.cyan('badgr status')}
|
|
24
|
-
${chalk.cyan('badgr logs <id>')}
|
|
25
|
-
${chalk.cyan('badgr down <id>')}
|
|
26
|
-
${chalk.cyan('badgr receipts')}
|
|
27
|
-
${chalk.cyan('badgr test')}
|
|
28
|
-
${chalk.cyan('badgr capacity')}
|
|
20
|
+
${chalk.cyan('badgr login')} Authenticate with your API key
|
|
21
|
+
${chalk.cyan('badgr run <command>')} Run a one-off GPU job
|
|
22
|
+
${chalk.cyan('badgr serve <model>')} Serve a model with an OpenAI-compatible endpoint
|
|
23
|
+
${chalk.cyan('badgr status')} Show what's running and what's billing
|
|
24
|
+
${chalk.cyan('badgr logs <id>')} Stream logs for a running job or endpoint
|
|
25
|
+
${chalk.cyan('badgr down <id>')} Stop a deployment and end billing
|
|
26
|
+
${chalk.cyan('badgr receipts')} Show cost history
|
|
27
|
+
${chalk.cyan('badgr test')} Run an end-to-end test (provision → run → teardown)
|
|
28
|
+
${chalk.cyan('badgr capacity')} Check what GPU capacity is available right now
|
|
29
29
|
|
|
30
30
|
${chalk.bold('EXAMPLES')}
|
|
31
31
|
${chalk.dim('# Verify the stack works end-to-end:')}
|
|
32
32
|
badgr test
|
|
33
33
|
|
|
34
|
-
${chalk.dim('#
|
|
34
|
+
${chalk.dim('# Tier 1 — managed provider routing (default):')}
|
|
35
35
|
badgr run python train.py
|
|
36
36
|
badgr serve meta-llama/Llama-3.1-8B-Instruct
|
|
37
37
|
|
|
38
|
-
${chalk.dim('#
|
|
39
|
-
badgr run python train.py --
|
|
40
|
-
badgr serve meta-llama/Llama-3.1-8B-Instruct --
|
|
38
|
+
${chalk.dim('# Tier 2 — marketplace routing, lower-cost options:')}
|
|
39
|
+
badgr run python train.py --tier 2
|
|
40
|
+
badgr serve meta-llama/Llama-3.1-8B-Instruct --tier 2
|
|
41
41
|
|
|
42
42
|
${chalk.dim('# Pin a specific GPU:')}
|
|
43
43
|
badgr run python train.py --gpu A100
|
|
@@ -53,12 +53,12 @@ ${chalk.bold('EXAMPLES')}
|
|
|
53
53
|
badgr receipts dep-abc123
|
|
54
54
|
|
|
55
55
|
${chalk.bold('badgr run OPTIONS')}
|
|
56
|
-
--gpu <type> GPU type (default: auto — Badgr picks best available
|
|
57
|
-
--
|
|
56
|
+
--gpu <type> GPU type (default: auto — Badgr picks best available)
|
|
57
|
+
--tier 1 Managed provider routing (default)
|
|
58
|
+
--tier 2 Marketplace provider routing, lower-cost options
|
|
58
59
|
--image <image> Docker image (default: python:3.11-slim)
|
|
59
60
|
--count <n> Number of GPUs (default: 1)
|
|
60
61
|
--region US|EU|AU Region preference
|
|
61
|
-
--tier 1|2 Provider tier: 1 = reliable (default), 2 = budget
|
|
62
62
|
--max-price <$/hr> Hard spend cap per GPU-hour
|
|
63
63
|
--max-runtime <min> Auto-stop after N minutes (recommended)
|
|
64
64
|
--max-cost <$> Auto-stop when spend reaches this amount
|
|
@@ -66,10 +66,10 @@ ${chalk.bold('badgr run OPTIONS')}
|
|
|
66
66
|
|
|
67
67
|
${chalk.bold('badgr serve OPTIONS')}
|
|
68
68
|
--gpu <type> GPU type (default: auto — inferred from model size)
|
|
69
|
-
--
|
|
69
|
+
--tier 1 Managed provider routing (default)
|
|
70
|
+
--tier 2 Marketplace provider routing, lower-cost options
|
|
70
71
|
--count <n> Number of GPUs (default: 1)
|
|
71
72
|
--region US|EU|AU Region preference
|
|
72
|
-
--tier 1|2 Provider tier: 1 = reliable (default), 2 = budget
|
|
73
73
|
--max-price <$/hr> Hard spend cap per GPU-hour
|
|
74
74
|
--no-wait Skip endpoint health check
|
|
75
75
|
|
|
@@ -103,7 +103,7 @@ async function main() {
|
|
|
103
103
|
case 'receipts': return receiptsCommand(config, rest, chalk);
|
|
104
104
|
case 'models': return modelsCommand(config, chalk);
|
|
105
105
|
case 'capacity': return capacityCommand(config, rest, chalk);
|
|
106
|
-
case 'test': return testCommand(config, chalk);
|
|
106
|
+
case 'test': return testCommand(config, rest, chalk);
|
|
107
107
|
// legacy aliases kept for compatibility
|
|
108
108
|
case 'up': return upCommand(config, rest, chalk);
|
|
109
109
|
case 'config': {
|
package/src/commands/run.js
CHANGED
|
@@ -18,7 +18,6 @@ export function parseRunArgs(args) {
|
|
|
18
18
|
if (args[i] === '--count') { flags.count = parseInt(args[++i], 10); i++; continue; }
|
|
19
19
|
if (args[i] === '--region') { flags.region = args[++i]; i++; continue; }
|
|
20
20
|
if (args[i] === '--tier') { flags.tier = args[++i]; i++; continue; }
|
|
21
|
-
if (args[i] === '--cheap') { flags.cheap = true; i++; continue; }
|
|
22
21
|
if (args[i] === '--max-price') { flags.maxPrice = parseFloat(args[++i]); i++; continue; }
|
|
23
22
|
if (args[i] === '--name') { flags.name = args[++i]; i++; continue; }
|
|
24
23
|
if (args[i] === '--detach') { flags.detach = true; i++; continue; }
|
|
@@ -349,9 +348,8 @@ export async function runCommand(config, args, chalk) {
|
|
|
349
348
|
const maxRuntimeMs = flags.maxRuntime ? flags.maxRuntime * 60 * 1000 : null;
|
|
350
349
|
const maxCost = flags.maxCost ?? null;
|
|
351
350
|
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
const effectiveTier = (flags.cheap || flags.tier === '2' || flags.tier === 'tier2' || flags.tier === 'tier-2')
|
|
351
|
+
// Tier 1 = managed routing (default). Tier 2 = marketplace routing, opt-in via --tier 2.
|
|
352
|
+
const effectiveTier = (flags.tier === '2' || flags.tier === 'tier2' || flags.tier === 'tier-2')
|
|
355
353
|
? '2'
|
|
356
354
|
: (flags.tier || '1');
|
|
357
355
|
|
|
@@ -367,7 +365,7 @@ export async function runCommand(config, args, chalk) {
|
|
|
367
365
|
console.log(chalk.bold(`\n⚡ Running ${workloadLabel}\n`));
|
|
368
366
|
if (command) console.log(` ${chalk.bold('Command:')} ${command.join(' ')}`);
|
|
369
367
|
if (image) console.log(` ${chalk.bold('Image:')} ${image}`);
|
|
370
|
-
if (effectiveTier === '2') console.log(` ${chalk.dim('(
|
|
368
|
+
if (effectiveTier === '2') console.log(` ${chalk.dim('(tier 2 — marketplace routing)')}`)
|
|
371
369
|
console.log();
|
|
372
370
|
process.stdout.write(chalk.dim(' Finding best GPU...'));
|
|
373
371
|
|
|
@@ -394,7 +392,7 @@ export async function runCommand(config, args, chalk) {
|
|
|
394
392
|
|
|
395
393
|
if (effectiveTier === '2' && process.stdin.isTTY) {
|
|
396
394
|
// Budget mode: confirm because the user is being routed to a less reliable provider.
|
|
397
|
-
const answer = await askConfirm(` Press ${chalk.bold('Enter')} to run on
|
|
395
|
+
const answer = await askConfirm(` Press ${chalk.bold('Enter')} to run on tier 2 (marketplace), or ${chalk.bold('q')} to cancel: `);
|
|
398
396
|
if (answer.toLowerCase() === 'q') {
|
|
399
397
|
console.log(chalk.dim('\n Cancelled.\n'));
|
|
400
398
|
process.exit(0);
|
|
@@ -459,20 +457,20 @@ export async function runCommand(config, args, chalk) {
|
|
|
459
457
|
process.exit(1);
|
|
460
458
|
}
|
|
461
459
|
|
|
462
|
-
// Tier 1
|
|
460
|
+
// Tier 1 out of capacity — offer tier 2 marketplace routing.
|
|
463
461
|
if (process.stdin.isTTY) {
|
|
464
462
|
const answer = await askConfirm(
|
|
465
|
-
`\n
|
|
463
|
+
`\n No tier 1 capacity available. Try tier 2 marketplace routing? [${chalk.bold('Enter')}/${chalk.bold('q')}]: `
|
|
466
464
|
);
|
|
467
465
|
if (answer.toLowerCase() === 'q') {
|
|
468
466
|
console.log(chalk.dim('\n Cancelled.\n'));
|
|
469
467
|
process.exit(0);
|
|
470
468
|
}
|
|
471
469
|
} else {
|
|
472
|
-
console.log(chalk.dim('\n
|
|
470
|
+
console.log(chalk.dim('\n No tier 1 capacity — trying tier 2 marketplace routing...\n'));
|
|
473
471
|
}
|
|
474
472
|
|
|
475
|
-
console.log(chalk.dim(' Searching
|
|
473
|
+
console.log(chalk.dim(' Searching tier 2 capacity...'));
|
|
476
474
|
try {
|
|
477
475
|
dep = await callApi('/run', {
|
|
478
476
|
method: 'POST',
|
|
@@ -487,13 +485,14 @@ export async function runCommand(config, args, chalk) {
|
|
|
487
485
|
console.error(chalk.dim(' Try `badgr capacity` to see what\'s available, or try again shortly.'));
|
|
488
486
|
} else if (d2?.code === 'PROVISIONING_FAILED' || d2?.code === 'PROVIDER_ADAPTER_ERROR') {
|
|
489
487
|
console.error(chalk.red(`\n ✗ Budget provider found capacity but could not start the machine. Please try again.\n`));
|
|
488
|
+
// (error detail kept below)
|
|
490
489
|
if (process.env.BADGR_DEBUG === '1' || process.env.BADGR_DEBUG === 'true') {
|
|
491
490
|
if (d2?.debug_error) console.error(chalk.dim(` Provider detail: ${d2.debug_error}`));
|
|
492
491
|
} else {
|
|
493
492
|
console.error(chalk.dim(` Run BADGR_DEBUG=1 badgr run … for a full trace.\n`));
|
|
494
493
|
}
|
|
495
494
|
} else {
|
|
496
|
-
console.error(chalk.red(`\n ✗ Could not start job on
|
|
495
|
+
console.error(chalk.red(`\n ✗ Could not start job on tier 2: ${err2.message}\n`));
|
|
497
496
|
console.error(chalk.dim(` Run BADGR_DEBUG=1 badgr run … for a full trace.`));
|
|
498
497
|
}
|
|
499
498
|
process.exit(1);
|
package/src/commands/serve.js
CHANGED
|
@@ -23,7 +23,6 @@ export function parseServeArgs(args) {
|
|
|
23
23
|
if (args[i] === '--count') { flags.count = parseInt(args[++i], 10); i++; continue; }
|
|
24
24
|
if (args[i] === '--region') { flags.region = args[++i]; i++; continue; }
|
|
25
25
|
if (args[i] === '--tier') { flags.tier = args[++i]; i++; continue; }
|
|
26
|
-
if (args[i] === '--cheap') { flags.cheap = true; i++; continue; }
|
|
27
26
|
if (args[i] === '--max-price') { flags.maxPrice = parseFloat(args[++i]); i++; continue; }
|
|
28
27
|
if (args[i] === '--name') { flags.name = args[++i]; i++; continue; }
|
|
29
28
|
if (args[i] === '--no-wait') { flags.noWait = true; i++; continue; }
|
|
@@ -75,15 +74,15 @@ export async function serveCommand(config, args, chalk) {
|
|
|
75
74
|
const gpu = flags.gpu ? flags.gpu.toUpperCase().replace('-', '_') : 'AUTO';
|
|
76
75
|
const gpuLabel = gpu === 'AUTO' ? 'auto' : gpu;
|
|
77
76
|
|
|
78
|
-
//
|
|
79
|
-
const effectiveTier = (flags.
|
|
77
|
+
// Tier 1 = managed routing (default). Tier 2 = marketplace routing, opt-in via --tier 2.
|
|
78
|
+
const effectiveTier = (flags.tier === '2' || flags.tier === 'tier2' || flags.tier === 'tier-2')
|
|
80
79
|
? '2'
|
|
81
80
|
: (flags.tier || '1');
|
|
82
81
|
|
|
83
82
|
console.log(chalk.bold('\nServing model\n'));
|
|
84
83
|
console.log(` ${chalk.bold('Model:')} ${model}`);
|
|
85
84
|
console.log(` ${chalk.bold('GPU:')} ${gpuLabel}`);
|
|
86
|
-
if (effectiveTier === '2') console.log(` ${chalk.dim('(
|
|
85
|
+
if (effectiveTier === '2') console.log(` ${chalk.dim('(tier 2 — marketplace routing)')}`);
|
|
87
86
|
console.log();
|
|
88
87
|
process.stdout.write(chalk.dim(' Finding GPU capacity...\n'));
|
|
89
88
|
|
|
@@ -118,20 +117,20 @@ export async function serveCommand(config, args, chalk) {
|
|
|
118
117
|
process.exit(1);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
// Tier 1
|
|
120
|
+
// Tier 1 out of capacity — offer tier 2 marketplace routing.
|
|
122
121
|
if (process.stdin.isTTY) {
|
|
123
122
|
const answer = await askConfirm(
|
|
124
|
-
`\n
|
|
123
|
+
`\n No tier 1 capacity available. Try tier 2 marketplace routing? [${chalk.bold('Enter')}/${chalk.bold('q')}]: `
|
|
125
124
|
);
|
|
126
125
|
if (answer.toLowerCase() === 'q') {
|
|
127
126
|
console.log(chalk.dim('\n Cancelled.\n'));
|
|
128
127
|
process.exit(0);
|
|
129
128
|
}
|
|
130
129
|
} else {
|
|
131
|
-
console.log(chalk.dim('\n
|
|
130
|
+
console.log(chalk.dim('\n No tier 1 capacity — trying tier 2 marketplace routing...\n'));
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
console.log(chalk.dim(' Searching
|
|
133
|
+
console.log(chalk.dim(' Searching tier 2 capacity...'));
|
|
135
134
|
try {
|
|
136
135
|
dep = await callApi('/serve', {
|
|
137
136
|
method: 'POST',
|
|
@@ -148,7 +147,7 @@ export async function serveCommand(config, args, chalk) {
|
|
|
148
147
|
console.error(chalk.red(`\n ✗ Budget provider found capacity but could not start the endpoint. Please try again.\n`));
|
|
149
148
|
console.error(chalk.dim(` Run BADGR_DEBUG=1 badgr serve … for a full trace.\n`));
|
|
150
149
|
} else {
|
|
151
|
-
console.error(chalk.red(`\n ✗
|
|
150
|
+
console.error(chalk.red(`\n ✗ Could not start endpoint on tier 2: ${err2.message}\n`));
|
|
152
151
|
console.error(chalk.dim(` Run BADGR_DEBUG=1 badgr serve … for a full trace.\n`));
|
|
153
152
|
}
|
|
154
153
|
process.exit(1);
|
package/src/commands/test-run.js
CHANGED
|
@@ -9,6 +9,20 @@ const TEST_COMMAND = ['python', '-c', "print('hello from badgr')"];
|
|
|
9
9
|
const TEST_IMAGE = 'python:3.11-slim';
|
|
10
10
|
const EXPECTED_OUTPUT = 'hello from badgr';
|
|
11
11
|
|
|
12
|
+
// --provider flag resolves to a backend tier value.
|
|
13
|
+
// 'tier1' → managed routing (default), 'tier2' → marketplace routing, 'secondary' → secondary dispatch.
|
|
14
|
+
const PROVIDER_TO_TIER = { tier1: '1', tier2: '2', secondary: 'modal' };
|
|
15
|
+
|
|
16
|
+
export function parseTestArgs(args) {
|
|
17
|
+
const flags = {};
|
|
18
|
+
let i = 0;
|
|
19
|
+
while (i < args.length) {
|
|
20
|
+
if (args[i] === '--provider' && args[i + 1]) { flags.provider = args[++i]; i++; continue; }
|
|
21
|
+
i++;
|
|
22
|
+
}
|
|
23
|
+
return flags;
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
function step(chalk, ok, msg, detail = '') {
|
|
13
27
|
const icon = ok ? chalk.green('✓') : chalk.red('✗');
|
|
14
28
|
const suffix = detail ? chalk.dim(` — ${detail}`) : '';
|
|
@@ -46,12 +60,40 @@ async function pollLogs(config, depId, expected, timeoutMs) {
|
|
|
46
60
|
return false;
|
|
47
61
|
}
|
|
48
62
|
|
|
49
|
-
export async function testCommand(config, chalk) {
|
|
63
|
+
export async function testCommand(config, args, chalk) {
|
|
50
64
|
requireApiKey(config);
|
|
51
65
|
|
|
66
|
+
const flags = parseTestArgs(Array.isArray(args) ? args : []);
|
|
67
|
+
const providerKey = flags.provider ? flags.provider.toLowerCase() : 'tier1';
|
|
68
|
+
|
|
69
|
+
if (providerKey === 'secondary') {
|
|
70
|
+
// Secondary dispatch provider uses a webhook model, not direct GPU rental.
|
|
71
|
+
// Verify the backend reports it as configured.
|
|
72
|
+
console.log(chalk.bold('\n⚡ Testing secondary dispatch provider\n'));
|
|
73
|
+
let routes;
|
|
74
|
+
try {
|
|
75
|
+
routes = await callApi('/compute/routes', { apiKey: config.apiKey, baseUrl: config.baseUrl });
|
|
76
|
+
} catch {
|
|
77
|
+
routes = null;
|
|
78
|
+
}
|
|
79
|
+
const secondaryRoute = Array.isArray(routes) ? routes.find(r => r.name === 'modal') : null;
|
|
80
|
+
if (secondaryRoute?.available) {
|
|
81
|
+
step(chalk, true, 'Secondary provider configured');
|
|
82
|
+
console.log(chalk.green('\n ✓ Secondary dispatch provider is ready\n'));
|
|
83
|
+
} else {
|
|
84
|
+
step(chalk, false, 'Secondary provider configured', 'contact support to enable secondary dispatch');
|
|
85
|
+
console.log(chalk.red('\n ✗ Secondary dispatch provider is not configured\n'));
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const tier = PROVIDER_TO_TIER[providerKey] ?? '1';
|
|
92
|
+
const tierLabel = tier === '1' ? 'tier 1 (managed routing)' : 'tier 2 (marketplace routing)';
|
|
93
|
+
|
|
52
94
|
console.log(chalk.bold('\n⚡ Running end-to-end test\n'));
|
|
53
95
|
console.log(chalk.dim(` Command: ${TEST_COMMAND.join(' ')}`));
|
|
54
|
-
console.log(chalk.dim(`
|
|
96
|
+
console.log(chalk.dim(` Routing: ${tier === '1' ? 'tier 1 — managed provider routing' : 'tier 2 — marketplace routing'}`));
|
|
55
97
|
console.log(chalk.dim(` Budget: max $${TEST_MAX_PRICE.toFixed(2)}/hr · 2 minute cap (~$0.05 max)`));
|
|
56
98
|
console.log();
|
|
57
99
|
|
|
@@ -59,7 +101,7 @@ export async function testCommand(config, chalk) {
|
|
|
59
101
|
let depId;
|
|
60
102
|
|
|
61
103
|
// ── 1. Provision ─────────────────────────────────────────────────────────
|
|
62
|
-
process.stdout.write(chalk.dim(
|
|
104
|
+
process.stdout.write(chalk.dim(` Provisioning GPU (${tierLabel})...\n`));
|
|
63
105
|
let dep;
|
|
64
106
|
const baseBody = {
|
|
65
107
|
command: TEST_COMMAND,
|
|
@@ -72,12 +114,12 @@ export async function testCommand(config, chalk) {
|
|
|
72
114
|
method: 'POST',
|
|
73
115
|
apiKey: config.apiKey,
|
|
74
116
|
baseUrl: config.baseUrl,
|
|
75
|
-
body: { ...baseBody, tier
|
|
117
|
+
body: { ...baseBody, tier },
|
|
76
118
|
});
|
|
77
119
|
} catch (err) {
|
|
78
|
-
if (err.errorData?.code === 'NO_CAPACITY_MATCH') {
|
|
120
|
+
if (err.errorData?.code === 'NO_CAPACITY_MATCH' && tier === '1') {
|
|
79
121
|
process.stdout.write('\n');
|
|
80
|
-
process.stdout.write(chalk.dim('
|
|
122
|
+
process.stdout.write(chalk.dim(' No tier 1 capacity — trying tier 2 marketplace routing...'));
|
|
81
123
|
try {
|
|
82
124
|
dep = await callApi('/run', {
|
|
83
125
|
method: 'POST',
|
package/tests/commands.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { parseRunArgs, classifyFailure, inferWorkload } from '../src/commands/run.js';
|
|
3
3
|
import { parseServeArgs } from '../src/commands/serve.js';
|
|
4
|
-
import { testCommand } from '../src/commands/test-run.js';
|
|
4
|
+
import { testCommand, parseTestArgs } from '../src/commands/test-run.js';
|
|
5
5
|
import { rankAlternatives, diffDescription, promptFallback } from '../src/fallback.js';
|
|
6
6
|
|
|
7
7
|
describe('parseRunArgs', () => {
|
|
@@ -73,20 +73,15 @@ describe('parseRunArgs', () => {
|
|
|
73
73
|
expect(flags.maxCost).toBe(5.0);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
it('parses --cheap flag', () => {
|
|
77
|
-
const { flags } = parseRunArgs(['python', 'train.py', '--cheap']);
|
|
78
|
-
expect(flags.cheap).toBe(true);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('--cheap defaults to falsy when not passed', () => {
|
|
82
|
-
const { flags } = parseRunArgs(['python', 'train.py']);
|
|
83
|
-
expect(flags.cheap).toBeFalsy();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
76
|
it('parses --tier 2 flag', () => {
|
|
87
77
|
const { flags } = parseRunArgs(['python', 'train.py', '--tier', '2']);
|
|
88
78
|
expect(flags.tier).toBe('2');
|
|
89
79
|
});
|
|
80
|
+
|
|
81
|
+
it('--tier defaults to undefined when not passed', () => {
|
|
82
|
+
const { flags } = parseRunArgs(['python', 'train.py']);
|
|
83
|
+
expect(flags.tier).toBeUndefined();
|
|
84
|
+
});
|
|
90
85
|
});
|
|
91
86
|
|
|
92
87
|
describe('classifyFailure', () => {
|
|
@@ -204,14 +199,14 @@ describe('parseServeArgs', () => {
|
|
|
204
199
|
expect(model).toBeNull();
|
|
205
200
|
});
|
|
206
201
|
|
|
207
|
-
it('parses --
|
|
208
|
-
const { flags } = parseServeArgs(['my/model', '--
|
|
209
|
-
expect(flags.
|
|
202
|
+
it('parses --tier 2 flag', () => {
|
|
203
|
+
const { flags } = parseServeArgs(['my/model', '--tier', '2']);
|
|
204
|
+
expect(flags.tier).toBe('2');
|
|
210
205
|
});
|
|
211
206
|
|
|
212
|
-
it('--
|
|
207
|
+
it('--tier defaults to undefined when not passed', () => {
|
|
213
208
|
const { flags } = parseServeArgs(['my/model']);
|
|
214
|
-
expect(flags.
|
|
209
|
+
expect(flags.tier).toBeUndefined();
|
|
215
210
|
});
|
|
216
211
|
});
|
|
217
212
|
|
|
@@ -221,6 +216,24 @@ describe('testCommand', () => {
|
|
|
221
216
|
});
|
|
222
217
|
});
|
|
223
218
|
|
|
219
|
+
describe('parseTestArgs', () => {
|
|
220
|
+
it('returns empty flags for no args', () => {
|
|
221
|
+
expect(parseTestArgs([])).toEqual({});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('parses --provider tier1', () => {
|
|
225
|
+
expect(parseTestArgs(['--provider', 'tier1'])).toEqual({ provider: 'tier1' });
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('parses --provider tier2', () => {
|
|
229
|
+
expect(parseTestArgs(['--provider', 'tier2'])).toEqual({ provider: 'tier2' });
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('parses --provider secondary', () => {
|
|
233
|
+
expect(parseTestArgs(['--provider', 'secondary'])).toEqual({ provider: 'secondary' });
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
224
237
|
describe('inferWorkload', () => {
|
|
225
238
|
it('returns general for empty command', () => {
|
|
226
239
|
expect(inferWorkload([])).toBe('general');
|