Updating status in the output when installing the service (#436)
* showing download progress in the output window * added note when installing the service that the commands are not available * added icon to the status bar when downloading and isntalling
This commit is contained in:
Родитель
64e33bd9e4
Коммит
0d63812208
|
@ -47,6 +47,7 @@
|
|||
"vscode.sql"
|
||||
],
|
||||
"devDependencies": {
|
||||
"chai": "^3.5.0",
|
||||
"decache": "^4.1.0",
|
||||
"del": "^2.2.1",
|
||||
"gulp": "github:gulpjs/gulp#4.0",
|
||||
|
|
|
@ -128,7 +128,7 @@ export default class MainController implements vscode.Disposable {
|
|||
|
||||
// initialize language service client
|
||||
return new Promise<boolean>( (resolve, reject) => {
|
||||
SqlToolsServerClient.instance.initialize(self._context).then(() => {
|
||||
SqlToolsServerClient.instance.initialize(self._context).then(serverResult => {
|
||||
|
||||
// Init status bar
|
||||
self._statusview = new StatusView();
|
||||
|
@ -151,7 +151,7 @@ export default class MainController implements vscode.Disposable {
|
|||
|
||||
// telemetry for activation
|
||||
Telemetry.sendTelemetryEvent('ExtensionActivated', {},
|
||||
{ activationTime: activationTimer.getDuration() }
|
||||
{ activationTime: activationTimer.getDuration(), serviceInstalled: serverResult.installedBeforeInitializing ? 1 : 0 }
|
||||
);
|
||||
|
||||
self.showReleaseNotesPrompt();
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
import * as https from 'https';
|
||||
import * as http from 'http';
|
||||
import * as stream from 'stream';
|
||||
import {parse} from 'url';
|
||||
import {parse, Url} from 'url';
|
||||
import {Runtime, getRuntimeDisplayName} from '../models/platform';
|
||||
import {getProxyAgent} from './proxy';
|
||||
import * as path from 'path';
|
||||
import {IConfig, ILogger} from './interfaces';
|
||||
import {IConfig, IStatusView} from './interfaces';
|
||||
import {ILogger} from '../models/interfaces';
|
||||
import Constants = require('../models/constants');
|
||||
|
||||
let tmp = require('tmp');
|
||||
let fs = require('fs');
|
||||
|
@ -27,7 +29,8 @@ tmp.setGracefulCleanup();
|
|||
export default class ServiceDownloadProvider {
|
||||
|
||||
constructor(private _config: IConfig,
|
||||
private _logger: ILogger) {
|
||||
private _logger: ILogger,
|
||||
private _statusView: IStatusView) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,12 +51,13 @@ export default class ServiceDownloadProvider {
|
|||
return fileName;
|
||||
}
|
||||
|
||||
private download(urlString: string, proxy?: string, strictSSL?: boolean): Promise<stream.Readable> {
|
||||
let url = parse(urlString);
|
||||
private setStatusUpdate(downloadPercentage: number): void {
|
||||
this._statusView.updateServiceDownloadingProgress(downloadPercentage);
|
||||
}
|
||||
|
||||
private getHttpClientOptions(url: Url, proxy?: string, strictSSL?: boolean): any {
|
||||
const agent = getProxyAgent(url, proxy, strictSSL);
|
||||
|
||||
let client = url.protocol === 'http:' ? http : https;
|
||||
let options: http.RequestOptions = {
|
||||
host: url.hostname,
|
||||
path: url.path,
|
||||
|
@ -71,30 +75,74 @@ export default class ServiceDownloadProvider {
|
|||
options = httpsOptions;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private download(urlString: string, proxy?: string, strictSSL?: boolean): Promise<stream.Readable> {
|
||||
let url = parse(urlString);
|
||||
let options = this.getHttpClientOptions(url, proxy, strictSSL);
|
||||
let client = url.protocol === 'http:' ? http : https;
|
||||
|
||||
return new Promise<stream.Readable>((resolve, reject) => {
|
||||
process.on('uncaughtException', function (err): void {
|
||||
// When server DNS address is not valid the http client doesn't return any error code,
|
||||
// So the promise never returns any reject or resolve. The only way to fix it was to handle the process exception
|
||||
// and check for that specific error message
|
||||
if (err !== undefined && err.message !== undefined && (<string>err.message).lastIndexOf('getaddrinfo') >= 0) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
return client.get(options, res => {
|
||||
|
||||
let request = client.request(options, response => {
|
||||
// handle redirection
|
||||
if (res.statusCode === 302) {
|
||||
return this.download(res.headers.location).then(result => {
|
||||
if (response.statusCode === 302 || response.statusCode === 301) {
|
||||
return this.download(response.headers.location, proxy, strictSSL).then(result => {
|
||||
return resolve(result);
|
||||
});
|
||||
} else if (res.statusCode !== 200) {
|
||||
return reject(Error(`Download failed with code ${res.statusCode}.`));
|
||||
} else if (response.statusCode !== 200) {
|
||||
return reject(Error(`Download failed with code ${response.statusCode}.`));
|
||||
}
|
||||
|
||||
return resolve(res);
|
||||
this.handleHttpResponseEvents(response);
|
||||
response.on('end', () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
response.on('error', err => {
|
||||
reject(`Reponse error: ${err.code || 'NONE'}`);
|
||||
});
|
||||
|
||||
return resolve(response);
|
||||
});
|
||||
|
||||
request.on('error', error => {
|
||||
reject(`Request error: ${error.code || 'NONE'}`);
|
||||
});
|
||||
|
||||
// Execute the request
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
|
||||
private handleHttpResponseEvents(response: http.IncomingMessage): void {
|
||||
// Downloading - hook up events
|
||||
let packageSize = parseInt(response.headers['content-length'], 10);
|
||||
let downloadedBytes = 0;
|
||||
let downloadPercentage = 0;
|
||||
let dots = 0;
|
||||
|
||||
this._logger.append(`(${Math.ceil(packageSize / 1024)} KB) `);
|
||||
response.on('data', data => {
|
||||
downloadedBytes += data.length;
|
||||
|
||||
// Update status bar item with percentage
|
||||
let newPercentage = Math.ceil(100 * (downloadedBytes / packageSize));
|
||||
if (newPercentage !== downloadPercentage) {
|
||||
this.setStatusUpdate(downloadPercentage);
|
||||
downloadPercentage = newPercentage;
|
||||
}
|
||||
|
||||
// Update dots after package name in output console
|
||||
let newDots = Math.ceil(downloadPercentage / 5);
|
||||
if (newDots > dots) {
|
||||
this._logger.append('.'.repeat(newDots - dots));
|
||||
dots = newDots;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SQL tools service installed folder.
|
||||
*/
|
||||
|
@ -134,7 +182,7 @@ export default class ServiceDownloadProvider {
|
|||
/**
|
||||
* Downloads the SQL tools service and decompress it in the install folder.
|
||||
*/
|
||||
public go(platform: Runtime): Promise<boolean> {
|
||||
public InstallSQLToolsService(platform: Runtime): Promise<boolean> {
|
||||
const proxy = <string>this._config.getWorkspaceConfig('http.proxy');
|
||||
const strictSSL = this._config.getWorkspaceConfig('http.proxyStrictSSL', true);
|
||||
|
||||
|
@ -142,52 +190,64 @@ export default class ServiceDownloadProvider {
|
|||
const fileName = this.getDownloadFileName( platform);
|
||||
const installDirectory = this.getInstallDirectory(platform);
|
||||
|
||||
this._logger.logDebug(`Installing sql tools service to ${installDirectory}`);
|
||||
this._logger.appendLine(`${Constants.serviceInstallingTo} ${installDirectory}.`);
|
||||
const urlString = this.getGetDownloadUrl(fileName);
|
||||
|
||||
this._logger.logDebug(`Attempting to download ${urlString}`);
|
||||
this._logger.appendLine(`${Constants.serviceDownloading} ${urlString}`);
|
||||
|
||||
return this.download(urlString, proxy, strictSSL)
|
||||
.then(inStream => {
|
||||
tmp.file((err, tmpPath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
this._logger.logDebug(`Downloading to ${tmpPath}...`);
|
||||
|
||||
const outStream = fs.createWriteStream(undefined, { fd: fd });
|
||||
|
||||
outStream.once('error', outStreamErr => reject(outStreamErr));
|
||||
inStream.once('error', inStreamErr => reject(inStreamErr));
|
||||
|
||||
outStream.once('finish', () => {
|
||||
// At this point, the asset has finished downloading.
|
||||
|
||||
this._logger.logDebug('Download complete!');
|
||||
this._logger.logDebug('Decompressing...');
|
||||
|
||||
return decompress(tmpPath, installDirectory)
|
||||
.then(files => {
|
||||
this._logger.logDebug(`Done! ${files.length} files unpacked.\n`);
|
||||
return resolve(true);
|
||||
})
|
||||
.catch(decompressErr => {
|
||||
this._logger.logDebug(`[ERROR] ${err}`);
|
||||
return reject(decompressErr);
|
||||
});
|
||||
});
|
||||
|
||||
inStream.pipe(outStream);
|
||||
this.install(inStream, installDirectory).then ( installed => {
|
||||
resolve(installed);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
this._logger.logDebug(`[ERROR] ${err}`);
|
||||
this._logger.appendLine(`[ERROR] ${err}`);
|
||||
reject(err);
|
||||
});
|
||||
}).then(res => {
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
private install(inStream: stream.Readable, installDirectory: string): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
tmp.file((err, tmpPath, fd, cleanupCallback) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
this._logger.logDebug(`Downloading to ${tmpPath}...`);
|
||||
|
||||
const outStream = fs.createWriteStream(undefined, { fd: fd });
|
||||
|
||||
outStream.once('error', outStreamErr => reject(outStreamErr));
|
||||
inStream.once('error', inStreamErr => reject(inStreamErr));
|
||||
|
||||
outStream.once('finish', () => {
|
||||
// At this point, the asset has finished downloading.
|
||||
|
||||
this._logger.appendLine(' Done!');
|
||||
this._logger.appendLine('Installing ...');
|
||||
this._statusView.installingService();
|
||||
|
||||
return decompress(tmpPath, installDirectory)
|
||||
.then(files => {
|
||||
this._logger.appendLine(`Done! ${files.length} files unpacked.\n`);
|
||||
this._statusView.serviceInstalled();
|
||||
resolve(true);
|
||||
})
|
||||
.catch(decompressErr => {
|
||||
this._logger.appendLine(`[ERROR] ${err}`);
|
||||
reject(decompressErr);
|
||||
});
|
||||
});
|
||||
|
||||
inStream.pipe(outStream);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as Utils from '../models/utils';
|
||||
import {IExtensionWrapper, ILogger} from './interfaces';
|
||||
|
||||
/*
|
||||
* ExtensionWrapper class handles the functions which requires the vscode modules.
|
||||
* Note: If the class is used from a gulp script, it cannot find the vs code module
|
||||
*/
|
||||
export class ExtensionWrapper implements IExtensionWrapper {
|
||||
getActiveTextEditorUri(): string {
|
||||
return Utils.getActiveTextEditorUri();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Logger class handles logging messages using the Util functions.
|
||||
*/
|
||||
export class Logger implements ILogger {
|
||||
logDebug(message: string): void {
|
||||
Utils.logDebug(message);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,10 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface IStatusView {
|
||||
installingService(fileUri: string): void;
|
||||
serviceInstalled(fileUri: string): void;
|
||||
serviceInstallationFailed(fileUri: string): void;
|
||||
installingService(): void;
|
||||
serviceInstalled(): void;
|
||||
serviceInstallationFailed(): void;
|
||||
updateServiceDownloadingProgress(downloadPercentage: number): void;
|
||||
}
|
||||
|
||||
export interface IConfig {
|
||||
|
@ -20,10 +21,4 @@ export interface IConfig {
|
|||
getSqlToolsConfigValue(configKey: string): any;
|
||||
}
|
||||
|
||||
export interface IExtensionWrapper {
|
||||
getActiveTextEditorUri(): string;
|
||||
}
|
||||
|
||||
export interface ILogger {
|
||||
logDebug(message: string): void;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import {Runtime, PlatformInformation} from '../models/platform';
|
||||
import {Runtime} from '../models/platform';
|
||||
import ServiceDownloadProvider from './download';
|
||||
import {IConfig, IStatusView, IExtensionWrapper} from './interfaces';
|
||||
import {IConfig, IStatusView} from './interfaces';
|
||||
let fs = require('fs-extra-promise');
|
||||
|
||||
|
||||
|
@ -19,8 +19,7 @@ export default class ServerProvider {
|
|||
|
||||
constructor(private _downloadProvider: ServiceDownloadProvider,
|
||||
private _config: IConfig,
|
||||
private _statusView: IStatusView,
|
||||
private _vsCodeExtention: IExtensionWrapper) {
|
||||
private _statusView: IStatusView) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,29 +50,15 @@ export default class ServerProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the SQL tools service if doesn't exist and returns the file path.
|
||||
*/
|
||||
public getServerPath(runtime?: Runtime): Promise<string> {
|
||||
|
||||
if (runtime === undefined) {
|
||||
return PlatformInformation.GetCurrent().then( currentPlatform => {
|
||||
return this.getServerPathForPlatform(currentPlatform.runtimeId);
|
||||
});
|
||||
} else {
|
||||
return this.getServerPathForPlatform(runtime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private getServerPathForPlatform(runtime: Runtime): Promise<string> {
|
||||
/**
|
||||
* Download the SQL tools service if doesn't exist and returns the file path.
|
||||
*/
|
||||
public getOrDownloadServer(runtime: Runtime): Promise<string> {
|
||||
// Attempt to find launch file path first from options, and then from the default install location.
|
||||
// If SQL tools service can't be found, download it.
|
||||
|
||||
const installDirectory = this._downloadProvider.getInstallDirectory(runtime);
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
return this.findServerPath(installDirectory).then(result => {
|
||||
return this.getServerPath(runtime).then(result => {
|
||||
if (result === undefined) {
|
||||
return this.downloadServerFiles(runtime).then ( downloadResult => {
|
||||
resolve(downloadResult);
|
||||
|
@ -89,18 +74,26 @@ export default class ServerProvider {
|
|||
});
|
||||
}
|
||||
|
||||
private downloadServerFiles(runtime: Runtime): Promise<string> {
|
||||
/**
|
||||
* Returns the path of the insalled service
|
||||
*/
|
||||
public getServerPath(runtime: Runtime): Promise<string> {
|
||||
const installDirectory = this._downloadProvider.getInstallDirectory(runtime);
|
||||
let currentFileUrl = this._vsCodeExtention.getActiveTextEditorUri();
|
||||
this._statusView.installingService(currentFileUrl);
|
||||
return this._downloadProvider.go(runtime).then( _ => {
|
||||
return this.findServerPath(installDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the service and returns the path of the insalled service
|
||||
*/
|
||||
public downloadServerFiles(runtime: Runtime): Promise<string> {
|
||||
const installDirectory = this._downloadProvider.getInstallDirectory(runtime);
|
||||
return this._downloadProvider.InstallSQLToolsService(runtime).then( _ => {
|
||||
return this.findServerPath(installDirectory).then ( result => {
|
||||
this._statusView.serviceInstalled(currentFileUrl);
|
||||
return result;
|
||||
});
|
||||
|
||||
}).catch(err => {
|
||||
this._statusView.serviceInstallationFailed(currentFileUrl);
|
||||
this._statusView.serviceInstallationFailed();
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {IStatusView} from './interfaces';
|
||||
import vscode = require('vscode');
|
||||
import Constants = require('../models/constants');
|
||||
|
||||
/*
|
||||
* The status class which includes the service initialization result.
|
||||
*/
|
||||
export class ServerInitializationResult {
|
||||
|
||||
public constructor(
|
||||
public installedBeforeInitializing: Boolean = false,
|
||||
public isRunning: Boolean = false,
|
||||
public serverPath: string = undefined
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
public Clone(): ServerInitializationResult {
|
||||
return new ServerInitializationResult(this.installedBeforeInitializing, this.isRunning, this.serverPath);
|
||||
}
|
||||
|
||||
public WithRunning(isRunning: Boolean): ServerInitializationResult {
|
||||
return new ServerInitializationResult(this.installedBeforeInitializing, isRunning, this.serverPath);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The status class shows service installing progress in UI
|
||||
*/
|
||||
export class ServerStatusView implements IStatusView, vscode.Disposable {
|
||||
private _numberOfSecondsBeforeHidingMessage = 5000;
|
||||
private _statusBarItem: vscode.StatusBarItem = undefined;
|
||||
private _progressTimerId: number;
|
||||
|
||||
constructor() {
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
vscode.window.onDidChangeActiveTextEditor((params) => this.onDidChangeActiveTextEditor(params));
|
||||
vscode.workspace.onDidCloseTextDocument((params) => this.onDidCloseTextDocument(params));
|
||||
}
|
||||
|
||||
public installingService(): void {
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.show();
|
||||
|
||||
this.showProgress('$(desktop-download) ' + Constants.serviceInstalling);
|
||||
}
|
||||
|
||||
public updateServiceDownloadingProgress(downloadPercentage: number): void {
|
||||
this._statusBarItem.text = '$(cloud-download) ' + `${Constants.serviceDownloading} ... ${downloadPercentage}%`;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
|
||||
public serviceInstalled(): void {
|
||||
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.text = Constants.serviceInstalled;
|
||||
this._statusBarItem.show();
|
||||
// Cleat the status bar after 2 seconds
|
||||
setTimeout(() => {
|
||||
this._statusBarItem.hide();
|
||||
}, this._numberOfSecondsBeforeHidingMessage);
|
||||
}
|
||||
|
||||
public serviceInstallationFailed(): void {
|
||||
this._statusBarItem.command = undefined;
|
||||
this._statusBarItem.text = Constants.serviceInstallationFailed;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
|
||||
private showProgress(statusText: string): void {
|
||||
let index = 0;
|
||||
let progressTicks = [ '|', '/', '-', '\\'];
|
||||
|
||||
|
||||
this._progressTimerId = setInterval(() => {
|
||||
index++;
|
||||
if (index > 3) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
let progressTick = progressTicks[index];
|
||||
if (this._statusBarItem.text !== Constants.serviceInstalled) {
|
||||
this._statusBarItem.text = statusText + ' ' + progressTick;
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.destroyStatusBar();
|
||||
}
|
||||
|
||||
private hideLastShownStatusBar(): void {
|
||||
if (typeof this._statusBarItem !== 'undefined') {
|
||||
this._statusBarItem.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
|
||||
// Hide the most recently shown status bar
|
||||
this.hideLastShownStatusBar();
|
||||
}
|
||||
|
||||
private onDidCloseTextDocument(doc: vscode.TextDocument): void {
|
||||
// Remove the status bar associated with the document
|
||||
this.destroyStatusBar();
|
||||
}
|
||||
|
||||
private destroyStatusBar(): void {
|
||||
if (typeof this._statusBarItem !== 'undefined') {
|
||||
this._statusBarItem.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,63 +3,100 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as Platform from '../models/platform';
|
||||
import {Runtime, PlatformInformation} from '../models/platform';
|
||||
import Config from '../configurations/config';
|
||||
import ServiceDownloadProvider from './download';
|
||||
import ServerProvider from './server';
|
||||
import {IExtensionWrapper, ILogger, IStatusView} from './interfaces';
|
||||
import {IStatusView} from './interfaces';
|
||||
import {ILogger} from '../models/interfaces';
|
||||
|
||||
class StubStatusView implements IStatusView {
|
||||
installingService(fileUri: string): void {
|
||||
console.log('Installing service');
|
||||
installingService(): void {
|
||||
console.log('...');
|
||||
}
|
||||
serviceInstalled(fileUri: string): void {
|
||||
serviceInstalled(): void {
|
||||
console.log('Service installed');
|
||||
}
|
||||
serviceInstallationFailed(fileUri: string): void {
|
||||
serviceInstallationFailed(): void {
|
||||
console.log('Service installation failed');
|
||||
}
|
||||
updateServiceDownloadingProgress(downloadPercentage: number): void {
|
||||
if (downloadPercentage === 100) {
|
||||
process.stdout.write('100%');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StubLogger implements ILogger {
|
||||
logDebug(message: string): void {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
class StubVsCode implements IExtensionWrapper {
|
||||
getActiveTextEditorUri(): string {
|
||||
return '';
|
||||
increaseIndent(): void {
|
||||
console.log('increaseIndent');
|
||||
}
|
||||
|
||||
decreaseIndent(): void {
|
||||
console.log('decreaseIndent');
|
||||
}
|
||||
|
||||
append(message?: string): void {
|
||||
process.stdout.write(message);
|
||||
}
|
||||
appendLine(message?: string): void {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
const config = new Config();
|
||||
const logger = new StubLogger();
|
||||
const statusView = new StubStatusView();
|
||||
const stubVsCode = new StubVsCode();
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger, statusView);
|
||||
let serverProvider = new ServerProvider(downloadProvider, config, statusView);
|
||||
|
||||
/*
|
||||
* Installs the service for the given platform if it's not already installed.
|
||||
*/
|
||||
export function installService(platform: Platform.Runtime): Promise<String> {
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger);
|
||||
let serverProvider = new ServerProvider(downloadProvider, config, statusView, stubVsCode);
|
||||
return serverProvider.getServerPath(platform);
|
||||
export function installService(runtime: Runtime): Promise<String> {
|
||||
if (runtime === undefined) {
|
||||
return PlatformInformation.GetCurrent().then( platformInfo => {
|
||||
if (platformInfo.isValidRuntime()) {
|
||||
return serverProvider.getOrDownloadServer(platformInfo.runtimeId);
|
||||
} else {
|
||||
throw new Error('unsupported runtime');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return serverProvider.getOrDownloadServer(runtime);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the install folder path for given platform.
|
||||
*/
|
||||
export function getServiceInstallDirectory(platform: Platform.Runtime): string {
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger);
|
||||
return downloadProvider.getInstallDirectory(platform);
|
||||
export function getServiceInstallDirectory(runtime: Runtime): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (runtime === undefined) {
|
||||
PlatformInformation.GetCurrent().then( platformInfo => {
|
||||
if (platformInfo.isValidRuntime()) {
|
||||
resolve(downloadProvider.getInstallDirectory(platformInfo.runtimeId));
|
||||
} else {
|
||||
reject('unsupported runtime');
|
||||
}
|
||||
}).catch( error => {
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
resolve(downloadProvider.getInstallDirectory(runtime));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the path to the root folder of service install location.
|
||||
*/
|
||||
export function getServiceInstallDirectoryRoot(): string {
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger);
|
||||
let directoryPath: string = downloadProvider.getInstallDirectoryRoot();
|
||||
directoryPath = directoryPath.replace('\\{#version#}\\{#platform#}', '');
|
||||
directoryPath = directoryPath.replace('/{#version#}/{#platform#}', '');
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
|
||||
import { ExtensionContext, workspace, languages } from 'vscode';
|
||||
import { ExtensionContext, workspace, window, OutputChannel, languages } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, ServerOptions,
|
||||
TransportKind, RequestType, NotificationType, NotificationHandler,
|
||||
ErrorAction, CloseAction } from 'vscode-languageclient';
|
||||
|
@ -13,15 +13,16 @@ import VscodeWrapper from '../controllers/vscodeWrapper';
|
|||
import Telemetry from '../models/telemetry';
|
||||
import * as Utils from '../models/utils';
|
||||
import {VersionRequest} from '../models/contracts';
|
||||
import {Logger} from '../models/logger';
|
||||
import Constants = require('../models/constants');
|
||||
import ServerProvider from './server';
|
||||
import ServiceDownloadProvider from './download';
|
||||
import {ExtensionWrapper, Logger} from './extUtil';
|
||||
import ExtConfig from '../configurations/extConfig';
|
||||
import StatusView from '../views/statusView';
|
||||
import {Runtime, PlatformInformation} from '../models/platform';
|
||||
import {PlatformInformation} from '../models/platform';
|
||||
import {ServerInitializationResult, ServerStatusView} from './serverStatus';
|
||||
|
||||
let opener = require('opener');
|
||||
let _channel: OutputChannel = undefined;
|
||||
|
||||
/**
|
||||
* @interface IMessage
|
||||
|
@ -116,36 +117,72 @@ export default class SqlToolsServiceClient {
|
|||
this._client = client;
|
||||
}
|
||||
|
||||
constructor(private _server: ServerProvider) {
|
||||
constructor(private _server: ServerProvider, private _logger: Logger) {
|
||||
}
|
||||
|
||||
// gets or creates the singleton SQL Tools service client instance
|
||||
public static get instance(): SqlToolsServiceClient {
|
||||
if (this._instance === undefined) {
|
||||
let config = new ExtConfig();
|
||||
let logger = new Logger();
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger);
|
||||
let statusView = new StatusView();
|
||||
let extWrapper = new ExtensionWrapper();
|
||||
let serviceProvider = new ServerProvider(downloadProvider, config, statusView, extWrapper);
|
||||
_channel = window.createOutputChannel(Constants.sqlToolsServiceName);
|
||||
let logger = new Logger(text => _channel.append(text));
|
||||
let statusView = new ServerStatusView();
|
||||
let downloadProvider = new ServiceDownloadProvider(config, logger, statusView);
|
||||
let serviceProvider = new ServerProvider(downloadProvider, config, statusView);
|
||||
|
||||
this._instance = new SqlToolsServiceClient(serviceProvider);
|
||||
this._instance = new SqlToolsServiceClient(serviceProvider, logger);
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
// initialize the SQL Tools Service Client instance by launching
|
||||
// out-of-proc server through the LanguageClient
|
||||
public initialize(context: ExtensionContext): Promise<boolean> {
|
||||
public initialize(context: ExtensionContext): Promise<ServerInitializationResult> {
|
||||
this._logger.appendLine(Constants.serviceInitializing);
|
||||
|
||||
return PlatformInformation.GetCurrent().then( platformInfo => {
|
||||
if (platformInfo.runtimeId === Runtime.UnknownRuntime) {
|
||||
throw new Error('Invalid Platform');
|
||||
} else {
|
||||
return this.initializeService(platformInfo.runtimeId, context);
|
||||
}
|
||||
return this.initializeForPlatform(platformInfo, context);
|
||||
});
|
||||
}
|
||||
|
||||
public initializeForPlatform(platformInfo: PlatformInformation, context: ExtensionContext): Promise<ServerInitializationResult> {
|
||||
return new Promise<ServerInitializationResult>( (resolve, reject) => {
|
||||
this._logger.appendLine(Constants.commandsNotAvailableWhileInstallingTheService);
|
||||
this._logger.appendLine();
|
||||
this._logger.append(`Platform: ${platformInfo.toString()}`);
|
||||
if (!platformInfo.isValidRuntime()) {
|
||||
Utils.showErrorMsg(Constants.unsupportedPlatformErrorMessage);
|
||||
reject('Invalid Platform');
|
||||
} else {
|
||||
if (platformInfo.runtimeId) {
|
||||
this._logger.appendLine(` (${platformInfo.getRuntimeDisplayName()})`);
|
||||
} else {
|
||||
this._logger.appendLine();
|
||||
}
|
||||
this._logger.appendLine();
|
||||
this._server.getServerPath(platformInfo.runtimeId).then(serverPath => {
|
||||
if (serverPath === undefined) {
|
||||
// Check if the service already installed and if not open the output channel to show the logs
|
||||
if (_channel !== undefined) {
|
||||
_channel.show();
|
||||
}
|
||||
this._server.downloadServerFiles(platformInfo.runtimeId).then ( installedServerPath => {
|
||||
this.initializeLanguageClient(installedServerPath, context);
|
||||
resolve(new ServerInitializationResult(true, true, installedServerPath));
|
||||
});
|
||||
} else {
|
||||
this.initializeLanguageClient(serverPath, context);
|
||||
resolve(new ServerInitializationResult(false, true, serverPath));
|
||||
}
|
||||
}).catch(err => {
|
||||
Utils.logDebug(Constants.serviceLoadingFailed + ' ' + err );
|
||||
Utils.showErrorMsg(Constants.serviceLoadingFailed);
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SQL language configuration
|
||||
*
|
||||
|
@ -176,63 +213,67 @@ export default class SqlToolsServiceClient {
|
|||
});
|
||||
}
|
||||
|
||||
private initializeService(runtime: Runtime, context: ExtensionContext): Promise<boolean> {
|
||||
let self = this;
|
||||
private initializeLanguageClient(serverPath: string, context: ExtensionContext): void {
|
||||
if (serverPath === undefined) {
|
||||
Utils.logDebug(Constants.invalidServiceFilePath);
|
||||
throw new Error(Constants.invalidServiceFilePath);
|
||||
} else {
|
||||
let self = this;
|
||||
self.initializeLanguageConfiguration();
|
||||
let serverOptions: ServerOptions = this.createServerOptions(serverPath);
|
||||
this.client = this.createLanguageClient(serverOptions);
|
||||
|
||||
return new Promise<boolean>( (resolve, reject) => {
|
||||
this._server.getServerPath(runtime).then(serverPath => {
|
||||
self.initializeLanguageConfiguration();
|
||||
|
||||
let serverArgs = [];
|
||||
let serverCommand = serverPath;
|
||||
if (serverPath === undefined) {
|
||||
Utils.logDebug(Constants.invalidServiceFilePath);
|
||||
throw new Error(Constants.invalidServiceFilePath);
|
||||
} else if (serverPath.endsWith('.dll')) {
|
||||
serverArgs = [serverPath];
|
||||
serverCommand = 'dotnet';
|
||||
}
|
||||
|
||||
// Enable diagnostic logging in the service if it is configured
|
||||
let config = workspace.getConfiguration(Constants.extensionConfigSectionName);
|
||||
if (config) {
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo) {
|
||||
serverArgs.push('--enable-logging');
|
||||
}
|
||||
}
|
||||
|
||||
// run the service host using dotnet.exe from the path
|
||||
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
|
||||
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector: ['sql'],
|
||||
synchronize: {
|
||||
configurationSection: 'mssql'
|
||||
},
|
||||
errorHandler: new LanguageClientErrorHandler()
|
||||
};
|
||||
|
||||
// cache the client instance for later use
|
||||
this.client = new LanguageClient('sqlserverclient', serverOptions, clientOptions);
|
||||
this.client.onReady().then( () => {
|
||||
this.checkServiceCompatibility();
|
||||
});
|
||||
if (context !== undefined) {
|
||||
// Create the language client and start the client.
|
||||
let disposable = this.client.start();
|
||||
|
||||
// Push the disposable to the context's subscriptions so that the
|
||||
// client can be deactivated on extension deactivation
|
||||
context.subscriptions.push(disposable);
|
||||
resolve(true);
|
||||
|
||||
}).catch(err => {
|
||||
Utils.logDebug(Constants.serviceLoadingFailed + ' ' + err );
|
||||
Utils.showErrorMsg(Constants.serviceLoadingFailed);
|
||||
reject(err);
|
||||
});
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createLanguageClient(serverOptions: ServerOptions): LanguageClient {
|
||||
// Options to control the language client
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
documentSelector: ['sql'],
|
||||
synchronize: {
|
||||
configurationSection: 'mssql'
|
||||
},
|
||||
errorHandler: new LanguageClientErrorHandler()
|
||||
};
|
||||
|
||||
// cache the client instance for later use
|
||||
let client = new LanguageClient(Constants.sqlToolsServiceName, serverOptions, clientOptions);
|
||||
client.onReady().then( () => {
|
||||
this.checkServiceCompatibility();
|
||||
});
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private createServerOptions(servicePath): ServerOptions {
|
||||
let serverArgs = [];
|
||||
let serverCommand: string = servicePath;
|
||||
if (servicePath.endsWith('.dll')) {
|
||||
serverArgs = [servicePath];
|
||||
serverCommand = 'dotnet';
|
||||
}
|
||||
|
||||
// Enable diagnostic logging in the service if it is configured
|
||||
let config = workspace.getConfiguration(Constants.extensionConfigSectionName);
|
||||
if (config) {
|
||||
let logDebugInfo = config[Constants.configLogDebugInfo];
|
||||
if (logDebugInfo) {
|
||||
serverArgs.push('--enable-logging');
|
||||
}
|
||||
}
|
||||
|
||||
// run the service host using dotnet.exe from the path
|
||||
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
|
||||
return serverOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -180,10 +180,15 @@ export const unfoundResult = 'Data was disposed when text editor was closed; to
|
|||
|
||||
export const serviceCompatibleVersion = '1.0.0';
|
||||
export const serviceNotCompatibleError = 'Client is not compatible with the service layer';
|
||||
export const serviceInstalling = 'Installing Sql Tools Service';
|
||||
export const serviceInstalling = 'Installing';
|
||||
export const serviceInstallingTo = 'Installing SQL tools service to';
|
||||
export const serviceInitializing = 'Initializing SQL tools service for the mssql extension.';
|
||||
export const commandsNotAvailableWhileInstallingTheService = 'Note: mssql commands will be available after installing the service.';
|
||||
export const serviceDownloading = 'Downloading';
|
||||
export const serviceInstalled = 'Sql Tools Service installed';
|
||||
export const serviceInstallationFailed = 'Failed to install Sql Tools Service';
|
||||
export const serviceLoadingFailed = 'Failed to load Sql Tools Service';
|
||||
export const unsupportedPlatformErrorMessage = 'The platform is not supported';
|
||||
export const invalidServiceFilePath = 'Invalid file path for Sql Tools Service';
|
||||
export const extensionNotInitializedError = 'Unable to execute the command while the extension is initializing. Please try again later.';
|
||||
|
||||
|
@ -225,6 +230,10 @@ export const macOpenSslErrorMessage = `OpenSSL version >=1.0.1 is required to co
|
|||
export const macOpenSslHelpButton = 'Help';
|
||||
export const macOpenSslHelpLink = 'https://github.com/Microsoft/vscode-mssql/wiki/OpenSSL-Configuration';
|
||||
|
||||
export const sqlToolsServiceName = 'SQLToolsService';
|
||||
|
||||
|
||||
|
||||
export const gettingStartedGuideLink = 'https://aka.ms/mssql-getting-started';
|
||||
|
||||
export const sqlToolsServiceCrashMessage = 'SQL Tools Service component could not start.';
|
||||
|
|
|
@ -277,3 +277,11 @@ export interface IResultsConfig {
|
|||
shortcuts: { [key: string]: string };
|
||||
messagesDefaultOpen: boolean;
|
||||
}
|
||||
|
||||
export interface ILogger {
|
||||
logDebug(message: string): void;
|
||||
increaseIndent(): void;
|
||||
decreaseIndent(): void;
|
||||
append(message?: string): void;
|
||||
appendLine(message?: string): void;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as os from 'os';
|
||||
import {ILogger} from './interfaces';
|
||||
import * as Utils from './utils';
|
||||
|
||||
/*
|
||||
* Logger class handles logging messages using the Util functions.
|
||||
*/
|
||||
export class Logger implements ILogger {
|
||||
private _writer: (message: string) => void;
|
||||
private _prefix: string;
|
||||
|
||||
private _indentLevel: number = 0;
|
||||
private _indentSize: number = 4;
|
||||
private _atLineStart: boolean = false;
|
||||
|
||||
constructor(writer: (message: string) => void, prefix?: string) {
|
||||
this._writer = writer;
|
||||
this._prefix = prefix;
|
||||
}
|
||||
|
||||
public logDebug(message: string): void {
|
||||
Utils.logDebug(message);
|
||||
}
|
||||
|
||||
private _appendCore(message: string): void {
|
||||
if (this._atLineStart) {
|
||||
if (this._indentLevel > 0) {
|
||||
const indent = ' '.repeat(this._indentLevel * this._indentSize);
|
||||
this._writer(indent);
|
||||
}
|
||||
|
||||
if (this._prefix) {
|
||||
this._writer(`[${this._prefix}] `);
|
||||
}
|
||||
|
||||
this._atLineStart = false;
|
||||
}
|
||||
|
||||
this._writer(message);
|
||||
}
|
||||
|
||||
public increaseIndent(): void {
|
||||
this._indentLevel += 1;
|
||||
}
|
||||
|
||||
public decreaseIndent(): void {
|
||||
if (this._indentLevel > 0) {
|
||||
this._indentLevel -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public append(message?: string): void {
|
||||
message = message || '';
|
||||
this._appendCore(message);
|
||||
}
|
||||
|
||||
public appendLine(message?: string): void {
|
||||
message = message || '';
|
||||
this._appendCore(message + os.EOL);
|
||||
this._atLineStart = true;
|
||||
}
|
||||
}
|
|
@ -76,6 +76,14 @@ export class PlatformInformation {
|
|||
return this.platform === 'linux';
|
||||
}
|
||||
|
||||
public isValidRuntime(): boolean {
|
||||
return this.runtimeId !== undefined && this.runtimeId !== Runtime.UnknownRuntime && this.runtimeId !== Runtime.UnknownVersion;
|
||||
}
|
||||
|
||||
public getRuntimeDisplayName(): string {
|
||||
return getRuntimeDisplayName(this.runtimeId);
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let result = this.platform;
|
||||
|
||||
|
@ -345,9 +353,11 @@ export class LinuxDistribution {
|
|||
let key = line.substring(0, equalsIndex);
|
||||
let value = line.substring(equalsIndex + 1);
|
||||
|
||||
// Strip double quotes if necessary
|
||||
// Strip quotes if necessary
|
||||
if (value.length > 1 && value.startsWith('"') && value.endsWith('"')) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
} else if (value.length > 1 && value.startsWith('\'') && value.endsWith('\'')) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
}
|
||||
|
||||
if (key === 'ID') {
|
||||
|
|
|
@ -23,7 +23,6 @@ class FileStatusBar {
|
|||
export default class StatusView implements vscode.Disposable {
|
||||
private _statusBars: { [fileUri: string]: FileStatusBar };
|
||||
private _lastShownStatusBar: FileStatusBar;
|
||||
private _numberOfSecondsBeforeHidingMessage = 5000;
|
||||
|
||||
constructor() {
|
||||
this._statusBars = {};
|
||||
|
@ -156,32 +155,6 @@ export default class StatusView implements vscode.Disposable {
|
|||
this.showProgress(fileUri, Constants.cancelingQueryLabel, bar.statusQuery);
|
||||
}
|
||||
|
||||
public installingService(fileUri: string): void {
|
||||
let bar = this.getStatusBar(fileUri);
|
||||
bar.statusConnection.command = undefined;
|
||||
this.showStatusBarItem(fileUri, bar.statusConnection);
|
||||
this.showProgress(fileUri, Constants.serviceInstalling, bar.statusConnection);
|
||||
}
|
||||
|
||||
public serviceInstalled(fileUri: string): void {
|
||||
let bar = this.getStatusBar(fileUri);
|
||||
bar.statusConnection.command = undefined;
|
||||
bar.statusConnection.text = Constants.serviceInstalled;
|
||||
this.showStatusBarItem(fileUri, bar.statusConnection);
|
||||
// Cleat the status bar after 2 seconds
|
||||
setTimeout(() => {
|
||||
bar.statusConnection.text = '';
|
||||
this.showStatusBarItem(fileUri, bar.statusConnection);
|
||||
}, this._numberOfSecondsBeforeHidingMessage);
|
||||
}
|
||||
|
||||
public serviceInstallationFailed(fileUri: string): void {
|
||||
let bar = this.getStatusBar(fileUri);
|
||||
bar.statusConnection.command = undefined;
|
||||
bar.statusConnection.text = Constants.serviceInstallationFailed;
|
||||
this.showStatusBarItem(fileUri, bar.statusConnection);
|
||||
}
|
||||
|
||||
public languageServiceUpdating(fileUri: string): void {
|
||||
let bar = this.getStatusBar(fileUri);
|
||||
bar.statusLanguageService.text = Constants.updatingIntelliSenseLabel;
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import assert = require('assert');
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import {IConfig} from '../src/languageservice/interfaces';
|
||||
import {IConfig, IStatusView} from '../src/languageservice/interfaces';
|
||||
import ServiceDownloadProvider from '../src/languageservice/download';
|
||||
import Config from '../src/configurations/config';
|
||||
import * as Platform from '../src/models/platform';
|
||||
import {ServerStatusView} from '../src/languageservice/serverStatus';
|
||||
import {Runtime} from '../src/models/platform';
|
||||
import * as path from 'path';
|
||||
|
||||
suite('ServiceDownloadProvider Tests', () => {
|
||||
let config: TypeMoq.Mock<IConfig>;
|
||||
let testStatusView: TypeMoq.Mock<IStatusView>;
|
||||
|
||||
setup(() => {
|
||||
config = TypeMoq.Mock.ofType(Config, TypeMoq.MockBehavior.Strict);
|
||||
testStatusView = TypeMoq.Mock.ofType(ServerStatusView, TypeMoq.MockBehavior.Strict);
|
||||
});
|
||||
|
||||
test('getInstallDirectory should return the exact value from config if the path is absolute', (done) => {
|
||||
|
@ -20,8 +23,8 @@ suite('ServiceDownloadProvider Tests', () => {
|
|||
let expected = expectedPathFromConfig;
|
||||
config.setup(x => x.getSqlToolsInstallDirectory()).returns(() => expectedPathFromConfig);
|
||||
config.setup(x => x.getSqlToolsPackageVersion()).returns(() => expectedVersionFromConfig);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined);
|
||||
let actual = downloadProvider.getInstallDirectory(Platform.Runtime.OSX_10_11_64);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined, testStatusView.object);
|
||||
let actual = downloadProvider.getInstallDirectory(Runtime.OSX_10_11_64);
|
||||
assert.equal(expected, actual);
|
||||
done();
|
||||
});
|
||||
|
@ -34,8 +37,8 @@ suite('ServiceDownloadProvider Tests', () => {
|
|||
let expected = __dirname + '/0.0.4';
|
||||
config.setup(x => x.getSqlToolsInstallDirectory()).returns(() => expectedPathFromConfig);
|
||||
config.setup(x => x.getSqlToolsPackageVersion()).returns(() => expectedVersionFromConfig);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined);
|
||||
let actual = downloadProvider.getInstallDirectory(Platform.Runtime.OSX_10_11_64);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined, testStatusView.object);
|
||||
let actual = downloadProvider.getInstallDirectory(Runtime.OSX_10_11_64);
|
||||
assert.equal(expected, actual);
|
||||
done();
|
||||
});
|
||||
|
@ -48,8 +51,8 @@ suite('ServiceDownloadProvider Tests', () => {
|
|||
let expected = __dirname + '/0.0.4/OSX';
|
||||
config.setup(x => x.getSqlToolsInstallDirectory()).returns(() => expectedPathFromConfig);
|
||||
config.setup(x => x.getSqlToolsPackageVersion()).returns(() => expectedVersionFromConfig);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined);
|
||||
let actual = downloadProvider.getInstallDirectory(Platform.Runtime.OSX_10_11_64);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined, testStatusView.object);
|
||||
let actual = downloadProvider.getInstallDirectory(Runtime.OSX_10_11_64);
|
||||
assert.equal(expected, actual);
|
||||
done();
|
||||
});
|
||||
|
@ -62,11 +65,25 @@ suite('ServiceDownloadProvider Tests', () => {
|
|||
let expected = path.join(__dirname, '../../service/0.0.4/OSX');
|
||||
config.setup(x => x.getSqlToolsInstallDirectory()).returns(() => expectedPathFromConfig);
|
||||
config.setup(x => x.getSqlToolsPackageVersion()).returns(() => expectedVersionFromConfig);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined);
|
||||
let actual = downloadProvider.getInstallDirectory(Platform.Runtime.OSX_10_11_64);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined, testStatusView.object);
|
||||
let actual = downloadProvider.getInstallDirectory(Runtime.OSX_10_11_64);
|
||||
assert.equal(expected, actual);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('getDownloadFileName should return the expected file name given a runtime', (done) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let expectedName = 'expected';
|
||||
let fileNamesJson = {Windows_7_64: `${expectedName}`};
|
||||
config.setup(x => x.getSqlToolsConfigValue('downloadFileNames')).returns(() => fileNamesJson);
|
||||
let downloadProvider = new ServiceDownloadProvider(config.object, undefined, testStatusView.object);
|
||||
let actual = downloadProvider.getDownloadFileName(Runtime.Windows_7_64);
|
||||
assert.equal(actual, expectedName);
|
||||
done();
|
||||
}).catch( error => {
|
||||
assert.fail(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import assert = require('assert');
|
||||
import {Runtime, PlatformInformation} from '../src/models/platform';
|
||||
import { expect } from 'chai';
|
||||
import {Runtime, PlatformInformation, LinuxDistribution} from '../src/models/platform';
|
||||
import Telemetry from '../src/models/telemetry';
|
||||
|
||||
function getPlatform(): Promise<Runtime> {
|
||||
|
@ -9,6 +10,7 @@ function getPlatform(): Promise<Runtime> {
|
|||
}
|
||||
|
||||
suite('Platform Tests', () => {
|
||||
|
||||
setup(() => {
|
||||
// Ensure that telemetry is disabled while testing
|
||||
Telemetry.disable();
|
||||
|
@ -20,4 +22,223 @@ suite('Platform Tests', () => {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('Retrieve correct information for Ubuntu 14.04', () => {
|
||||
const dist = distro_ubuntu_14_04();
|
||||
expect(dist.name).to.equal('ubuntu');
|
||||
expect(dist.version).to.equal('14.04');
|
||||
});
|
||||
|
||||
test('Retrieve correct information for Ubuntu 14.04 with quotes', () => {
|
||||
const dist = distro_ubuntu_14_04_with_quotes();
|
||||
expect(dist.name).to.equal('ubuntu');
|
||||
expect(dist.version).to.equal('14.04');
|
||||
});
|
||||
|
||||
test('Retrieve correct information for Fedora 23', () => {
|
||||
const dist = distro_fedora_23();
|
||||
expect(dist.name).to.equal('fedora');
|
||||
expect(dist.version).to.equal('23');
|
||||
});
|
||||
|
||||
test('Retrieve correct information for Debian 8', () => {
|
||||
const dist = distro_debian_8();
|
||||
|
||||
expect(dist.name).to.equal('debian');
|
||||
expect(dist.version).to.equal('8');
|
||||
});
|
||||
|
||||
test('Retrieve correct information for CentOS 7', () => {
|
||||
const dist = distro_centos_7();
|
||||
|
||||
expect(dist.name).to.equal('centos');
|
||||
expect(dist.version).to.equal('7');
|
||||
});
|
||||
|
||||
test('Compute correct RID for Windows 64-bit', () => {
|
||||
const platformInfo = new PlatformInformation('win32', 'x86_64');
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.Windows_7_64.toString());
|
||||
});
|
||||
|
||||
test('Compute no RID for Windows with bad architecture', () => {
|
||||
const platformInfo = new PlatformInformation('win32', 'bad');
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(undefined);
|
||||
});
|
||||
|
||||
test('Compute correct RID for OSX', () => {
|
||||
const platformInfo = new PlatformInformation('darwin', 'x86_64');
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.OSX_10_11_64.toString());
|
||||
});
|
||||
|
||||
test('Compute no RID for OSX with 32-bit architecture', () => {
|
||||
const platformInfo = new PlatformInformation('darwin', 'x86');
|
||||
|
||||
expect(platformInfo.runtimeId, undefined);
|
||||
});
|
||||
|
||||
test('Compute correct RID for Ubuntu 14.04', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_ubuntu_14_04());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.Ubuntu_14.toString());
|
||||
});
|
||||
|
||||
test('Compute correct RID for Fedora 23', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_fedora_23());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.Fedora_23.toString());
|
||||
});
|
||||
|
||||
test('Compute correct RID for Debian 8', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_debian_8());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.Debian_8.toString());
|
||||
});
|
||||
|
||||
test('Compute correct RID for CentOS 7', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_centos_7());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.CentOS_7.toString());
|
||||
});
|
||||
|
||||
test('Compute correct RID for KDE neon', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_kde_neon_5_8());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal(Runtime.Ubuntu_16.toString());
|
||||
});
|
||||
|
||||
test('Compute no RID for CentOS 7 with 32-bit architecture', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86', distro_centos_7());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal( undefined);
|
||||
});
|
||||
|
||||
test('Compute no RID for fake distro with no ID_LIKE', () => {
|
||||
const platformInfo = new PlatformInformation('linux', 'x86_64', distro_unknown_no_id_like());
|
||||
|
||||
expect(platformInfo.runtimeId).to.equal( undefined);
|
||||
});
|
||||
});
|
||||
|
||||
function distro_ubuntu_14_04(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on Ubuntu 14.04
|
||||
const input = `
|
||||
NAME="Ubuntu"
|
||||
VERSION="14.04.5 LTS, Trusty Tahr"
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
PRETTY_NAME="Ubuntu 14.04.5 LTS"
|
||||
VERSION_ID="14.04"
|
||||
HOME_URL="http://www.ubuntu.com/"
|
||||
SUPPORT_URL="http://help.ubuntu.com/"
|
||||
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_ubuntu_14_04_with_quotes(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on Ubuntu 14.04
|
||||
const input = `
|
||||
NAME='Ubuntu'
|
||||
VERSION='14.04.5 LTS, Trusty Tahr'
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
PRETTY_NAME='Ubuntu 14.04.5 LTS'
|
||||
VERSION_ID='14.04'
|
||||
HOME_URL='http://www.ubuntu.com/'
|
||||
SUPPORT_URL='http://help.ubuntu.com/'
|
||||
BUG_REPORT_URL='http://bugs.launchpad.net/ubuntu/'`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_fedora_23(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on Fedora 23
|
||||
const input = `
|
||||
NAME=Fedora
|
||||
VERSION="23 (Workstation Edition)"
|
||||
ID=fedora
|
||||
VERSION_ID=23
|
||||
PRETTY_NAME="Fedora 23 (Workstation Edition)"
|
||||
ANSI_COLOR="0;34"
|
||||
CPE_NAME="cpe:/o:fedoraproject:fedora:23"
|
||||
HOME_URL="https://fedoraproject.org/"
|
||||
BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||
REDHAT_BUGZILLA_PRODUCT_VERSION=23
|
||||
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION=23
|
||||
PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy
|
||||
VARIANT="Workstation Edition"
|
||||
VARIANT_ID=workstation`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_debian_8(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on Debian 8
|
||||
const input = `
|
||||
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||
NAME="Debian GNU/Linux"
|
||||
VERSION_ID="8"
|
||||
VERSION="8 (jessie)"
|
||||
ID=debian
|
||||
HOME_URL="http://www.debian.org/"
|
||||
SUPPORT_URL="http://www.debian.org/support"
|
||||
BUG_REPORT_URL="https://bugs.debian.org/"`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_centos_7(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on CentOS 7
|
||||
const input = `
|
||||
NAME="CentOS Linux"
|
||||
VERSION="7 (Core)"
|
||||
ID="centos"
|
||||
ID_LIKE="rhel fedora"
|
||||
VERSION_ID="7"
|
||||
PRETTY_NAME="CentOS Linux 7 (Core)"
|
||||
ANSI_COLOR="0;31"
|
||||
CPE_NAME="cpe:/o:centos:centos:7"
|
||||
HOME_URL="https://www.centos.org/"
|
||||
BUG_REPORT_URL="https://bugs.centos.org/"
|
||||
|
||||
CENTOS_MANTISBT_PROJECT="CentOS-7"
|
||||
CENTOS_MANTISBT_PROJECT_VERSION="7"
|
||||
REDHAT_SUPPORT_PRODUCT="centos"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION="7"`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_kde_neon_5_8(): LinuxDistribution {
|
||||
// Copied from /etc/os-release on KDE Neon 5.8
|
||||
const input = `
|
||||
NAME="KDE neon"
|
||||
VERSION="5.8"
|
||||
ID=neon
|
||||
ID_LIKE="ubuntu debian"
|
||||
PRETTY_NAME="KDE neon User Edition 5.8"
|
||||
VERSION_ID="16.04"
|
||||
HOME_URL="http://neon.kde.org/"
|
||||
SUPPORT_URL="http://neon.kde.org/"
|
||||
BUG_REPORT_URL="http://bugs.kde.org/"
|
||||
VERSION_CODENAME=xenial
|
||||
UBUNTU_CODENAME=xenial`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
||||
function distro_unknown_no_id_like(): LinuxDistribution {
|
||||
const input = `
|
||||
PRETTY_NAME="Make believe 1.0"
|
||||
NAME="Make believe"
|
||||
VERSION_ID="1.0"
|
||||
VERSION="1.0 (rogers)"
|
||||
ID=MakeBelieve`;
|
||||
|
||||
return LinuxDistribution.FromReleaseInfo(input, '\n');
|
||||
}
|
||||
|
|
|
@ -2,120 +2,129 @@ import * as TypeMoq from 'typemoq';
|
|||
import assert = require('assert');
|
||||
import ServiceDownloadProvider from '../src/languageservice/download';
|
||||
import ServerProvider from '../src/languageservice/server';
|
||||
import StatusView from './../src/views/statusView';
|
||||
import {ServerStatusView} from '../src/languageservice/serverStatus';
|
||||
import Config from './../src/configurations/config';
|
||||
import {ExtensionWrapper} from '../src/languageservice/extUtil';
|
||||
import * as path from 'path';
|
||||
import {Runtime} from '../src/models/platform';
|
||||
import {IConfig, IStatusView, IExtensionWrapper} from '../src/languageservice/interfaces';
|
||||
import {IConfig, IStatusView} from '../src/languageservice/interfaces';
|
||||
|
||||
interface IFixture {
|
||||
executableFileName: string;
|
||||
executablesFromConfig: string[];
|
||||
runtime: Runtime;
|
||||
installDir: string;
|
||||
}
|
||||
|
||||
suite('Server tests', () => {
|
||||
|
||||
let testDownloadProvider: TypeMoq.Mock<ServiceDownloadProvider>;
|
||||
let testStatusView: TypeMoq.Mock<IStatusView>;
|
||||
let testConfig: TypeMoq.Mock<IConfig>;
|
||||
let testVsCode: TypeMoq.Mock<IExtensionWrapper>;
|
||||
|
||||
setup(() => {
|
||||
testDownloadProvider = TypeMoq.Mock.ofType(ServiceDownloadProvider, TypeMoq.MockBehavior.Strict);
|
||||
testStatusView = TypeMoq.Mock.ofType(StatusView, TypeMoq.MockBehavior.Strict);
|
||||
testStatusView = TypeMoq.Mock.ofType(ServerStatusView, TypeMoq.MockBehavior.Strict);
|
||||
testConfig = TypeMoq.Mock.ofType(Config, TypeMoq.MockBehavior.Strict);
|
||||
testVsCode = TypeMoq.Mock.ofType(ExtensionWrapper, TypeMoq.MockBehavior.Strict);
|
||||
});
|
||||
|
||||
test('findServerPath should return error given a folder with no installed service', () => {
|
||||
let installDir = __dirname;
|
||||
const platform = Runtime.Windows_7_64;
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', 'exeFile2']);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
function setupMocks(fixture: IFixture): void {
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => fixture.executablesFromConfig);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(fixture.runtime)).returns(() => fixture.installDir);
|
||||
testDownloadProvider.setup(x => x.InstallSQLToolsService(fixture.runtime)).callback(() => {
|
||||
fixture.executablesFromConfig = [fixture.executableFileName.replace(fixture.installDir, '')];
|
||||
}).returns(() => { return Promise.resolve(true); });
|
||||
}
|
||||
|
||||
server.findServerPath(installDir).then( result => {
|
||||
test('findServerPath should return error given a folder with no installed service', () => {
|
||||
let fixture: IFixture = {
|
||||
executableFileName: '',
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: ['exeFile1', 'exeFile2']
|
||||
};
|
||||
|
||||
setupMocks(fixture);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
return server.findServerPath(fixture.installDir).then( result => {
|
||||
assert.equal(result, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
test('findServerPath should return the file path given a file that exists', () => {
|
||||
let installDir = __dirname;
|
||||
let fileName = path.join(installDir, __filename);
|
||||
const platform = Runtime.Windows_7_64;
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
let fixture: IFixture = {
|
||||
executableFileName: __filename,
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: undefined
|
||||
};
|
||||
setupMocks(fixture);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
server.findServerPath(fileName).then( result => {
|
||||
assert.equal(result, fileName);
|
||||
return server.findServerPath(fixture.executableFileName).then( result => {
|
||||
assert.equal(result, fixture.executableFileName);
|
||||
});
|
||||
});
|
||||
|
||||
test('findServerPath should not return the given file path if doesn not exist', () => {
|
||||
let installDir = __dirname;
|
||||
let fileName = path.join(installDir, __filename);
|
||||
const platform = Runtime.Windows_7_64;
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', 'exeFile2']);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
let fixture: IFixture = {
|
||||
executableFileName: __filename,
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: ['exeFile1', 'exeFile2']
|
||||
};
|
||||
setupMocks(fixture);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
server.findServerPath(fileName).then( result => {
|
||||
assert.equal(fileName, undefined);
|
||||
return server.findServerPath(fixture.installDir).then( result => {
|
||||
assert.equal(result, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
test('findServerPath should return a valid file path given a folder with installed service', () => {
|
||||
let installDir = __dirname;
|
||||
let fileName = __filename;
|
||||
const platform = Runtime.Windows_7_64;
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', fileName]);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
let fixture: IFixture = {
|
||||
executableFileName: __filename,
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: ['exeFile1', __filename]
|
||||
};
|
||||
setupMocks(fixture);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
server.findServerPath(fileName).then( result => {
|
||||
assert.equal(result, path.join(installDir, fileName));
|
||||
return server.findServerPath(fixture.executableFileName).then( result => {
|
||||
assert.equal(result, fixture.executableFileName);
|
||||
});
|
||||
});
|
||||
|
||||
test('getServerPath should download the service if not exist and return the valid service file path', () => {
|
||||
let installDir = __dirname;
|
||||
let fileName: string = __filename.replace(installDir, '');
|
||||
const platform = Runtime.Windows_7_64;
|
||||
let executables: string[] = ['exeFile1'];
|
||||
test('getOrDownloadServer should download the service if not exist and return the valid service file path', () => {
|
||||
let fixture: IFixture = {
|
||||
executableFileName: __filename,
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: ['exeFile1']
|
||||
};
|
||||
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => executables);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testStatusView.setup(x => x.serviceInstalled(TypeMoq.It.isAny()));
|
||||
testStatusView.setup(x => x.installingService(TypeMoq.It.isAny()));
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
testDownloadProvider.setup(x => x.go(platform)).callback(() => {
|
||||
executables = [fileName];
|
||||
setupMocks(fixture);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
}).returns(() => { return Promise.resolve(true); });
|
||||
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
|
||||
server.getServerPath(platform).then( result => {
|
||||
assert.equal(result, path.join(installDir, fileName));
|
||||
return server.getOrDownloadServer(fixture.runtime).then( result => {
|
||||
assert.equal(result, fixture.executableFileName);
|
||||
});
|
||||
});
|
||||
|
||||
test('getServerPath should not download the service if already exist', () => {
|
||||
let installDir = __dirname;
|
||||
let fileName: string = __filename.replace(installDir, '');
|
||||
const platform = Runtime.Windows_7_64;
|
||||
let executables: string[] = [fileName];
|
||||
test('getOrDownloadServer should not download the service if already exist', () => {
|
||||
let fixture: IFixture = {
|
||||
executableFileName: __filename,
|
||||
runtime: Runtime.Windows_7_64,
|
||||
installDir: __dirname,
|
||||
executablesFromConfig: [__filename.replace(__dirname, '')]
|
||||
};
|
||||
|
||||
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => executables);
|
||||
testDownloadProvider.setup(x => x.getInstallDirectory(platform)).returns(() => installDir);
|
||||
testStatusView.setup(x => x.serviceInstalled(TypeMoq.It.isAny()));
|
||||
testStatusView.setup(x => x.installingService(TypeMoq.It.isAny()));
|
||||
testVsCode.setup(x => x.getActiveTextEditorUri()).returns(() => 'test');
|
||||
setupMocks(fixture);
|
||||
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object, testVsCode.object);
|
||||
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
|
||||
|
||||
server.getServerPath(platform).then( result => {
|
||||
assert.equal(result, path.join(installDir, fileName));
|
||||
return server.getOrDownloadServer(fixture.runtime).then( result => {
|
||||
assert.equal(result, fixture.executableFileName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import * as TypeMoq from 'typemoq';
|
||||
import assert = require('assert');
|
||||
import ServerProvider from '../src/languageservice/server';
|
||||
import SqlToolsServiceClient from '../src/languageservice/serviceClient';
|
||||
import {Logger} from '../src/models/logger';
|
||||
import {PlatformInformation} from '../src/models/platform';
|
||||
|
||||
interface IFixture {
|
||||
platformInfo: PlatformInformation;
|
||||
installedServerPath: string;
|
||||
downloadedServerPath: string;
|
||||
}
|
||||
|
||||
suite('Service Client tests', () => {
|
||||
|
||||
let testServiceProvider: TypeMoq.Mock<ServerProvider>;
|
||||
let logger = new Logger(text => console.log(text));
|
||||
|
||||
setup(() => {
|
||||
testServiceProvider = TypeMoq.Mock.ofType(ServerProvider, TypeMoq.MockBehavior.Strict);
|
||||
});
|
||||
|
||||
function setupMocks(fixture: IFixture): void {
|
||||
testServiceProvider.setup(x => x.downloadServerFiles(fixture.platformInfo.runtimeId)).returns(() => {
|
||||
return Promise.resolve(fixture.downloadedServerPath);
|
||||
});
|
||||
testServiceProvider.setup(x => x.getServerPath(fixture.platformInfo.runtimeId)).returns(() => {
|
||||
return Promise.resolve(fixture.installedServerPath);
|
||||
});
|
||||
}
|
||||
|
||||
test('initializeForPlatform should not install the service if already exists', () => {
|
||||
let fixture: IFixture = {
|
||||
installedServerPath: 'already installed service',
|
||||
downloadedServerPath: undefined,
|
||||
platformInfo: new PlatformInformation('win32', 'x86_64', undefined)
|
||||
};
|
||||
|
||||
setupMocks(fixture);
|
||||
let serviceClinet = new SqlToolsServiceClient(testServiceProvider.object, logger);
|
||||
|
||||
return serviceClinet.initializeForPlatform(fixture.platformInfo, undefined).then( result => {
|
||||
assert.notEqual(result, undefined);
|
||||
assert.equal(result.serverPath, fixture.installedServerPath);
|
||||
assert.equal(result.installedBeforeInitializing, false);
|
||||
});
|
||||
});
|
||||
|
||||
test('initializeForPlatform should install the service if not exists', () => {
|
||||
let fixture: IFixture = {
|
||||
installedServerPath: undefined,
|
||||
downloadedServerPath: 'downloaded service',
|
||||
platformInfo: new PlatformInformation('win32', 'x86_64', undefined)
|
||||
};
|
||||
|
||||
setupMocks(fixture);
|
||||
let serviceClinet = new SqlToolsServiceClient(testServiceProvider.object, logger);
|
||||
|
||||
return serviceClinet.initializeForPlatform(fixture.platformInfo, undefined).then( result => {
|
||||
assert.notEqual(result, undefined);
|
||||
assert.equal(result.serverPath, fixture.downloadedServerPath);
|
||||
assert.equal(result.installedBeforeInitializing, true);
|
||||
});
|
||||
});
|
||||
|
||||
test('initializeForPlatform should fails given unsupported platform', () => {
|
||||
let fixture: IFixture = {
|
||||
installedServerPath: 'already installed service',
|
||||
downloadedServerPath: undefined,
|
||||
platformInfo: new PlatformInformation('invalid platform', 'x86_64', undefined)
|
||||
};
|
||||
|
||||
setupMocks(fixture);
|
||||
let serviceClinet = new SqlToolsServiceClient(testServiceProvider.object, logger);
|
||||
|
||||
return serviceClinet.initializeForPlatform(fixture.platformInfo, undefined).catch( error => {
|
||||
return assert.equal(error, 'Invalid Platform');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,529 @@
|
|||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/typed-typings/npm-assertion-error/105841317bd2bdd5d110bfb763e49e482a77230d/main.d.ts
|
||||
declare module '~chai~assertion-error' {
|
||||
// Type definitions for assertion-error 1.0.0
|
||||
// Project: https://github.com/chaijs/assertion-error
|
||||
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>
|
||||
// Definitions: https://github.com/borisyankov/DefinitelyTyped
|
||||
|
||||
export class AssertionError implements Error {
|
||||
constructor(message: string, props?: any, ssf?: Function);
|
||||
public name: string;
|
||||
public message: string;
|
||||
public showDiff: boolean;
|
||||
public stack: string;
|
||||
|
||||
/**
|
||||
* Allow errors to be converted to JSON for static transfer.
|
||||
*
|
||||
* @param {Boolean} include stack (default: `true`)
|
||||
* @return {Object} object that can be `JSON.stringify`
|
||||
*/
|
||||
public toJSON(stack: boolean): Object;
|
||||
}
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Assert.d.ts
|
||||
declare module '~chai/lib/Assert' {
|
||||
export interface AssertStatic extends Assert {
|
||||
}
|
||||
|
||||
export interface Assert {
|
||||
/**
|
||||
* @param expression Expression to test for truthiness.
|
||||
* @param message Message to display on error.
|
||||
*/
|
||||
(expression: any, message?: string): void;
|
||||
(expression: any, messageCallback: () => string): void;
|
||||
|
||||
fail(actual?: any, expected?: any, msg?: string, operator?: string): void;
|
||||
|
||||
ok(val: any, msg?: string): void;
|
||||
isOk(val: any, msg?: string): void;
|
||||
notOk(val: any, msg?: string): void;
|
||||
isNotOk(val: any, msg?: string): void;
|
||||
|
||||
equal(act: any, exp: any, msg?: string): void;
|
||||
notEqual(act: any, exp: any, msg?: string): void;
|
||||
|
||||
strictEqual(act: any, exp: any, msg?: string): void;
|
||||
notStrictEqual(act: any, exp: any, msg?: string): void;
|
||||
|
||||
deepEqual(act: any, exp: any, msg?: string): void;
|
||||
notDeepEqual(act: any, exp: any, msg?: string): void;
|
||||
|
||||
isTrue(val: any, msg?: string): void;
|
||||
isFalse(val: any, msg?: string): void;
|
||||
|
||||
isNotTrue(val: any, msg?: string): void;
|
||||
isNotFalse(val: any, msg?: string): void;
|
||||
|
||||
isNull(val: any, msg?: string): void;
|
||||
isNotNull(val: any, msg?: string): void;
|
||||
|
||||
isUndefined(val: any, msg?: string): void;
|
||||
isDefined(val: any, msg?: string): void;
|
||||
|
||||
isNaN(val: any, msg?: string): void;
|
||||
isNotNaN(val: any, msg?: string): void;
|
||||
|
||||
isAbove(val: number, abv: number, msg?: string): void;
|
||||
isBelow(val: number, blw: number, msg?: string): void;
|
||||
|
||||
isAtLeast(val: number, atlst: number, msg?: string): void;
|
||||
isAtMost(val: number, atmst: number, msg?: string): void;
|
||||
|
||||
isFunction(val: any, msg?: string): void;
|
||||
isNotFunction(val: any, msg?: string): void;
|
||||
|
||||
isObject(val: any, msg?: string): void;
|
||||
isNotObject(val: any, msg?: string): void;
|
||||
|
||||
isArray(val: any, msg?: string): void;
|
||||
isNotArray(val: any, msg?: string): void;
|
||||
|
||||
isString(val: any, msg?: string): void;
|
||||
isNotString(val: any, msg?: string): void;
|
||||
|
||||
isNumber(val: any, msg?: string): void;
|
||||
isNotNumber(val: any, msg?: string): void;
|
||||
|
||||
isBoolean(val: any, msg?: string): void;
|
||||
isNotBoolean(val: any, msg?: string): void;
|
||||
|
||||
typeOf(val: any, type: string, msg?: string): void;
|
||||
notTypeOf(val: any, type: string, msg?: string): void;
|
||||
|
||||
instanceOf(val: any, type: Function, msg?: string): void;
|
||||
notInstanceOf(val: any, type: Function, msg?: string): void;
|
||||
|
||||
include(exp: string, inc: any, msg?: string): void;
|
||||
include(exp: any[], inc: any, msg?: string): void;
|
||||
include(exp: Object, inc: Object, msg?: string): void;
|
||||
|
||||
notInclude(exp: string, inc: any, msg?: string): void;
|
||||
notInclude(exp: any[], inc: any, msg?: string): void;
|
||||
|
||||
match(exp: any, re: RegExp, msg?: string): void;
|
||||
notMatch(exp: any, re: RegExp, msg?: string): void;
|
||||
|
||||
property(obj: Object, prop: string, msg?: string): void;
|
||||
notProperty(obj: Object, prop: string, msg?: string): void;
|
||||
deepProperty(obj: Object, prop: string, msg?: string): void;
|
||||
notDeepProperty(obj: Object, prop: string, msg?: string): void;
|
||||
|
||||
propertyVal(obj: Object, prop: string, val: any, msg?: string): void;
|
||||
propertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
|
||||
|
||||
deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): void;
|
||||
deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
|
||||
|
||||
lengthOf(exp: any, len: number, msg?: string): void;
|
||||
|
||||
throw(fn: Function, msg?: string): void;
|
||||
throw(fn: Function, regExp: RegExp): void;
|
||||
throw(fn: Function, errType: Function, msg?: string): void;
|
||||
throw(fn: Function, errType: Function, regExp: RegExp): void;
|
||||
|
||||
throws(fn: Function, msg?: string): void;
|
||||
throws(fn: Function, regExp: RegExp): void;
|
||||
throws(fn: Function, errType: Function, msg?: string): void;
|
||||
throws(fn: Function, errType: Function, regExp: RegExp): void;
|
||||
|
||||
Throw(fn: Function, msg?: string): void;
|
||||
Throw(fn: Function, regExp: RegExp): void;
|
||||
Throw(fn: Function, errType: Function, msg?: string): void;
|
||||
Throw(fn: Function, errType: Function, regExp: RegExp): void;
|
||||
|
||||
doesNotThrow(fn: Function, msg?: string): void;
|
||||
doesNotThrow(fn: Function, regExp: RegExp): void;
|
||||
doesNotThrow(fn: Function, errType: Function, msg?: string): void;
|
||||
doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void;
|
||||
|
||||
operator(val: any, operator: string, val2: any, msg?: string): void;
|
||||
closeTo(act: number, exp: number, delta: number, msg?: string): void;
|
||||
approximately(act: number, exp: number, delta: number, msg?: string): void;
|
||||
|
||||
sameMembers(set1: any[], set2: any[], msg?: string): void;
|
||||
sameDeepMembers(set1: any[], set2: any[], msg?: string): void;
|
||||
includeMembers(superset: any[], subset: any[], msg?: string): void;
|
||||
includeDeepMembers(superset: any[], subset: any[], msg?: string): void;
|
||||
|
||||
ifError(val: any, msg?: string): void;
|
||||
|
||||
isExtensible(obj: {}, msg?: string): void;
|
||||
extensible(obj: {}, msg?: string): void;
|
||||
isNotExtensible(obj: {}, msg?: string): void;
|
||||
notExtensible(obj: {}, msg?: string): void;
|
||||
|
||||
isSealed(obj: {}, msg?: string): void;
|
||||
sealed(obj: {}, msg?: string): void;
|
||||
isNotSealed(obj: {}, msg?: string): void;
|
||||
notSealed(obj: {}, msg?: string): void;
|
||||
|
||||
isFrozen(obj: Object, msg?: string): void;
|
||||
frozen(obj: Object, msg?: string): void;
|
||||
isNotFrozen(obj: Object, msg?: string): void;
|
||||
notFrozen(obj: Object, msg?: string): void;
|
||||
|
||||
oneOf(inList: any, list: any[], msg?: string): void;
|
||||
|
||||
changes(fn: Function, obj: {}, property: string): void;
|
||||
doesNotChange(fn: Function, obj: {}, property: string): void;
|
||||
increases(fn: Function, obj: {}, property: string): void;
|
||||
doesNotIncrease(fn: Function, obj: {}, property: string): void;
|
||||
|
||||
decreases(fn: Function, obj: {}, property: string): void;
|
||||
doesNotDecrease(fn: Function, obj: {}, property: string): void;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Assert' {
|
||||
export * from '~chai/lib/Assert';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Assertion.d.ts
|
||||
declare module '~chai/lib/Assertion' {
|
||||
export interface AssertionStatic {
|
||||
(target?: any, message?: string, stack?: Function): Assertion;
|
||||
new (target?: any, message?: string, stack?: Function): Assertion;
|
||||
}
|
||||
|
||||
export interface Assertion extends LanguageChains, NumericComparison, TypeComparison {
|
||||
not: Assertion;
|
||||
deep: Deep;
|
||||
any: KeyFilter;
|
||||
all: KeyFilter;
|
||||
a: TypeComparison;
|
||||
an: TypeComparison;
|
||||
include: Include;
|
||||
includes: Include;
|
||||
contain: Include;
|
||||
contains: Include;
|
||||
ok: Assertion;
|
||||
true: Assertion;
|
||||
false: Assertion;
|
||||
null: Assertion;
|
||||
undefined: Assertion;
|
||||
NaN: Assertion;
|
||||
exist: Assertion;
|
||||
empty: Assertion;
|
||||
arguments: Assertion;
|
||||
Arguments: Assertion;
|
||||
equal: Equal;
|
||||
equals: Equal;
|
||||
eq: Equal;
|
||||
eql: Equal;
|
||||
eqls: Equal;
|
||||
property: Property;
|
||||
ownProperty: OwnProperty;
|
||||
haveOwnProperty: OwnProperty;
|
||||
ownPropertyDescriptor: OwnPropertyDescriptor;
|
||||
haveOwnPropertyDescriptor: OwnPropertyDescriptor;
|
||||
length: Length;
|
||||
lengthOf: Length;
|
||||
match: Match;
|
||||
matches: Match;
|
||||
string(str: string, message?: string): Assertion;
|
||||
keys: Keys;
|
||||
key(str: string): Assertion;
|
||||
throw: Throw;
|
||||
throws: Throw;
|
||||
Throw: Throw;
|
||||
respondTo: RespondTo;
|
||||
respondsTo: RespondTo;
|
||||
itself: Assertion;
|
||||
satisfy: Satisfy;
|
||||
satisfies: Satisfy;
|
||||
closeTo: CloseTo;
|
||||
approximately: CloseTo;
|
||||
members: Members;
|
||||
increase: PropertyChange;
|
||||
increases: PropertyChange;
|
||||
decrease: PropertyChange;
|
||||
decreases: PropertyChange;
|
||||
change: PropertyChange;
|
||||
changes: PropertyChange;
|
||||
extensible: Assertion;
|
||||
sealed: Assertion;
|
||||
frozen: Assertion;
|
||||
oneOf(list: any[], message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface LanguageChains {
|
||||
to: Assertion;
|
||||
be: Assertion;
|
||||
been: Assertion;
|
||||
is: Assertion;
|
||||
that: Assertion;
|
||||
which: Assertion;
|
||||
and: Assertion;
|
||||
has: Assertion;
|
||||
have: Assertion;
|
||||
with: Assertion;
|
||||
at: Assertion;
|
||||
of: Assertion;
|
||||
same: Assertion;
|
||||
}
|
||||
|
||||
export interface NumericComparison {
|
||||
above: NumberComparer;
|
||||
gt: NumberComparer;
|
||||
greaterThan: NumberComparer;
|
||||
least: NumberComparer;
|
||||
gte: NumberComparer;
|
||||
below: NumberComparer;
|
||||
lt: NumberComparer;
|
||||
lessThan: NumberComparer;
|
||||
most: NumberComparer;
|
||||
lte: NumberComparer;
|
||||
within(start: number, finish: number, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface NumberComparer {
|
||||
(value: number, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface TypeComparison {
|
||||
(type: string, message?: string): Assertion;
|
||||
instanceof: InstanceOf;
|
||||
instanceOf: InstanceOf;
|
||||
}
|
||||
|
||||
export interface InstanceOf {
|
||||
(constructor: Object, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface CloseTo {
|
||||
(expected: number, delta: number, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Deep {
|
||||
equal: Equal;
|
||||
equals: Equal;
|
||||
eq: Equal;
|
||||
include: Include;
|
||||
property: Property;
|
||||
members: Members;
|
||||
}
|
||||
|
||||
export interface KeyFilter {
|
||||
keys: Keys;
|
||||
}
|
||||
|
||||
export interface Equal {
|
||||
(value: any, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Property {
|
||||
(name: string, value?: any, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface OwnProperty {
|
||||
(name: string, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface OwnPropertyDescriptor {
|
||||
(name: string, descriptor: PropertyDescriptor, message?: string): Assertion;
|
||||
(name: string, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Length extends LanguageChains, NumericComparison {
|
||||
(length: number, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Include {
|
||||
(value: Object, message?: string): Assertion;
|
||||
(value: string, message?: string): Assertion;
|
||||
(value: number, message?: string): Assertion;
|
||||
string(value: string, message?: string): Assertion;
|
||||
keys: Keys;
|
||||
members: Members;
|
||||
any: KeyFilter;
|
||||
all: KeyFilter;
|
||||
}
|
||||
|
||||
export interface Match {
|
||||
(regexp: RegExp | string, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Keys {
|
||||
(...keys: any[]): Assertion;
|
||||
(keys: any[]): Assertion;
|
||||
(keys: Object): Assertion;
|
||||
}
|
||||
|
||||
export interface Throw {
|
||||
(): Assertion;
|
||||
(expected: string, message?: string): Assertion;
|
||||
(expected: RegExp, message?: string): Assertion;
|
||||
(constructor: Error, expected?: string, message?: string): Assertion;
|
||||
(constructor: Error, expected?: RegExp, message?: string): Assertion;
|
||||
(constructor: Function, expected?: string, message?: string): Assertion;
|
||||
(constructor: Function, expected?: RegExp, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface RespondTo {
|
||||
(method: string, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Satisfy {
|
||||
(matcher: Function, message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface Members {
|
||||
(set: any[], message?: string): Assertion;
|
||||
}
|
||||
|
||||
export interface PropertyChange {
|
||||
(object: Object, prop: string, msg?: string): Assertion;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Assertion' {
|
||||
export * from '~chai/lib/Assertion';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Expect.d.ts
|
||||
declare module '~chai/lib/Expect' {
|
||||
import {AssertionStatic} from '~chai/lib/Assertion';
|
||||
|
||||
export interface ExpectStatic extends AssertionStatic {
|
||||
fail(actual?: any, expected?: any, message?: string, operator?: string): void;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Expect' {
|
||||
export * from '~chai/lib/Expect';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Should.d.ts
|
||||
declare module '~chai/lib/Should' {
|
||||
export interface Should extends ShouldAssertion {
|
||||
not: ShouldAssertion;
|
||||
fail(actual: any, expected: any, message?: string, operator?: string): void;
|
||||
}
|
||||
|
||||
export interface ShouldAssertion {
|
||||
Throw: ShouldThrow;
|
||||
throw: ShouldThrow;
|
||||
equal(value1: any, value2: any, message?: string): void;
|
||||
exist(value: any, message?: string): void;
|
||||
}
|
||||
|
||||
export interface ShouldThrow {
|
||||
(actual: Function): void;
|
||||
(actual: Function, expected: string | RegExp, message?: string): void;
|
||||
(actual: Function, constructor: Error | Function, expected?: string | RegExp, message?: string): void;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Should' {
|
||||
export * from '~chai/lib/Should';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Config.d.ts
|
||||
declare module '~chai/lib/Config' {
|
||||
export interface Config {
|
||||
includeStack: boolean;
|
||||
showDiff: boolean;
|
||||
truncateThreshold: number;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Config' {
|
||||
export * from '~chai/lib/Config';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Utils.d.ts
|
||||
declare module '~chai/lib/Utils' {
|
||||
import {Assertion} from '~chai/lib/Assertion';
|
||||
|
||||
export interface PathInfo {
|
||||
parent: any;
|
||||
name: number|string;
|
||||
value: any;
|
||||
exists: boolean;
|
||||
}
|
||||
|
||||
export interface Utils {
|
||||
addChainableMethod(ctx: any, name: string, chainingBehavior: (value: any) => void): void;
|
||||
addMethod(ctx: any, name: string, method: (value: any) => void): void;
|
||||
addProperty(ctx: any, name: string, getter: () => void): void;
|
||||
expectTypes(obj: Object, types: string[]): void;
|
||||
flag(obj: Object, key: string, value?: any): any;
|
||||
getActual(obj: Object, actual?: any): any;
|
||||
getEnumerableProperties(obj: Object): string[];
|
||||
getMessage(obj: Object, params: any[]): string;
|
||||
getMessage(obj: Object, message: string, negateMessage: string): string;
|
||||
getName(func: Function): string;
|
||||
getPathInfo(path: string, obj: Object): PathInfo;
|
||||
getPathValue(path: string, obj: Object): any;
|
||||
getProperties(obj: Object): string[];
|
||||
hasProperty(obj: Object, name: string): boolean;
|
||||
transferFlags(assertion: Assertion | any, obj: Object, includeAll?: boolean): void;
|
||||
inspect(obj: any): any;
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Utils' {
|
||||
export * from '~chai/lib/Utils';
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/lib/Chai.d.ts
|
||||
declare module '~chai/lib/Chai' {
|
||||
import * as AE from '~chai~assertion-error';
|
||||
|
||||
import * as Assert from '~chai/lib/Assert';
|
||||
import * as A from '~chai/lib/Assertion';
|
||||
import * as Expect from '~chai/lib/Expect';
|
||||
import * as Should from '~chai/lib/Should';
|
||||
import * as Config from '~chai/lib/Config';
|
||||
import * as Utils from '~chai/lib/Utils';
|
||||
|
||||
namespace chai {
|
||||
export interface AssertionStatic extends A.AssertionStatic {}
|
||||
export class AssertionError extends AE.AssertionError {}
|
||||
export var Assertion: A.AssertionStatic;
|
||||
export var expect: Expect.ExpectStatic;
|
||||
export var assert: Assert.AssertStatic;
|
||||
export var config: Config.Config;
|
||||
export var util: Utils.Utils;
|
||||
export function should(): Should.Should;
|
||||
export function Should(): Should.Should;
|
||||
/**
|
||||
* Provides a way to extend the internals of Chai
|
||||
*/
|
||||
export function use(fn: (chai: any, utils: Utils.Utils) => void): typeof chai;
|
||||
}
|
||||
|
||||
export = chai;
|
||||
|
||||
/* tslint:disable:no-internal-module */
|
||||
global {
|
||||
interface Object {
|
||||
should: A.Assertion;
|
||||
}
|
||||
}
|
||||
}
|
||||
declare module 'chai/lib/Chai' {
|
||||
import main = require('~chai/lib/Chai');
|
||||
export = main;
|
||||
}
|
||||
|
||||
// Generated by typings
|
||||
// Source: https://raw.githubusercontent.com/types/npm-chai/793bee097a6a644e078a033603d88ac89eb7b560/index.d.ts
|
||||
declare module 'chai' {
|
||||
// Type definitions for chai 3.4.0
|
||||
// Project: http://chaijs.com/
|
||||
// Original Definitions by: Jed Mao <https://github.com/jedmao/>,
|
||||
// Bart van der Schoor <https://github.com/Bartvds>,
|
||||
// Andrew Brown <https://github.com/AGBrown>,
|
||||
// Olivier Chevet <https://github.com/olivr70>,
|
||||
// Matt Wistrand <https://github.com/mwistrand>
|
||||
|
||||
import chai = require('~chai/lib/Chai');
|
||||
|
||||
export = chai;
|
||||
}
|
Загрузка…
Ссылка в новой задаче