downloading the SQL tools service if does not exist (#70)

* downloading the SQL tools service if does not exist before loading the extension
This commit is contained in:
Leila Lali 2016-09-13 15:57:29 -07:00 коммит произвёл GitHub
Родитель de2c4d5973
Коммит d6593bd1eb
20 изменённых файлов: 807 добавлений и 63 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -8,4 +8,5 @@ packages
*.nupkg
*.vsix
tools
examples
examples
sqltoolsservice

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

@ -1,4 +1,5 @@
var gulp = require('gulp');
var rename = require('gulp-rename');
var install = require('gulp-install');
var tslint = require('gulp-tslint');
var ts = require('gulp-typescript');
@ -156,10 +157,12 @@ gulp.task('ext:copy-tests', () => {
.pipe(gulp.dest(config.paths.project.root + '/out/test/resources/'))
});
gulp.task('ext:copy-packages', () => {
var serviceHostVersion = "0.0.9";
return gulp.src(config.paths.project.root + '/packages/Microsoft.SqlTools.ServiceLayer.' + serviceHostVersion + '/lib/netcoreapp1.0/**/*')
.pipe(gulp.dest(config.paths.project.root + '/out/tools/'))
gulp.task('ext:copy-config', () => {
var env = process.env.VsMsSqlEnv;
env = env == undefined ? "dev" : env;
return gulp.src(config.paths.project.root + '/src/configurations/' + env + '.config.json')
.pipe(rename('config.json'))
.pipe(gulp.dest(config.paths.project.root + '/out/src'));
});
gulp.task('ext:copy-js', () => {
@ -169,7 +172,7 @@ gulp.task('ext:copy-js', () => {
.pipe(gulp.dest(config.paths.project.root + '/out/src'))
});
gulp.task('ext:copy', gulp.series('ext:copy-tests', 'ext:copy-packages', 'ext:copy-js'));
gulp.task('ext:copy', gulp.series('ext:copy-tests', 'ext:copy-js', 'ext:copy-config'));
gulp.task('ext:build', gulp.series('ext:nuget-download', 'ext:nuget-restore', 'ext:lint', 'ext:compile', 'ext:copy'));

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

@ -48,6 +48,7 @@
"gulp-sourcemaps": "^1.6.0",
"gulp-tslint": "^6.0.2",
"gulp-typescript": "^2.13.6",
"gulp-rename": "^1.2.2",
"pm-mocha-jenkins-reporter": "^0.2.6",
"tslint": "^3.14.0",
"typescript": "^1.8.9",
@ -63,7 +64,12 @@
"request": "^2.73.0",
"underscore": "^1.8.3",
"vscode-extension-telemetry": "^0.0.5",
"vscode-languageclient": "^2.0.0"
"vscode-languageclient": "^2.0.0",
"fs-extra-promise": "^0.3.1",
"http-proxy-agent": "^1.0.0",
"https-proxy-agent": "^1.0.0",
"tmp": "^0.0.28",
"decompress": "^4.0.0"
},
"contributes": {
"languages": [

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

@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const fs = require('fs');
import * as path from 'path';
import Utils = require('../models/utils');
export default class Config {
private static _configJsonContent = undefined;
public static get configJsonContent(): any {
if (this._configJsonContent === undefined) {
this._configJsonContent = this.loadConfig();
}
return this._configJsonContent;
}
public getSqlToolsServiceDownloadUrl(): string {
try {
let json = Config.configJsonContent;
return json.sqlToolsService.downloadUrl + '/' + json.sqlToolsService.version;
} catch (error) {
Utils.showErrorMsg(error);
throw(error);
}
}
public getSqlToolsInstallDirectory(): string {
try {
let json = Config.configJsonContent;
return json.sqlToolsService.installDir;
} catch (error) {
Utils.showErrorMsg(error);
throw(error);
}
}
public getSqlToolsExecutableFiles(): string[] {
try {
let json = Config.configJsonContent;
return json.sqlToolsService.executableFiles;
} catch (error) {
Utils.showErrorMsg(error);
throw(error);
}
}
static loadConfig(): any {
let configContent = fs.readFileSync(path.join(__dirname, '../config.json'));
return JSON.parse(configContent);
}
}

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

@ -0,0 +1,8 @@
{
"sqlToolsService": {
"downloadUrl": "http://dtnuget:8080/download/microsoft.sqltools.servicelayer",
"version": "0.0.10",
"installDir": "../../../sqltoolsservice",
"executableFiles": ["Microsoft.SqlTools.ServiceLayer.exe", "Microsoft.SqlTools.ServiceLayer", "Microsoft.SqlTools.ServiceLayer.dll"]
}
}

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

@ -0,0 +1,6 @@
{
"sqlToolsService": {
"downloadUrl": "",
"version": "0.0.8"
}
}

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

@ -58,7 +58,9 @@ export default class ConnectionManager {
this.vscodeWrapper.onDidCloseTextDocument(params => this.onDidCloseTextDocument(params));
this.vscodeWrapper.onDidSaveTextDocument(params => this.onDidSaveTextDocument(params));
this.client.onNotification(ConnectionContracts.ConnectionChangedNotification.type, this.handleConnectionChangedNotification());
if (this.client !== undefined) {
this.client.onNotification(ConnectionContracts.ConnectionChangedNotification.type, this.handleConnectionChangedNotification());
}
}
private get vscodeWrapper(): VscodeWrapper {

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

@ -21,6 +21,7 @@ export default class MainController implements vscode.Disposable {
private _connectionMgr: ConnectionManager;
private _prompter: IPrompter;
private _vscodeWrapper: VscodeWrapper;
private _initialized: boolean = false;
constructor(context: vscode.ExtensionContext,
connectionManager?: ConnectionManager,
@ -51,7 +52,7 @@ export default class MainController implements vscode.Disposable {
this._statusview.dispose();
}
public activate(): void {
public activate(): Promise<boolean> {
const self = this;
let activationTimer = new Utils.Timer();
@ -72,33 +73,46 @@ export default class MainController implements vscode.Disposable {
this._vscodeWrapper = new VscodeWrapper();
// initialize language service client
SqlToolsServerClient.instance.initialize(this._context);
// Init status bar
this._statusview = new StatusView();
// Init CodeAdapter for use when user response to questions is needed
this._prompter = new CodeAdapter();
// Init content provider for results pane
this._outputContentProvider = new SqlOutputContentProvider(self._context, self._statusview);
let registration = vscode.workspace.registerTextDocumentContentProvider(SqlOutputContentProvider.providerName, self._outputContentProvider);
this._context.subscriptions.push(registration);
// Init connection manager and connection MRU
this._connectionMgr = new ConnectionManager(self._context, self._statusview, self._prompter);
activationTimer.end();
// telemetry for activation
Telemetry.sendTelemetryEvent(this._context, 'ExtensionActivated', {},
{ activationTime: activationTimer.getDuration() }
);
Utils.logDebug(Constants.extensionActivated);
return this.initialize(activationTimer);
}
public isInitialized(): boolean {
return this._initialized;
}
public initialize(activationTimer: Utils.Timer): Promise<boolean> {
// initialize language service client
return new Promise<boolean>( (resolve, reject) => {
SqlToolsServerClient.instance.initialize(this._context).then(() => {
const self = this;
// Init status bar
this._statusview = new StatusView();
// Init CodeAdapter for use when user response to questions is needed
this._prompter = new CodeAdapter();
// Init content provider for results pane
this._outputContentProvider = new SqlOutputContentProvider(self._context, self._statusview);
let registration = vscode.workspace.registerTextDocumentContentProvider(SqlOutputContentProvider.providerName, self._outputContentProvider);
this._context.subscriptions.push(registration);
// Init connection manager and connection MRU
this._connectionMgr = new ConnectionManager(self._context, self._statusview, self._prompter);
activationTimer.end();
// telemetry for activation
Telemetry.sendTelemetryEvent(this._context, 'ExtensionActivated', {},
{ activationTime: activationTimer.getDuration() }
);
Utils.logDebug(Constants.extensionActivated);
this._initialized = true;
resolve(true);
});
});
}
// Choose a new database from the current server
private onChooseDatabase(): Promise<boolean> {
return this._connectionMgr.onChooseDatabase();

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

@ -6,10 +6,10 @@ let controller: MainController = undefined;
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext): void {
export function activate(context: vscode.ExtensionContext): Promise<boolean> {
controller = new MainController(context);
context.subscriptions.push(controller);
controller.activate();
return controller.activate();
}
// this method is called when your extension is deactivated

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

@ -0,0 +1,192 @@
/*---------------------------------------------------------------------------------------------
* 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 https from 'https';
import * as http from 'http';
import * as stream from 'stream';
import {parse} from 'url';
import {Platform} from '../models/platform';
import {getProxyAgent} from './proxy';
import Utils = require('../models/utils');
import Config from '../configurations/config';
import * as path from 'path';
import { workspace } from 'vscode';
let tmp = require('tmp');
let fs = require('fs');
const decompress = require('decompress');
tmp.setGracefulCleanup();
/*
* Service Download Provider class which handles downloading the SQL Tools service.
*/
export default class ServiceDownloadProvider {
constructor(private _config: Config) {
}
/**
* Returns the download url for given platfotm
*/
public getDownloadFileName(platform: Platform): string {
let fileName = 'microsoft.sqltools.servicelayer-';
switch (platform) {
case Platform.Windows:
fileName += 'win-x64-netcoreapp1.0.zip';
break;
case Platform.OSX:
fileName += 'osx-x64-netcoreapp1.0.tar.gz';
break;
case Platform.CentOS:
fileName += 'centos-x64-netcoreapp1.0.tar.gz';
break;
case Platform.Debian:
fileName += 'debian-x64-netcoreapp1.0.tar.gz';
break;
case Platform.Fedora:
fileName += 'fedora-x64-netcoreapp1.0.tar.gz';
break;
case Platform.OpenSUSE:
fileName += 'opensuse-x64-netcoreapp1.0.tar.gz';
break;
case Platform.RHEL:
fileName += 'rhel-x64-netcoreapp1.0.tar.gz';
break;
case Platform.Ubuntu14:
fileName += 'ubuntu14-x64-netcoreapp1.0.tar.gz';
break;
case Platform.Ubuntu16:
fileName += 'ubuntu16-x64-netcoreapp1.0.tar.gz';
break;
default:
if (process.platform === 'linux') {
throw new Error('Unsupported linux distribution');
} else {
throw new Error('Unsupported platform: ${process.platform}');
}
}
return fileName;
}
private download(urlString: string, proxy?: string, strictSSL?: boolean): Promise<stream.Readable> {
process.on('uncaughtException', function (err): void {
console.log(err);
});
let url = parse(urlString);
const agent = getProxyAgent(url, proxy, strictSSL);
let client = url.protocol === 'http:' ? http : https;
let options: http.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent,
port: +url.port
};
if (url.protocol === 'https:') {
let httpsOptions: https.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent,
port: +url.port
};
options = httpsOptions;
}
return new Promise<stream.Readable>((resolve, reject) => {
return client.get(options, res => {
// handle redirection
if (res.statusCode === 302) {
return this.download(res.headers.location);
} else if (res.statusCode !== 200) {
return reject(Error('Download failed with code ${res.statusCode}.'));
}
return resolve(res);
});
});
}
/**
* Returns SQL tools service installed folder.
*/
public getInstallDirectory(): string {
let installDirFromConfig = this._config.getSqlToolsInstallDirectory();
const basePath = path.join(__dirname, installDirFromConfig);
if (!fs.existsSync(basePath)) {
fs.mkdirSync(basePath);
}
return basePath;
}
/**
* Downloads the SQL tools service and decompress it in the install folder.
*/
public go(platform: Platform): Promise<boolean> {
const config = workspace.getConfiguration();
const proxy = config.get<string>('http.proxy');
const strictSSL = config.get('http.proxyStrictSSL', true);
return new Promise<boolean>((resolve, reject) => {
const fileName = this.getDownloadFileName( platform);
const installDirectory = this.getInstallDirectory();
Utils.logDebug('Installing sql tools service to ${installDirectory}');
let baseDownloadUrl = this._config.getSqlToolsServiceDownloadUrl();
const urlString = baseDownloadUrl + '/' + fileName;
Utils.logDebug('Attempting to download ${fileName}');
return this.download(urlString, proxy, strictSSL)
.then(inStream => {
tmp.file((err, tmpPath, fd, cleanupCallback) => {
if (err) {
return reject(err);
}
Utils.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.
Utils.logDebug('Download complete!');
Utils.logDebug('Decompressing...');
return decompress(tmpPath, installDirectory)
.then(files => {
Utils.logDebug('Done! ${files.length} files unpacked.\n');
return resolve(true);
})
.catch(decompressErr => {
Utils.logDebug('[ERROR] ${err}');
return reject(decompressErr);
});
});
inStream.pipe(outStream);
});
})
.catch(err => {
Utils.logDebug('[ERROR] ${err}');
reject(err);
});
}).then(res => {
return res;
});
}
}

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

@ -0,0 +1,48 @@
/*---------------------------------------------------------------------------------------------
* 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 { Url, parse as parseUrl } from 'url';
let HttpProxyAgent = require('http-proxy-agent');
let HttpsProxyAgent = require('https-proxy-agent');
function getSystemProxyURL(requestURL: Url): string {
if (requestURL.protocol === 'http:') {
return process.env.HTTP_PROXY || process.env.http_proxy || undefined;
} else if (requestURL.protocol === 'https:') {
return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || undefined;
}
return undefined;
}
/*
* Returns the proxy agent using the proxy url in the parameters or the system proxy. Returns null if no proxy found
*/
export function getProxyAgent(requestURL: Url, proxy?: string, strictSSL?: boolean): any {
const proxyURL = proxy || getSystemProxyURL(requestURL);
if (!proxyURL) {
return undefined;
}
const proxyEndpoint = parseUrl(proxyURL);
if (!/^https?:$/.test(proxyEndpoint.protocol)) {
return undefined;
}
strictSSL = strictSSL || true;
const opts = {
host: proxyEndpoint.hostname,
port: Number(proxyEndpoint.port),
auth: proxyEndpoint.auth,
rejectUnauthorized: strictSSL
};
return requestURL.protocol === 'http:' ? new HttpProxyAgent(opts) : new HttpsProxyAgent(opts);
}

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

@ -0,0 +1,107 @@
/*---------------------------------------------------------------------------------------------
* 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 path from 'path';
import * as Utils from '../models/utils';
import {Platform, getCurrentPlatform} from '../models/platform';
import ServiceDownloadProvider from './download';
import StatusView from '../views/statusView';
import Config from '../configurations/config';
let fs = require('fs-extra-promise');
/*
* Service Provider class finds the SQL tools service executable file or downloads it if doesn't exist.
*/
export default class ServerProvider {
constructor(private _downloadProvider?: ServiceDownloadProvider,
private _config?: Config,
private _statusView?: StatusView) {
if (!this._config) {
this._config = new Config();
}
if (!this._downloadProvider) {
this._downloadProvider = new ServiceDownloadProvider(this._config);
}
if (!this._statusView) {
this._statusView = new StatusView();
}
}
/**
* Given a file path, returns the path to the SQL Tools service file.
*/
public findServerPath(filePath: string): Promise<string> {
return fs.lstatAsync(filePath).then(stats => {
// If a file path was passed, assume its the launch file.
if (stats.isFile()) {
return filePath;
}
// Otherwise, search the specified folder.
let candidate: string;
if (this._config !== undefined) {
let executableFiles: string[] = this._config.getSqlToolsExecutableFiles();
executableFiles.forEach(element => {
let executableFile = path.join(filePath, element);
if (candidate === undefined && fs.existsSync(executableFile)) {
candidate = executableFile;
return candidate;
}
});
}
return candidate;
});
}
/**
* Download the SQL tools service if doesn't exist and returns the file path.
*/
public getServerPath(): 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();
return new Promise<string>((resolve, reject) => {
return this.findServerPath(installDirectory).then(result => {
if (result === undefined) {
return this.downloadServerFiles().then ( downloadResult => {
resolve(downloadResult);
});
} else {
return resolve(result);
}
}).catch(err => {
return reject(err);
});
}).catch(err => {
throw err;
});
}
private downloadServerFiles(): Promise<string> {
const platform = getCurrentPlatform();
if (platform === Platform.Unknown) {
throw new Error('Invalid Platform');
}
const installDirectory = this._downloadProvider.getInstallDirectory();
let currentFileUrl = Utils.getActiveTextEditorUri();
this._statusView.installingService(currentFileUrl);
return this._downloadProvider.go(platform).then( _ => {
return this.findServerPath(installDirectory).then ( result => {
this._statusView.serviceInstalled(currentFileUrl);
return result;
});
});
}
}

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

@ -4,13 +4,16 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as path from 'path';
import { ExtensionContext } from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions,
TransportKind, RequestType, NotificationType, NotificationHandler } from 'vscode-languageclient';
import * as Utils from '../models/utils';
import {VersionRequest} from '../models/contracts';
import Constants = require('../models/constants');
import ServerProvider from './server';
import ServiceDownloadProvider from './download';
import Config from '../configurations/config';
import StatusView from '../views/statusView';
// The Service Client class handles communication with the VS Code LanguageClient
export default class SqlToolsServiceClient {
@ -29,42 +32,58 @@ export default class SqlToolsServiceClient {
this._client = client;
}
constructor(private _server: ServerProvider) {
}
// gets or creates the singleton SQL Tools service client instance
public static get instance(): SqlToolsServiceClient {
if (this._instance === undefined) {
this._instance = new SqlToolsServiceClient();
let config = new Config();
let downloadProvider = new ServiceDownloadProvider(config);
let statusView = new StatusView();
let serviceProvider = new ServerProvider(downloadProvider, config, statusView);
this._instance = new SqlToolsServiceClient(serviceProvider);
}
return this._instance;
}
// initialize the SQL Tools Service Client instance by launching
// out-of-proc server through the LanguageClient
public initialize(context: ExtensionContext): void {
public initialize(context: ExtensionContext): Promise<boolean> {
return new Promise<boolean>( (resolve, reject) => {
this._server.getServerPath().then(serverPath => {
let serverArgs = [];
let serverCommand = serverPath;
if (serverPath.endsWith('.dll')) {
serverArgs = [serverPath];
serverCommand = 'dotnet';
}
// run the service host using dotnet.exe from the path
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
// run the service host using dotnet.exe from the path
let serverCommand = 'dotnet';
let serverArgs = [ context.asAbsolutePath(path.join('./out/tools', 'Microsoft.SqlTools.ServiceLayer.dll')) ];
let serverOptions: ServerOptions = { command: serverCommand, args: serverArgs, transport: TransportKind.stdio };
// Options to control the language client
let clientOptions: LanguageClientOptions = {
documentSelector: ['sql'],
synchronize: {
configurationSection: 'sqlTools'
}
};
// Options to control the language client
let clientOptions: LanguageClientOptions = {
documentSelector: ['sql'],
synchronize: {
configurationSection: 'sqlTools'
}
};
// cache the client instance for later use
this.client = new LanguageClient('sqlserverclient', serverOptions, clientOptions);
this.client.onReady().then( () => {
this.checkServiceCompatibility();
});
// Create the language client and start the client.
let disposable = this.client.start();
// cache the client instance for later use
this.client = new LanguageClient('sqlserverclient', serverOptions, clientOptions);
this.client.onReady().then( () => {
this.checkServiceCompatibility();
// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
resolve(true);
});
});
// 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);
}
/**
@ -74,7 +93,9 @@ export default class SqlToolsServiceClient {
* @returns A thenable object for when the request receives a response
*/
public sendRequest<P, R, E>(type: RequestType<P, R, E>, params?: P): Thenable<R> {
return this.client.sendRequest(type, params);
if (this.client !== undefined) {
return this.client.sendRequest(type, params);
}
}
/**
@ -83,7 +104,9 @@ export default class SqlToolsServiceClient {
* @param handler The handler to register
*/
public onNotification<P>(type: NotificationType<P>, handler: NotificationHandler<P>): void {
return this.client.onNotification(type, handler);
if (this._client !== undefined) {
return this.client.onNotification(type, handler);
}
}
public checkServiceCompatibility(): Promise<boolean> {

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

@ -126,6 +126,8 @@ export const executeQueryCommandCompleted = 'Command(s) completed successfully.'
export const serviceCompatibleVersion = '1.0.0';
export const serviceNotCompatibleError = 'Client is not compatiable with the service layer';
export const serviceInstalling = 'Installing Sql Tools Service';
export const serviceInstalled = 'Sql Tools Service installed';
export const untitledScheme = 'untitled';
export const untitledSaveTimeThreshold = 10.0;

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

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* 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 child_process from 'child_process';
export enum Platform {
Unknown,
Windows,
OSX,
CentOS,
Debian,
Fedora,
OpenSUSE,
RHEL,
Ubuntu14,
Ubuntu16
}
export function getCurrentPlatform(): Platform {
if (process.platform === 'win32') {
return Platform.Windows;
} else if (process.platform === 'darwin') {
return Platform.OSX;
} else if (process.platform === 'linux') {
// Get the text of /etc/os-release to discover which Linux distribution we're running on.
// For details: https://www.freedesktop.org/software/systemd/man/os-release.html
const text = child_process.execSync('cat /etc/os-release').toString();
const lines = text.split('\n');
function getValue(name: string): String {
for (let line of lines) {
line = line.trim();
if (line.startsWith(name)) {
const equalsIndex = line.indexOf('=');
if (equalsIndex >= 0) {
let value = line.substring(equalsIndex + 1);
// Strip double quotes if necessary
if (value.length > 1 && value.startsWith('"') && value.endsWith('"')) {
value = value.substring(1, value.length - 1);
}
return value;
}
}
}
return undefined;
}
const id = getValue('ID');
switch (id) {
case 'ubuntu':
const versionId = getValue('VERSION_ID');
if (versionId.startsWith('14')) {
// This also works for Linux Mint
return Platform.Ubuntu14;
} else if (versionId.startsWith('16')) {
return Platform.Ubuntu16;
}
break;
case 'centos':
return Platform.CentOS;
case 'fedora':
return Platform.Fedora;
case 'opensuse':
return Platform.OpenSUSE;
case 'rhel':
return Platform.RHEL;
case 'debian':
return Platform.Debian;
case 'ol':
// Oracle Linux is binary compatible with CentOS
return Platform.CentOS;
case 'elementary OS':
const eOSVersionId = getValue('VERSION_ID');
if (eOSVersionId.startsWith('0.3')) {
// Elementary OS 0.3 Freya is binary compatible with Ubuntu 14.04
return Platform.Ubuntu14;
} else if (eOSVersionId.startsWith('0.4')) {
// Elementary OS 0.4 Loki is binary compatible with Ubuntu 16.04
return Platform.Ubuntu16;
}
default:
return Platform.Windows;
}
}
return Platform.Unknown;
}

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

@ -128,6 +128,20 @@ export default class StatusView implements vscode.Disposable {
bar.statusQuery.hide();
}
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);
}
/**
* Associate a new uri with an existing Uri's status bar
*

20
test/config.test.ts Normal file
Просмотреть файл

@ -0,0 +1,20 @@
import assert = require('assert');
import Config from '../src/configurations/config';
import Telemetry from '../src/models/telemetry';
suite('Config Tests', () => {
setup(() => {
// Ensure that telemetry is disabled while testing
Telemetry.disable();
});
test('getSqlToolsServiceDownloadUrl should return valid value', (done) => {
return new Promise((resolve, reject) => {
let config = new Config();
let serviceDownloawUrl = config.getSqlToolsServiceDownloadUrl;
assert.notEqual(serviceDownloawUrl, undefined);
done();
});
});
});

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

@ -33,7 +33,7 @@ suite('Initialization Tests', () => {
let controller: MainController = Extension.getController();
let connectionManager: ConnectionManager = controller.connectionManager;
assert.notStrictEqual(undefined, connectionManager.client);
done();
});
done();
});
});

24
test/platform.test.ts Normal file
Просмотреть файл

@ -0,0 +1,24 @@
import assert = require('assert');
import {Platform, getCurrentPlatform} from '../src/models/platform';
import Telemetry from '../src/models/telemetry';
function getPlatform(): Promise<Platform> {
return new Promise((resolve, reject) => {
let platform = getCurrentPlatform();
resolve(platform);
});
}
suite('Platform Tests', () => {
setup(() => {
// Ensure that telemetry is disabled while testing
Telemetry.disable();
});
test('getCurrentPlatform should return valid value', (done) => {
getPlatform().then(platform => {
assert.notEqual(platform, Platform.Unknown);
done();
});
});
});

117
test/server.test.ts Normal file
Просмотреть файл

@ -0,0 +1,117 @@
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 Config from './../src/configurations/config';
import * as path from 'path';
import {getCurrentPlatform} from '../src/models/platform';
suite('Server tests', () => {
let testDownloadProvider: TypeMoq.Mock<ServiceDownloadProvider>;
let testStatusView: TypeMoq.Mock<StatusView>;
let testConfig: TypeMoq.Mock<Config>;
setup(() => {
testDownloadProvider = TypeMoq.Mock.ofType(ServiceDownloadProvider, TypeMoq.MockBehavior.Strict);
testStatusView = TypeMoq.Mock.ofType(StatusView, TypeMoq.MockBehavior.Strict);
testConfig = TypeMoq.Mock.ofType(Config, TypeMoq.MockBehavior.Strict);
});
test('findServerPath should return error given a folder with no installed service', () => {
let installDir = __dirname;
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', 'exeFile2']);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.findServerPath(installDir).then( result => {
assert.equal(result, undefined);
});
});
test('findServerPath should return error given a folder with no installed service', () => {
let installDir = __dirname;
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', 'exeFile2']);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.findServerPath(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);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.findServerPath(fileName).then( result => {
assert.equal(result, fileName);
});
});
test('findServerPath should not return the given file path if doesn not exist', () => {
let installDir = __dirname;
let fileName = path.join(installDir, __filename);
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', 'exeFile2']);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.findServerPath(fileName).then( result => {
assert.equal(fileName, undefined);
});
});
test('findServerPath should return a valid file path given a folder with installed service', () => {
let installDir = __dirname;
let fileName = __filename;
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => ['exeFile1', fileName]);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.findServerPath(fileName).then( result => {
assert.equal(result, path.join(installDir, fileName));
});
});
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 = getCurrentPlatform();
let executables: string[] = ['exeFile1'];
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => executables);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
testStatusView.setup(x => x.serviceInstalled(TypeMoq.It.isAny()));
testStatusView.setup(x => x.installingService(TypeMoq.It.isAny()));
testDownloadProvider.setup(x => x.go(platform)).callback(() => {
executables = [fileName];
}).returns(() => { return Promise.resolve(true); });
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.getServerPath().then( result => {
assert.equal(result, path.join(installDir, fileName));
});
});
test('getServerPath should not download the service if already exist', () => {
let installDir = __dirname;
let fileName: string = __filename.replace(installDir, '');
let executables: string[] = [fileName];
testConfig.setup(x => x.getSqlToolsExecutableFiles()).returns(() => executables);
testDownloadProvider.setup(x => x.getInstallDirectory()).returns(() => installDir);
testStatusView.setup(x => x.serviceInstalled(TypeMoq.It.isAny()));
testStatusView.setup(x => x.installingService(TypeMoq.It.isAny()));
let server = new ServerProvider(testDownloadProvider.object, testConfig.object, testStatusView.object);
server.getServerPath().then( result => {
assert.equal(result, path.join(installDir, fileName));
});
});
});