mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-15 17:22:25 -05:00
Add and fix Notebook tests (#10488)
* Add and fix Notebook tests * Fix name * Fix compile * Acutally fix error * Add Notebook title test and fix command * Add extra check and add comments * Remove extra show error message
This commit is contained in:
@@ -75,7 +75,7 @@ export function executeStreamedCommand(cmd: string, options: childProcess.SpawnO
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(localize('executeCommandProcessExited', "Process exited with with error code: {0}. StdErr Output: {1}", code, stdErrLog));
|
||||
reject(new Error(localize('executeCommandProcessExited', "Process exited with error code: {0}. StdErr Output: {1}", code, stdErrLog)));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -54,12 +54,12 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
||||
});
|
||||
});
|
||||
}));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('_notebook.command.new', (context?: azdata.ConnectedContext) => {
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('_notebook.command.new', async (context?: azdata.ConnectedContext) => {
|
||||
let connectionProfile: azdata.IConnectionProfile = undefined;
|
||||
if (context && context.connectionProfile) {
|
||||
connectionProfile = context.connectionProfile;
|
||||
}
|
||||
newNotebook(connectionProfile);
|
||||
return newNotebook(connectionProfile);
|
||||
}));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.open', async () => {
|
||||
await openNotebook();
|
||||
@@ -142,10 +142,10 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
||||
};
|
||||
}
|
||||
|
||||
function newNotebook(connectionProfile: azdata.IConnectionProfile) {
|
||||
let title = findNextUntitledEditorName();
|
||||
let untitledUri = vscode.Uri.parse(`untitled:${title}`);
|
||||
let options: azdata.nb.NotebookShowOptions = connectionProfile ? {
|
||||
async function newNotebook(connectionProfile: azdata.IConnectionProfile): Promise<azdata.nb.NotebookEditor> {
|
||||
const title = findNextUntitledEditorName();
|
||||
const untitledUri = vscode.Uri.parse(`untitled:${title}`);
|
||||
const options: azdata.nb.NotebookShowOptions = connectionProfile ? {
|
||||
viewColumn: null,
|
||||
preserveFocus: true,
|
||||
preview: null,
|
||||
@@ -153,11 +153,7 @@ function newNotebook(connectionProfile: azdata.IConnectionProfile) {
|
||||
connectionProfile: connectionProfile,
|
||||
defaultKernel: null
|
||||
} : null;
|
||||
azdata.nb.showNotebookDocument(untitledUri, options).then(success => {
|
||||
|
||||
}, (err: Error) => {
|
||||
vscode.window.showErrorMessage(err.message);
|
||||
});
|
||||
return azdata.nb.showNotebookDocument(untitledUri, options);
|
||||
}
|
||||
|
||||
function findNextUntitledEditorName(): string {
|
||||
|
||||
@@ -17,3 +17,7 @@ export async function assertThrowsAsync(fn: () => Promise<any>, msg: string): Pr
|
||||
assert.throws(f, msg);
|
||||
}
|
||||
}
|
||||
|
||||
export async function sleep(ms: number): Promise<{}> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as utils from '../../common/utils';
|
||||
import { MockOutputChannel } from './stubs';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import { sleep } from './testUtils';
|
||||
|
||||
describe('Utils Tests', function () {
|
||||
|
||||
@@ -129,12 +132,190 @@ describe('Utils Tests', function () {
|
||||
|
||||
it('different lengths', () => {
|
||||
const random = ['1.0.0', '42', '100.0', '0.1', '1.0.1'];
|
||||
const randomSorted = ['0.1', '1.0.0', '1.0.1', '42', '100.0']
|
||||
const randomSorted = ['0.1', '1.0.0', '1.0.1', '42', '100.0'];
|
||||
should(utils.sortPackageVersions(random)).deepEqual(randomSorted);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClusterEndpoints', () => {
|
||||
describe('executeBufferedCommand', () => {
|
||||
|
||||
it('runs successfully', async () => {
|
||||
await utils.executeBufferedCommand('echo hello', {}, new MockOutputChannel());
|
||||
});
|
||||
|
||||
it('errors correctly with invalid command', async () => {
|
||||
await should(utils.executeBufferedCommand('invalidcommand', {}, new MockOutputChannel())).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
describe('executeStreamedCommand', () => {
|
||||
|
||||
it('runs successfully', async () => {
|
||||
await utils.executeStreamedCommand('echo hello', {}, new MockOutputChannel());
|
||||
});
|
||||
|
||||
it('errors correctly with invalid command', async () => {
|
||||
await should(utils.executeStreamedCommand('invalidcommand', {}, new MockOutputChannel())).be.rejected();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEditorTitleFree', () => {
|
||||
afterEach( async () => {
|
||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||
});
|
||||
|
||||
it('title is free', () => {
|
||||
should(utils.isEditorTitleFree('MyTitle')).be.true();
|
||||
});
|
||||
|
||||
it('title is not free with text document sharing name', async () => {
|
||||
const editorTitle = 'Untitled-1';
|
||||
should(utils.isEditorTitleFree(editorTitle)).be.true('Title should be free before opening text document');
|
||||
await vscode.workspace.openTextDocument();
|
||||
should(utils.isEditorTitleFree(editorTitle)).be.false('Title should not be free after opening text document');
|
||||
});
|
||||
|
||||
it('title is not free with notebook document sharing name', async () => {
|
||||
const editorTitle = 'MyUntitledNotebook';
|
||||
should(utils.isEditorTitleFree(editorTitle)).be.true('Title should be free before opening notebook');
|
||||
await azdata.nb.showNotebookDocument(vscode.Uri.parse(`untitled:${editorTitle}`));
|
||||
should(utils.isEditorTitleFree('MyUntitledNotebook')).be.false('Title should not be free after opening notebook');
|
||||
});
|
||||
|
||||
it('title is not free with notebook document sharing name created through command', async () => {
|
||||
const editorTitle = 'Notebook-0';
|
||||
should(utils.isEditorTitleFree(editorTitle)).be.true('Title should be free before opening notebook');
|
||||
await vscode.commands.executeCommand('_notebook.command.new');
|
||||
should(utils.isEditorTitleFree(editorTitle)).be.false('Title should not be free after opening notebook');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClusterEndpoints', () => {
|
||||
const baseServerInfo: azdata.ServerInfo = {
|
||||
serverMajorVersion: -1,
|
||||
serverMinorVersion: -1,
|
||||
serverReleaseVersion: -1,
|
||||
engineEditionId: -1,
|
||||
serverVersion: '',
|
||||
serverLevel: '',
|
||||
serverEdition: '',
|
||||
isCloud: false,
|
||||
azureVersion: -1,
|
||||
osVersion: '',
|
||||
options: {}
|
||||
};
|
||||
it('empty endpoints does not error', () => {
|
||||
const serverInfo = Object.assign({}, baseServerInfo);
|
||||
serverInfo.options['clusterEndpoints'] = [];
|
||||
should(utils.getClusterEndpoints(serverInfo).length).equal(0);
|
||||
});
|
||||
|
||||
it('endpoints without endpoint field are created successfully', () => {
|
||||
const serverInfo = Object.assign({}, baseServerInfo);
|
||||
const ipAddress = 'localhost';
|
||||
const port = '123';
|
||||
serverInfo.options['clusterEndpoints'] = [{ ipAddress: ipAddress, port: port }];
|
||||
const endpoints = utils.getClusterEndpoints(serverInfo);
|
||||
should(endpoints.length).equal(1);
|
||||
should(endpoints[0].endpoint).equal('https://localhost:123');
|
||||
});
|
||||
|
||||
it('endpoints with endpoint field are created successfully', () => {
|
||||
const endpoint = 'https://myActualEndpoint:8080';
|
||||
const serverInfo = Object.assign({}, baseServerInfo);
|
||||
serverInfo.options['clusterEndpoints'] = [{ endpoint: endpoint, ipAddress: 'localhost', port: '123' }];
|
||||
const endpoints = utils.getClusterEndpoints(serverInfo);
|
||||
should(endpoints.length).equal(1);
|
||||
should(endpoints[0].endpoint).equal(endpoint);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHostAndPortFromEndpoint', () => {
|
||||
it('valid endpoint is parsed correctly', () => {
|
||||
const host = 'localhost';
|
||||
const port = '123';
|
||||
const hostAndIp = utils.getHostAndPortFromEndpoint(`https://${host}:${port}`);
|
||||
should(hostAndIp).deepEqual({ host: host, port: port });
|
||||
});
|
||||
|
||||
it('invalid endpoint is returned as is', () => {
|
||||
const host = 'localhost';
|
||||
const hostAndIp = utils.getHostAndPortFromEndpoint(`https://${host}`);
|
||||
should(hostAndIp).deepEqual({ host: host, port: undefined });
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', () => {
|
||||
it('runs as expected', async () => {
|
||||
const filename = path.join(os.tmpdir(), `NotebookUtilsTest_${uuid.v4()}`);
|
||||
try {
|
||||
should(await utils.exists(filename)).be.false();
|
||||
await fs.writeFile(filename, '');
|
||||
should(await utils.exists(filename)).be.true();
|
||||
} finally {
|
||||
try {
|
||||
await fs.unlink(filename);
|
||||
} catch { /* no-op */ }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIgnoreSslVerificationConfigSetting', () => {
|
||||
it('runs as expected', async () => {
|
||||
should(utils.getIgnoreSslVerificationConfigSetting()).be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('debounce', () => {
|
||||
class DebounceTest {
|
||||
public fnCalled = 0;
|
||||
public getterCalled = 0;
|
||||
|
||||
@utils.debounce(100)
|
||||
fn(): void {
|
||||
this.fnCalled++;
|
||||
}
|
||||
|
||||
@utils.debounce(100)
|
||||
get getter(): number {
|
||||
this.getterCalled++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
it('decorates function correctly', async () => {
|
||||
const debounceTestObj = new DebounceTest();
|
||||
debounceTestObj.fn();
|
||||
debounceTestObj.fn();
|
||||
await sleep(500);
|
||||
should(debounceTestObj.fnCalled).equal(1);
|
||||
debounceTestObj.fn();
|
||||
debounceTestObj.fn();
|
||||
await sleep(500);
|
||||
should(debounceTestObj.fnCalled).equal(2);
|
||||
});
|
||||
|
||||
it('decorates getter correctly', async () => {
|
||||
const debounceTestObj = new DebounceTest();
|
||||
let getterValue = debounceTestObj.getter;
|
||||
getterValue = debounceTestObj.getter;
|
||||
await sleep(500);
|
||||
should(debounceTestObj.getterCalled).equal(1);
|
||||
getterValue = debounceTestObj.getter;
|
||||
getterValue = debounceTestObj.getter;
|
||||
await sleep(500);
|
||||
should(debounceTestObj.getterCalled).equal(2);
|
||||
should(getterValue).be.undefined();
|
||||
});
|
||||
|
||||
it('decorating setter not supported', async () => {
|
||||
should(() => {
|
||||
class UnsupportedTest {
|
||||
@utils.debounce(100)
|
||||
set setter(value: number) { }
|
||||
}
|
||||
new UnsupportedTest();
|
||||
}).throw();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('Jupyter Session', function (): void {
|
||||
|
||||
beforeEach(() => {
|
||||
mockJupyterSession = TypeMoq.Mock.ofType(SessionStub);
|
||||
session = new JupyterSession(mockJupyterSession.object, undefined);
|
||||
session = new JupyterSession(mockJupyterSession.object, undefined, true);
|
||||
});
|
||||
|
||||
it('should always be able to change kernels', function (): void {
|
||||
@@ -145,7 +145,7 @@ describe('Jupyter Session', function (): void {
|
||||
kernel = session.kernel;
|
||||
// Then I expect it to have the ID, and only be called once
|
||||
should(kernel.id).equal('id');
|
||||
mockJupyterSession.verify(s => s.kernel, TypeMoq.Times.exactly(2));
|
||||
mockJupyterSession.verify(s => s.kernel, TypeMoq.Times.exactly(1));
|
||||
});
|
||||
|
||||
it('should send name in changeKernel request', async function (): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user