File size: 5,094 Bytes
32151b6
 
 
 
 
 
 
 
 
 
3e8ea5d
32151b6
 
 
3e8ea5d
32151b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3e8ea5d
 
 
 
 
 
 
 
 
 
 
 
 
 
32151b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3e8ea5d
32151b6
3e8ea5d
 
 
 
 
32151b6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3e8ea5d
 
32151b6
 
3e8ea5d
 
 
 
 
 
 
32151b6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { resolve } from 'node:path';
import { pathToFileURL } from 'node:url';

import {
    assertKnownOptions,
    assertSpaceTargetConfig,
    buildNextActions,
    classifyRequiredAndRecommendedNames,
    getJsonKeyValues,
    getJsonNames,
    isMainModule,
    readOptionValue,
    runDoctorCommand,
    validateSpaceId,
    validateSpaceUrl
} from './hf-space-doctor-utils.mjs';

describe('HF Space doctor utilities', () => {
    it('parses hf CLI JSON output after hint lines', () => {
        const names = getJsonNames(
            [
                'Hint: Use `hf spaces variables add user/space -e KEY=VALUE` to add variables.',
                '[{"key":"APP_PASSWORD"},{"key":"AGENT_API_TOKEN"}]'
            ].join('\n')
        );

        assert.deepEqual([...names], ['APP_PASSWORD', 'AGENT_API_TOKEN']);
    });

    it('does not treat square brackets in hint text as JSON', () => {
        const names = getJsonNames(
            [
                'Hint: Usage: hf spaces secrets list [OPTIONS] SPACE_ID',
                '[{"key":"OPENAI_API_KEY"}]'
            ].join('\n')
        );

        assert.deepEqual([...names], ['OPENAI_API_KEY']);
    });

    it('parses hf CLI variable values after hint lines', () => {
        const values = getJsonKeyValues(
            [
                'Hint: Use `hf spaces variables add user/space -e KEY=VALUE` to add variables.',
                '[{"key":"AGENT_STATE_BACKEND","value":"memory"},{"key":"NEXT_PUBLIC_IMAGE_STORAGE_MODE","value":"indexeddb"}]'
            ].join('\n')
        );

        assert.deepEqual([...values], [
            ['AGENT_STATE_BACKEND', 'memory'],
            ['NEXT_PUBLIC_IMAGE_STORAGE_MODE', 'indexeddb']
        ]);
    });

    it('keeps auth remediation broad enough for network and token failures', () => {
        const actions = buildNextActions([
            {
                status: 'fail',
                name: 'hf-auth',
                message: 'hf CLI auth check failed.',
                error: 'TLS failed while checking auth'
            }
        ]);

        assert.equal(actions.length, 1);
        assert.match(actions[0], /network\/proxy/);
        assert.match(actions[0], /hf auth login/);
    });

    it('classifies required and recommended remote variables separately', () => {
        const result = classifyRequiredAndRecommendedNames(
            new Set(['AGENT_STATE_BACKEND', 'NEXT_PUBLIC_IMAGE_STORAGE_MODE']),
            ['AGENT_STATE_BACKEND', 'NEXT_PUBLIC_IMAGE_STORAGE_MODE'],
            ['APP_LOG_LEVEL']
        );

        assert.deepEqual(result, {
            missingRequired: [],
            missingRecommended: ['APP_LOG_LEVEL']
        });
    });

    it('detects the main module with file URL encoding', () => {
        const argvPath = 'scripts/path with space.mjs';
        const moduleUrl = pathToFileURL(resolve(argvPath)).href;

        assert.equal(isMainModule(moduleUrl, argvPath), true);
        assert.equal(isMainModule(moduleUrl, undefined), false);
    });

    it('validates Hugging Face Space target config consistently', () => {
        assert.equal(validateSpaceId('example/demo'), undefined);
        assert.equal(validateSpaceId('demo'), undefined);
        assert.equal(validateSpaceUrl('https://example-demo.hf.space'), undefined);
        assert.match(validateSpaceId('a/b/c'), /space_name or namespace\/space_name/);
        assert.match(validateSpaceId('.bad/demo'), /cannot start/);
        assert.match(validateSpaceId('bad--name/demo'), /cannot start/);
        assert.match(validateSpaceId('bad.git/demo'), /cannot start/);
        assert.match(validateSpaceId(`${'a'.repeat(97)}/demo`), /1-96 characters/);
        assert.match(validateSpaceUrl('https://example.com'), /\.hf\.space/);
        assert.match(validateSpaceUrl('https://user:pass@example-demo.hf.space'), /plain Space origin/);
        assert.match(validateSpaceUrl('https://example-demo.hf.space/share/abc'), /plain Space origin/);
        assert.match(validateSpaceUrl('https://example-demo.hf.space?token=secret'), /plain Space origin/);
        assert.throws(
            () =>
                assertSpaceTargetConfig({
                    spaceId: 'example/demo',
                    spaceUrl: 'https://example.com'
                }),
            /\.hf\.space/
        );
    });

    it('rejects unknown CLI options and blank inline option values', () => {
        assert.doesNotThrow(() => assertKnownOptions(['--skip-remote'], ['--skip-remote']));
        assert.throws(() => assertKnownOptions(['--unknown'], ['--skip-remote']), /Unknown option/);
        assert.throws(() => readOptionValue(['--space-id='], '--space-id'), /requires a value/);
    });

    it('times out direct doctor commands instead of hanging', () => {
        const result = runDoctorCommand(process.execPath, ['-e', 'setTimeout(() => {}, 1000)'], { timeoutMs: 100 });

        assert.equal(result.ok, false);
        assert.match(result.error, /timed out|ETIMEDOUT|SIGTERM/i);
    });
});