|
1 | 1 | import * as path from 'path';
|
2 | 2 | import { IExtensionContext } from '../../extension/common/types';
|
3 |
| -import { registerConfiglessDebug } from '../../extension/noConfigDebugInit'; |
| 3 | +import { registerNoConfigDebug as registerNoConfigDebug } from '../../extension/noConfigDebugInit'; |
4 | 4 | import * as TypeMoq from 'typemoq';
|
5 | 5 | import * as sinon from 'sinon';
|
6 |
| -import { Uri } from 'vscode'; |
| 6 | +import { DebugConfiguration, DebugSessionOptions, RelativePattern, Uri } from 'vscode'; |
7 | 7 | import * as utils from '../../extension/utils';
|
8 | 8 | import { assert } from 'console';
|
9 | 9 | import * as fs from 'fs';
|
10 | 10 |
|
11 |
| -suite('registerConfiglessDebug', function () { |
12 |
| - this.timeout(100000); // Increase timeout to 10 seconds |
13 |
| - let replaceStub: sinon.SinonStub; |
14 |
| - let appendStub: sinon.SinonStub; |
| 11 | +suite('setup for no-config debug scenario', function () { |
| 12 | + let envVarCollectionReplaceStub: sinon.SinonStub; |
| 13 | + let envVarCollectionAppendStub: sinon.SinonStub; |
15 | 14 | let context: TypeMoq.IMock<IExtensionContext>;
|
16 |
| - let createFileSystemWatcher: sinon.SinonStub; |
| 15 | + let debugAdapterEndpointDir: string; |
| 16 | + let debuggerAdapterEndpointPath: string; |
| 17 | + let noConfigScriptsDir: string; |
| 18 | + let bundledDebugPath: string; |
| 19 | + let DEBUGPY_ADAPTER_ENDPOINTS = 'DEBUGPY_ADAPTER_ENDPOINTS'; |
| 20 | + let BUNDLED_DEBUGPY_PATH = 'BUNDLED_DEBUGPY_PATH'; |
17 | 21 |
|
| 22 | + const testDataDir = path.join(__dirname, 'testData'); |
| 23 | + const testFilePath = path.join(testDataDir, 'debuggerAdapterEndpoint.txt'); |
| 24 | + suiteSetup(() => { |
| 25 | + // create file called testData/debuggerAdapterEndpoint.txt |
| 26 | + if (!fs.existsSync(testDataDir)) { |
| 27 | + fs.mkdirSync(testDataDir); |
| 28 | + } |
| 29 | + fs.writeFileSync(testFilePath, JSON.stringify({ client: { port: 5678 } })); |
| 30 | + }); |
18 | 31 | setup(() => {
|
19 | 32 | context = TypeMoq.Mock.ofType<IExtensionContext>();
|
20 | 33 |
|
21 |
| - context.setup((c) => c.storageUri).returns(() => Uri.parse('a')); |
22 |
| - context.setup((c) => (c as any).extensionPath).returns(() => 'b'); |
| 34 | + context.setup((c) => (c as any).extensionPath).returns(() => 'fake/extension/path'); |
23 | 35 | context.setup((c) => c.subscriptions).returns(() => []);
|
24 |
| - |
25 |
| - createFileSystemWatcher = sinon.stub(utils, 'createFileSystemWatcher'); |
26 |
| - createFileSystemWatcher.callsFake(() => { |
27 |
| - return { |
28 |
| - onDidCreate: (cb: (arg0: Uri) => void) => { |
29 |
| - cb(Uri.parse('a')); |
30 |
| - }, |
31 |
| - }; |
32 |
| - }); |
33 |
| - sinon.stub(fs, 'readFile').callsFake( |
34 |
| - (TypeMoq.It.isAny(), |
35 |
| - TypeMoq.It.isAny(), |
36 |
| - (err, data) => { |
37 |
| - console.log(err, data); |
38 |
| - }), |
39 |
| - ); |
| 36 | + debugAdapterEndpointDir = path.join(context.object.extensionPath, 'noConfigDebugAdapterEndpoints'); |
| 37 | + debuggerAdapterEndpointPath = path.join(debugAdapterEndpointDir, 'debuggerAdapterEndpoint.txt'); |
| 38 | + noConfigScriptsDir = path.join(context.object.extensionPath, 'bundled/scripts/noConfigScripts'); |
| 39 | + bundledDebugPath = path.join(context.object.extensionPath, 'bundled/libs/debugpy'); |
40 | 40 | });
|
41 | 41 | teardown(() => {
|
42 | 42 | sinon.restore();
|
43 | 43 | });
|
| 44 | + suiteTeardown(() => { |
| 45 | + if (fs.existsSync(testDataDir)) { |
| 46 | + fs.rmSync(testDataDir, { recursive: true, force: true }); |
| 47 | + } |
| 48 | + }); |
44 | 49 |
|
45 | 50 | test('should add environment variables for DEBUGPY_ADAPTER_ENDPOINTS, BUNDLED_DEBUGPY_PATH, and PATH', async () => {
|
46 |
| - const debugAdapterEndpointDir = path.join(context.object.extensionPath, 'noConfigDebugAdapterEndpoints'); |
47 |
| - const debuggerAdapterEndpointPath = path.join(debugAdapterEndpointDir, 'debuggerAdapterEndpoint.txt'); |
48 |
| - const noConfigScriptsDir = path.join(context.object.extensionPath, 'bundled/scripts/noConfigScripts'); |
49 |
| - const bundledDebugPath = path.join(context.object.extensionPath, 'bundled/libs/debugpy'); |
50 |
| - |
51 | 51 | const environmentVariableCollectionMock = TypeMoq.Mock.ofType<any>();
|
52 |
| - replaceStub = sinon.stub(); |
53 |
| - appendStub = sinon.stub(); |
| 52 | + envVarCollectionReplaceStub = sinon.stub(); |
| 53 | + envVarCollectionAppendStub = sinon.stub(); |
| 54 | + |
| 55 | + // set up the environment variable collection mock including asserts for the key, value pairs |
54 | 56 | environmentVariableCollectionMock
|
55 | 57 | .setup((x) => x.replace(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
56 | 58 | .callback((key, value) => {
|
57 |
| - if (key === 'DEBUGPY_ADAPTER_ENDPOINTS') { |
| 59 | + if (key === DEBUGPY_ADAPTER_ENDPOINTS) { |
58 | 60 | assert(value === debuggerAdapterEndpointPath);
|
59 |
| - } else if (key === 'BUNDLED_DEBUGPY_PATH') { |
| 61 | + } else if (key === BUNDLED_DEBUGPY_PATH) { |
60 | 62 | assert(value === bundledDebugPath);
|
61 | 63 | }
|
62 | 64 | })
|
63 |
| - .returns(replaceStub); |
| 65 | + .returns(envVarCollectionReplaceStub); |
64 | 66 | environmentVariableCollectionMock
|
65 | 67 | .setup((x) => x.append(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
66 | 68 | .callback((key, value) => {
|
67 | 69 | if (key === 'PATH') {
|
68 | 70 | assert(value === `:${noConfigScriptsDir}`);
|
69 | 71 | }
|
70 | 72 | })
|
71 |
| - .returns(appendStub); |
| 73 | + .returns(envVarCollectionAppendStub); |
| 74 | + |
| 75 | + context.setup((c) => c.environmentVariableCollection).returns(() => environmentVariableCollectionMock.object); |
| 76 | + |
| 77 | + setupFileSystemWatchers(); |
| 78 | + |
| 79 | + // run init for no config debug |
| 80 | + await registerNoConfigDebug(context.object); |
| 81 | + |
| 82 | + // assert that functions called right number of times |
| 83 | + sinon.assert.calledTwice(envVarCollectionReplaceStub); |
| 84 | + sinon.assert.calledOnce(envVarCollectionAppendStub); |
| 85 | + }); |
| 86 | + |
| 87 | + test('should create file system watcher for debuggerAdapterEndpointFolder', async () => { |
| 88 | + // Arrange |
| 89 | + const environmentVariableCollectionMock = TypeMoq.Mock.ofType<any>(); |
| 90 | + context.setup((c) => c.environmentVariableCollection).returns(() => environmentVariableCollectionMock.object); |
| 91 | + let createFileSystemWatcherFunct = setupFileSystemWatchers(); |
72 | 92 |
|
| 93 | + // Act |
| 94 | + await registerNoConfigDebug(context.object); |
| 95 | + |
| 96 | + // Assert |
| 97 | + sinon.assert.calledOnce(createFileSystemWatcherFunct); |
| 98 | + const expectedPattern = new RelativePattern(debugAdapterEndpointDir, '**/*'); |
| 99 | + sinon.assert.calledWith(createFileSystemWatcherFunct, expectedPattern); |
| 100 | + }); |
| 101 | + |
| 102 | + test('should start debug session with client port', async () => { |
| 103 | + // Arrange |
| 104 | + const environmentVariableCollectionMock = TypeMoq.Mock.ofType<any>(); |
73 | 105 | context.setup((c) => c.environmentVariableCollection).returns(() => environmentVariableCollectionMock.object);
|
74 | 106 |
|
75 |
| - await registerConfiglessDebug(context.object); |
76 |
| - console.log('All done!'); |
77 |
| - sinon.assert.calledTwice(replaceStub); |
| 107 | + // mock file sys watcher to give back test file |
| 108 | + let createFileSystemWatcherFunct: sinon.SinonStub; |
| 109 | + createFileSystemWatcherFunct = sinon.stub(utils, 'createFileSystemWatcher'); |
| 110 | + createFileSystemWatcherFunct.callsFake(() => { |
| 111 | + return { |
| 112 | + onDidCreate: (callback: (arg0: Uri) => void) => { |
| 113 | + callback(Uri.parse(testFilePath)); |
| 114 | + }, |
| 115 | + }; |
| 116 | + }); |
| 117 | + |
| 118 | + // create stub of fs.readFile function |
| 119 | + sinon.stub(fs, 'readFile').callsFake((_path: any, callback: (arg0: null, arg1: Buffer) => void) => { |
| 120 | + console.log('reading file'); |
| 121 | + callback(null, Buffer.from(JSON.stringify({ client: { port: 5678 } }))); |
| 122 | + }); |
| 123 | + |
| 124 | + const debugStub = sinon.stub(utils, 'debugStartDebugging').resolves(true); |
| 125 | + |
| 126 | + // Act |
| 127 | + await registerNoConfigDebug(context.object); |
| 128 | + |
| 129 | + // Assert |
| 130 | + sinon.assert.calledOnce(debugStub); |
| 131 | + const expectedConfig: DebugConfiguration = { |
| 132 | + type: 'python', |
| 133 | + request: 'attach', |
| 134 | + name: 'Attach to Python', |
| 135 | + port: 5678, |
| 136 | + host: 'localhost', |
| 137 | + }; |
| 138 | + const optionsExpected: DebugSessionOptions = { |
| 139 | + noDebug: false, |
| 140 | + }; |
| 141 | + const actualConfig = debugStub.getCall(0).args[1]; |
| 142 | + const actualOptions = debugStub.getCall(0).args[2]; |
| 143 | + |
| 144 | + if (JSON.stringify(actualConfig) !== JSON.stringify(expectedConfig)) { |
| 145 | + console.log('Config diff:', { |
| 146 | + expected: expectedConfig, |
| 147 | + actual: actualConfig, |
| 148 | + }); |
| 149 | + } |
| 150 | + |
| 151 | + if (JSON.stringify(actualOptions) !== JSON.stringify(optionsExpected)) { |
| 152 | + console.log('Options diff:', { |
| 153 | + expected: optionsExpected, |
| 154 | + actual: actualOptions, |
| 155 | + }); |
| 156 | + } |
| 157 | + |
| 158 | + sinon.assert.calledWith(debugStub, undefined, expectedConfig, optionsExpected); |
78 | 159 | });
|
79 | 160 | });
|
| 161 | + |
| 162 | +function setupFileSystemWatchers(): sinon.SinonStub { |
| 163 | + // create stub of createFileSystemWatcher function that will return a fake watcher with a callback |
| 164 | + let createFileSystemWatcherFunct: sinon.SinonStub; |
| 165 | + createFileSystemWatcherFunct = sinon.stub(utils, 'createFileSystemWatcher'); |
| 166 | + createFileSystemWatcherFunct.callsFake(() => { |
| 167 | + return { |
| 168 | + onDidCreate: (callback: (arg0: Uri) => void) => { |
| 169 | + callback(Uri.parse('fake/debuggerAdapterEndpoint.txt')); |
| 170 | + }, |
| 171 | + }; |
| 172 | + }); |
| 173 | + // create stub of fs.readFile function |
| 174 | + sinon.stub(fs, 'readFile').callsFake( |
| 175 | + (TypeMoq.It.isAny(), |
| 176 | + TypeMoq.It.isAny(), |
| 177 | + (err, data) => { |
| 178 | + console.log(err, data); |
| 179 | + }), |
| 180 | + ); |
| 181 | + return createFileSystemWatcherFunct; |
| 182 | +} |
0 commit comments