mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add tests to GitHubRemoteBook (#11953)
* Tests for githubRemoteBook class * Add some tests and remove unused class * Address PR comments
This commit is contained in:
@@ -14,14 +14,14 @@ import { IAsset } from './remoteBookController';
|
|||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
|
|
||||||
export class GitHubRemoteBook extends RemoteBook {
|
export class GitHubRemoteBook extends RemoteBook {
|
||||||
constructor(public remotePath: vscode.Uri, public outputChannel: vscode.OutputChannel, protected _asset: IAsset) {
|
constructor(public readonly remotePath: vscode.Uri, public readonly outputChannel: vscode.OutputChannel, public readonly asset: IAsset) {
|
||||||
super(remotePath, outputChannel, _asset);
|
super(remotePath, outputChannel, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createLocalCopy(): Promise<void> {
|
public async createLocalCopy(): Promise<void> {
|
||||||
this.outputChannel.show(true);
|
this.outputChannel.show(true);
|
||||||
this.setLocalPath();
|
this.setLocalPath();
|
||||||
this.outputChannel.appendLine(loc.msgDownloadLocation(this._localPath.fsPath));
|
this.outputChannel.appendLine(loc.msgDownloadLocation(this.localPath.fsPath));
|
||||||
this.outputChannel.appendLine(loc.msgRemoteBookDownloadProgress);
|
this.outputChannel.appendLine(loc.msgRemoteBookDownloadProgress);
|
||||||
this.createDirectory();
|
this.createDirectory();
|
||||||
let notebookConfig = vscode.workspace.getConfiguration(constants.notebookConfigKey);
|
let notebookConfig = vscode.workspace.getConfiguration(constants.notebookConfigKey);
|
||||||
@@ -34,7 +34,7 @@ export class GitHubRemoteBook extends RemoteBook {
|
|||||||
'timeout': downloadTimeout
|
'timeout': downloadTimeout
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let downloadRequest = request.get(this._asset.browserDownloadUrl.toString(false), options)
|
let downloadRequest = request.get(this.asset.browserDownloadUrl.toString(false), options)
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
this.outputChannel.appendLine(loc.msgRemoteBookDownloadError);
|
this.outputChannel.appendLine(loc.msgRemoteBookDownloadError);
|
||||||
this.outputChannel.appendLine(error.message);
|
this.outputChannel.appendLine(error.message);
|
||||||
@@ -46,7 +46,7 @@ export class GitHubRemoteBook extends RemoteBook {
|
|||||||
return reject(new Error(loc.httpRequestError(response.statusCode, response.statusMessage)));
|
return reject(new Error(loc.httpRequestError(response.statusCode, response.statusMessage)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let remoteBookFullPath = vscode.Uri.file(this._localPath.fsPath.concat('.', this._asset.format));
|
let remoteBookFullPath = vscode.Uri.file(this.localPath.fsPath.concat('.', this.asset.format));
|
||||||
downloadRequest.pipe(fs.createWriteStream(remoteBookFullPath.fsPath))
|
downloadRequest.pipe(fs.createWriteStream(remoteBookFullPath.fsPath))
|
||||||
.on('close', async () => {
|
.on('close', async () => {
|
||||||
resolve(this.extractFiles(remoteBookFullPath));
|
resolve(this.extractFiles(remoteBookFullPath));
|
||||||
@@ -60,14 +60,14 @@ export class GitHubRemoteBook extends RemoteBook {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public async createDirectory(): Promise<void> {
|
public async createDirectory(): Promise<void> {
|
||||||
let fileName = this._asset.book.concat('-').concat(this._asset.version).concat('-').concat(this._asset.language);
|
let fileName = this.asset.book.concat('-').concat(this.asset.version).concat('-').concat(this.asset.language);
|
||||||
this._localPath = vscode.Uri.file(path.join(this._localPath.fsPath, fileName));
|
this.localPath = vscode.Uri.file(path.join(this.localPath.fsPath, fileName));
|
||||||
try {
|
try {
|
||||||
let exists = await fs.pathExists(this._localPath.fsPath);
|
let exists = await fs.pathExists(this.localPath.fsPath);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
await fs.remove(this._localPath.fsPath);
|
await fs.remove(this.localPath.fsPath);
|
||||||
}
|
}
|
||||||
await fs.promises.mkdir(this._localPath.fsPath);
|
await fs.promises.mkdir(this.localPath.fsPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.outputChannel.appendLine(loc.msgRemoteBookDirectoryError);
|
this.outputChannel.appendLine(loc.msgRemoteBookDirectoryError);
|
||||||
this.outputChannel.appendLine(error.message);
|
this.outputChannel.appendLine(error.message);
|
||||||
@@ -77,13 +77,13 @@ export class GitHubRemoteBook extends RemoteBook {
|
|||||||
try {
|
try {
|
||||||
if (process.platform === constants.winPlatform || process.platform === constants.macPlatform) {
|
if (process.platform === constants.winPlatform || process.platform === constants.macPlatform) {
|
||||||
let zippedFile = new zip(remoteBookFullPath.fsPath);
|
let zippedFile = new zip(remoteBookFullPath.fsPath);
|
||||||
zippedFile.extractAllTo(this._localPath.fsPath);
|
zippedFile.extractAllTo(this.localPath.fsPath);
|
||||||
} else {
|
} else {
|
||||||
await tar.extract({ file: remoteBookFullPath.fsPath, cwd: this._localPath.fsPath });
|
await tar.extract({ file: remoteBookFullPath.fsPath, cwd: this.localPath.fsPath });
|
||||||
}
|
}
|
||||||
await fs.promises.unlink(remoteBookFullPath.fsPath);
|
await fs.promises.unlink(remoteBookFullPath.fsPath);
|
||||||
this.outputChannel.appendLine(loc.msgRemoteBookDownloadComplete);
|
this.outputChannel.appendLine(loc.msgRemoteBookDownloadComplete);
|
||||||
vscode.commands.executeCommand('notebook.command.openNotebookFolder', this._localPath.fsPath, undefined, true);
|
vscode.commands.executeCommand('notebook.command.openNotebookFolder', this.localPath.fsPath, undefined, true);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
this.outputChannel.appendLine(loc.msgRemoteBookUnpackingError);
|
this.outputChannel.appendLine(loc.msgRemoteBookUnpackingError);
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import * as utils from '../common/utils';
|
|||||||
import { IAsset } from './remoteBookController';
|
import { IAsset } from './remoteBookController';
|
||||||
|
|
||||||
export abstract class RemoteBook {
|
export abstract class RemoteBook {
|
||||||
protected _localPath: vscode.Uri;
|
public localPath: vscode.Uri;
|
||||||
|
|
||||||
constructor(public remotePath: vscode.Uri, public outputChannel: vscode.OutputChannel, protected _asset?: IAsset) {
|
constructor(public readonly remotePath: vscode.Uri, public readonly outputChannel: vscode.OutputChannel, public readonly _asset?: IAsset) {
|
||||||
this.remotePath = remotePath;
|
this.remotePath = remotePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +21,10 @@ export abstract class RemoteBook {
|
|||||||
if (vscode.workspace.workspaceFolders !== undefined) {
|
if (vscode.workspace.workspaceFolders !== undefined) {
|
||||||
// Get workspace root path
|
// Get workspace root path
|
||||||
let folders = vscode.workspace.workspaceFolders;
|
let folders = vscode.workspace.workspaceFolders;
|
||||||
this._localPath = vscode.Uri.file(folders[0].uri.fsPath);
|
this.localPath = vscode.Uri.file(folders[0].uri.fsPath);
|
||||||
} else {
|
} else {
|
||||||
//If no workspace folder is opened then path is Users directory
|
//If no workspace folder is opened then path is Users directory
|
||||||
this._localPath = vscode.Uri.file(utils.getUserHome());
|
this.localPath = vscode.Uri.file(utils.getUserHome());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import * as loc from '../common/localizedConstants';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { RemoteBookDialogModel } from '../dialog/remoteBookDialogModel';
|
import { RemoteBookDialogModel } from '../dialog/remoteBookDialogModel';
|
||||||
import { GitHubRemoteBook } from '../book/githubRemoteBook';
|
import { GitHubRemoteBook } from '../book/githubRemoteBook';
|
||||||
import { SharedRemoteBook } from '../book/sharedRemoteBook';
|
|
||||||
import { winPlatform, macPlatform } from '../common/constants';
|
import { winPlatform, macPlatform } from '../common/constants';
|
||||||
|
|
||||||
const assetNameRE = /([a-zA-Z0-9]+)(?:-|_)([a-zA-Z0-9.]+)(?:-|_)([a-zA-Z0-9]+).(zip|tar.gz|tgz)/;
|
const assetNameRE = /([a-zA-Z0-9]+)(?:-|_)([a-zA-Z0-9.]+)(?:-|_)([a-zA-Z0-9]+).(zip|tar.gz|tgz)/;
|
||||||
@@ -20,8 +19,6 @@ export class RemoteBookController {
|
|||||||
public async setRemoteBook(url: vscode.Uri, remoteLocation: string, asset?: IAsset): Promise<void> {
|
public async setRemoteBook(url: vscode.Uri, remoteLocation: string, asset?: IAsset): Promise<void> {
|
||||||
if (remoteLocation === 'GitHub') {
|
if (remoteLocation === 'GitHub') {
|
||||||
this.model.remoteBook = new GitHubRemoteBook(url, this.outputChannel, asset);
|
this.model.remoteBook = new GitHubRemoteBook(url, this.outputChannel, asset);
|
||||||
} else {
|
|
||||||
this.model.remoteBook = new SharedRemoteBook(url, this.outputChannel);
|
|
||||||
}
|
}
|
||||||
return await this.model.remoteBook.createLocalCopy();
|
return await this.model.remoteBook.createLocalCopy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
import { RemoteBook } from '../book/remoteBook';
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
|
|
||||||
|
|
||||||
export class SharedRemoteBook extends RemoteBook {
|
|
||||||
constructor(public remotePath: vscode.Uri, public outputChannel: vscode.OutputChannel) {
|
|
||||||
super(remotePath, outputChannel);
|
|
||||||
}
|
|
||||||
public async createLocalCopy(): Promise<void> {
|
|
||||||
throw new Error('Not yet supported');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
116
extensions/notebook/src/test/book/githubRemoteBook.test.ts
Normal file
116
extensions/notebook/src/test/book/githubRemoteBook.test.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { RemoteBookDialogModel } from '../../dialog/remoteBookDialogModel';
|
||||||
|
import { IAsset, RemoteBookController } from '../../book/remoteBookController';
|
||||||
|
import * as should from 'should';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { MockExtensionContext } from '../common/stubs';
|
||||||
|
import { AppContext } from '../../common/appContext';
|
||||||
|
import * as loc from '../../common/localizedConstants';
|
||||||
|
import { GitHubRemoteBook } from '../../book/githubRemoteBook';
|
||||||
|
import { RemoteBook } from '../../book/remoteBook';
|
||||||
|
import * as nock from 'nock';
|
||||||
|
import * as os from 'os';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
describe('Github Remote Book', function () {
|
||||||
|
let mockExtensionContext: vscode.ExtensionContext = new MockExtensionContext();
|
||||||
|
let appContext = new AppContext(mockExtensionContext);
|
||||||
|
let model = new RemoteBookDialogModel();
|
||||||
|
let controller = new RemoteBookController(model, appContext.outputChannel);
|
||||||
|
|
||||||
|
afterEach(function (): void {
|
||||||
|
sinon.restore();
|
||||||
|
nock.cleanAll();
|
||||||
|
nock.enableNetConnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Verify GitHub Remote Book is created by controller', async function (): Promise<void> {
|
||||||
|
let releaseURL = vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1');
|
||||||
|
let asset : IAsset = {
|
||||||
|
name: 'CU-1.0-EN.zip',
|
||||||
|
book: 'CU',
|
||||||
|
version: '1.0',
|
||||||
|
language: 'EN',
|
||||||
|
format: 'zip',
|
||||||
|
url: vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1/assets/1'),
|
||||||
|
browserDownloadUrl: vscode.Uri.parse('https://github.com/microsoft/test/releases/download/v1/CU-1.0-EN.zip'),
|
||||||
|
}
|
||||||
|
let remoteLocation = loc.onGitHub;
|
||||||
|
controller.setRemoteBook(releaseURL, remoteLocation, asset);
|
||||||
|
should(controller.model.remoteBook).not.null();
|
||||||
|
should(controller.model.remoteBook instanceof GitHubRemoteBook).be.true;
|
||||||
|
let book = model.remoteBook as GitHubRemoteBook;
|
||||||
|
should(book.asset.browserDownloadUrl.toString(false)).equal('https://github.com/microsoft/test/releases/download/v1/CU-1.0-EN.zip');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Verify set local path is called when creating a GitHub Remote Book', async function (): Promise<void> {
|
||||||
|
let releaseURL = vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1');
|
||||||
|
let asset : IAsset = {
|
||||||
|
name: 'CU-1.0-EN.zip',
|
||||||
|
book: 'CU',
|
||||||
|
version: '1.0',
|
||||||
|
language: 'EN',
|
||||||
|
format: 'zip',
|
||||||
|
url: vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1/assets/1'),
|
||||||
|
browserDownloadUrl: vscode.Uri.parse('https://github.com/microsoft/test/releases/download/v1/CU-1.0-EN.zip'),
|
||||||
|
}
|
||||||
|
let remoteLocation = loc.onGitHub;
|
||||||
|
const createCopySpy = sinon.spy(GitHubRemoteBook.prototype, 'createLocalCopy');
|
||||||
|
const setPathSpy = sinon.spy(RemoteBook.prototype, 'setLocalPath');
|
||||||
|
controller.setRemoteBook(releaseURL, remoteLocation, asset);
|
||||||
|
should(createCopySpy.calledOnce).be.true;
|
||||||
|
should(setPathSpy.calledOnce).be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should download contents from Github', async function (): Promise<void> {
|
||||||
|
let releaseURL = vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1');
|
||||||
|
let asset : IAsset = {
|
||||||
|
name: 'CU-1.0-EN.zip',
|
||||||
|
book: 'CU',
|
||||||
|
version: '1.0',
|
||||||
|
language: 'EN',
|
||||||
|
format: 'zip',
|
||||||
|
url: vscode.Uri.parse('https://api.github.com/repos/microsoft/test/releases/v1/assets/1'),
|
||||||
|
browserDownloadUrl: vscode.Uri.parse('https://github.com/microsoft/test/releases/download/v1/CU-1.0-EN.zip'),
|
||||||
|
}
|
||||||
|
let remoteLocation = loc.onGitHub;
|
||||||
|
controller.setRemoteBook(releaseURL, remoteLocation, asset);
|
||||||
|
|
||||||
|
model.remoteBook.localPath = vscode.Uri.file(os.tmpdir());
|
||||||
|
let setPathStub = sinon.stub(GitHubRemoteBook.prototype, 'setLocalPath');
|
||||||
|
setPathStub.callsFake(function() {
|
||||||
|
console.log(`Downloading book in ${model.remoteBook.localPath}`);
|
||||||
|
})
|
||||||
|
const setExtractSpy = sinon.spy(GitHubRemoteBook.prototype, 'extractFiles');
|
||||||
|
nock('https://github.com')
|
||||||
|
.persist()
|
||||||
|
.get('/microsoft/test/releases/download/v1/CU-1.0-EN.zip')
|
||||||
|
.replyWithFile(200, __filename);
|
||||||
|
await model.remoteBook.createLocalCopy();
|
||||||
|
should(setExtractSpy.calledOnceWith(vscode.Uri.file(model.remoteBook.localPath.fsPath)));
|
||||||
|
await fs.promises.stat(model.remoteBook.localPath.fsPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should reject if unexpected error', async function (): Promise<void> {
|
||||||
|
nock('https://github.com')
|
||||||
|
.persist()
|
||||||
|
.get('/microsoft/test/releases/download/v1/CU-1.0-EN.zip')
|
||||||
|
.replyWithError(new Error('Unexpected Error'));
|
||||||
|
await should(model.remoteBook.createLocalCopy()).be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should reject if response status code is not 200', async function (): Promise<void> {
|
||||||
|
nock('https://github.com')
|
||||||
|
.persist()
|
||||||
|
.get('/microsoft/test/releases/download/v1/CU-1.0-EN.zip')
|
||||||
|
.reply(404)
|
||||||
|
const createLocalCopy = model.remoteBook.createLocalCopy();
|
||||||
|
await should(createLocalCopy).be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user