unittest.ts 2.61 KB
Newer Older
1
2
3
4
5
6
7
8
9
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

/**
 *  Unit test helper.
 *  It should be inside "test", but must be here for compatibility, until we refactor all test cases.
 *
 *  Use this module to replace NNI globals with mocked values:
 *
10
11
12
13
 *      import 'common/globals/unittest';
 *
 *  Or:
 *
14
15
16
17
 *      import globals from 'common/globals/unittest';
 *
 *  You can then edit these mocked globals and the injection will be visible to all modules.
 *  Remember to invoke `resetGlobals()` in "after()" hook if you do so.
18
19
 *
 *  Attention: TypeScript will remove "unused" import statements. Use the first format when "globals" is never used.
20
21
22
23
24
25
26
 **/

import os from 'os';
import path from 'path';

import type { NniManagerArgs } from './arguments';
import { NniPaths, createPaths } from './paths';
27
import type { LogStream } from './log_stream';
28
29
30
31
// Enforce ts-node to import `shutdown.ts`.
// Without this line it might complain "log_1.getRobustLogger is not a function".
// "Magic. Do not touch."
import './shutdown';
32
33
34
35
36
37
38
39
40

// copied from https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
type Mutable<Type> = {
    -readonly [Property in keyof Type]: Type[Property];
};

export interface MutableGlobals {
    args: Mutable<NniManagerArgs>;
    paths: Mutable<NniPaths>;
41
42
43
    logStream: LogStream;

    reset(): void;
44
45
46
47
48
49
50
51
52
53
54
}

export function resetGlobals(): void {
    const args: NniManagerArgs = {
        port: 8080,
        experimentId: 'unittest',
        action: 'create',
        experimentsDirectory: path.join(os.homedir(), 'nni-experiments'),
        logLevel: 'info',
        foreground: false,
        urlPrefix: '',
55
        tunerCommandChannel: null,
56
        pythonInterpreter: 'python',
57
        mode: 'unittest'
58
59
    };
    const paths = createPaths(args);
60
61
62
    const logStream = {
        writeLine: (_line: string): void => { /* dummy */ },
        writeLineSync: (_line: string): void => { /* dummy */ },
63
64
65
66
        close: async (): Promise<void> => { /* dummy */ }
    };
    const shutdown = {
        register: (..._: any): void => { /* dummy */ },
67
    };
68

69
    const globalAsAny = global as any;
70
    const utGlobals = { args, paths, logStream, shutdown, reset: resetGlobals };
71
72
    if (globalAsAny.nni === undefined) {
        globalAsAny.nni = utGlobals;
73
    } else {
74
        Object.assign(globalAsAny.nni, utGlobals);
75
76
77
78
79
80
81
82
83
84
85
86
    }
}

function isUnitTest(): boolean {
    const event = process.env['npm_lifecycle_event'] ?? '';
    return event.startsWith('test') || event === 'mocha' || event === 'nyc';
}

if (isUnitTest()) {
    resetGlobals();
}

87
const globals: MutableGlobals = (global as any).nni;
88
export default globals;