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:
Leila Lali 2016-12-02 11:44:45 -08:00 коммит произвёл GitHub
Родитель 64e33bd9e4
Коммит 0d63812208
19 изменённых файлов: 1462 добавлений и 319 удалений

Просмотреть файл

@ -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;
}

66
src/models/logger.ts Normal file
Просмотреть файл

@ -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');
});
});
});

529
typings/chai.d.ts поставляемый Normal file
Просмотреть файл

@ -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;
}