From f725ee96b9bf80768f69b53fb4087f129b306a5e Mon Sep 17 00:00:00 2001 From: Aasim Khan Date: Tue, 16 Jun 2020 13:24:48 -0700 Subject: [PATCH] Code refactoring for extension testing (#10529) * Setting up tests on import extension * -Added API wrappers for all the azdata and vscode APIs to make them easily mockable -Added some unit tests for the import extension -Some code logic separations * -added code report for the import extension in ci * Did some more code refractoring * -Added json report generation * updated vscodetestcoverage to latest version in import extension. * -remove duplicate codecoverageConfig.json --- extensions/import/coverConfig.json | 20 + extensions/import/package.json | 11 +- extensions/import/src/common/apiWrapper.ts | 88 +++ extensions/import/src/common/constants.ts | 60 ++ extensions/import/src/constants.ts | 12 - .../import/src/controllers/mainController.ts | 17 +- extensions/import/src/main.ts | 10 +- .../import/src/services/serviceClient.ts | 27 +- extensions/import/src/services/telemetry.ts | 46 +- extensions/import/src/test/import.test.ts | 225 ++++++ extensions/import/src/test/index.ts | 48 ++ extensions/import/src/wizard/api/basePage.ts | 17 +- .../import/src/wizard/api/importPage.ts | 5 +- .../import/src/wizard/flatFileWizard.ts | 88 ++- .../import/src/wizard/pages/fileConfigPage.ts | 60 +- .../src/wizard/pages/modifyColumnsPage.ts | 27 +- .../src/wizard/pages/prosePreviewPage.ts | 22 +- .../import/src/wizard/pages/summaryPage.ts | 52 +- extensions/import/yarn.lock | 740 +++++++++++++++++- scripts/test-extensions-unit.bat | 6 + scripts/test-extensions-unit.js | 1 + scripts/test-extensions-unit.sh | 5 + 22 files changed, 1356 insertions(+), 231 deletions(-) create mode 100644 extensions/import/coverConfig.json create mode 100644 extensions/import/src/common/apiWrapper.ts create mode 100644 extensions/import/src/common/constants.ts delete mode 100644 extensions/import/src/constants.ts create mode 100644 extensions/import/src/test/import.test.ts create mode 100644 extensions/import/src/test/index.ts diff --git a/extensions/import/coverConfig.json b/extensions/import/coverConfig.json new file mode 100644 index 0000000000..56a1a6ef27 --- /dev/null +++ b/extensions/import/coverConfig.json @@ -0,0 +1,20 @@ +{ + "enabled": true, + "relativeSourcePath": "..", + "relativeCoverageDir": "../../coverage", + "ignorePatterns": [ + "**/node_modules/**", + "**/test/**" + ], + "includePid": false, + "reports": [ + "cobertura", + "lcov", + "json" + ], + "verbose": false, + "remapOptions": { + "basePath": "..", + "useAbsolutePaths": true + } +} diff --git a/extensions/import/package.json b/extensions/import/package.json index 3f52051f70..58eee186dd 100644 --- a/extensions/import/package.json +++ b/extensions/import/package.json @@ -68,10 +68,17 @@ "htmlparser2": "^3.10.1", "service-downloader": "0.2.1", "vscode-extension-telemetry": "0.0.18", - "vscode-nls": "^3.2.1" + "vscode-nls": "^3.2.1" }, "devDependencies": { - "@types/node": "^12.11.7" + "@types/mocha": "^5.2.5", + "@types/node": "^12.11.7", + "mocha": "^5.2.0", + "mocha-junit-reporter": "^1.17.0", + "mocha-multi-reporters": "^1.1.7", + "should": "^13.2.1", + "typemoq": "^2.1.0", + "vscodetestcover": "^1.0.9" }, "__metadata": { "id": "23", diff --git a/extensions/import/src/common/apiWrapper.ts b/extensions/import/src/common/apiWrapper.ts new file mode 100644 index 0000000000..a6e6ab7cb8 --- /dev/null +++ b/extensions/import/src/common/apiWrapper.ts @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as azdata from 'azdata'; +/** + * Wrapper class to act as a facade over VSCode and Data APIs and allow us to test/mock callbacks into + * this API from our code + */ + +export class ApiWrapper { + + public createOutputChannel(name: string): vscode.OutputChannel { + return vscode.window.createOutputChannel(name); + } + + public getExtension(extensionId: string): vscode.Extension | undefined { + return vscode.extensions.getExtension(extensionId); + } + + public getUriForConnection(connectionId: string): Thenable { + return azdata.connection.getUriForConnection(connectionId); + } + + public getProvider(providerId: string, providerType: azdata.DataProviderType): T { + return azdata.dataprotocol.getProvider(providerId, providerType); + } + + public getCurrentConnection(): Thenable { + return azdata.connection.getCurrentConnection(); + } + + public openConnectionDialog(providers?: string[]): Thenable { + return azdata.connection.openConnectionDialog(providers); + } + + public showErrorMessage(message: string, ...items: string[]): Thenable { + return vscode.window.showErrorMessage(message, ...items); + } + + public createWizard(title: string): azdata.window.Wizard { + return azdata.window.createWizard(title); + } + + public createWizardPage(title: string): azdata.window.WizardPage { + return azdata.window.createWizardPage(title); + } + + public createButton(lable: string) { + return azdata.window.createButton(lable); + } + + public showOpenDialog(options: vscode.OpenDialogOptions): Thenable { + return vscode.window.showOpenDialog(options); + } + + public getActiveConnections(): Thenable { + return azdata.connection.getActiveConnections(); + } + + public listDatabases(connectionId: string): Thenable { + return azdata.connection.listDatabases(connectionId); + } + + public openExternal(target: vscode.Uri): Thenable { + return vscode.env.openExternal(target); + } + + public getConfiguration(section?: string, resource?: vscode.Uri | null): vscode.WorkspaceConfiguration { + return vscode.workspace.getConfiguration(section, resource); + } + + public registerTask(task: string, callback: azdata.tasks.ITaskHandler) { + azdata.tasks.registerTask(task, callback); + } + + public getCredentials(connectionId: string) { + return azdata.connection.getCredentials(connectionId); + } + + public getConnectionString(connectionId: string, includePassword: boolean) { + return azdata.connection.getConnectionString(connectionId, includePassword); + } + + +} diff --git a/extensions/import/src/common/constants.ts b/extensions/import/src/common/constants.ts new file mode 100644 index 0000000000..186a3876d5 --- /dev/null +++ b/extensions/import/src/common/constants.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); + +export const extensionConfigSectionName = 'flatFileImport'; +export const serviceName = 'Flat File Import Service'; +export const providerId = 'FlatFileImport'; +export const configLogDebugInfo = 'logDebugInfo'; +export const sqlConfigSectionName = 'sql'; +export const mssqlProvider = 'MSSQL'; + +export const supportedProviders = [mssqlProvider]; + +// Links +export const serviceCrashLink = 'https://github.com/Microsoft/azuredatastudio/issues/2090'; + +// Tasks +export const flatFileImportStartCommand = 'flatFileImport.start'; + +// Localized texts +export const crashButtonText = localize('import.serviceCrashButton', "Give Feedback"); +export const serviceCrashMessageText = localize('serviceCrashMessage', "service component could not start"); +export const serverDropDownTitleText = localize('flatFileImport.serverDropdownTitle', "Server the database is in"); +export const databaseDropdownTitleText = localize('flatFileImport.databaseDropdownTitle', "Database the table is created in"); +export const browseFilesText = localize('flatFileImport.browseFiles', "Browse"); +export const openFileText = localize('flatFileImport.openFile', "Open"); +export const fileTextboxTitleText = localize('flatFileImport.fileTextboxTitle', "Location of the file to be imported"); +export const tableTextboxTitleText = localize('flatFileImport.tableTextboxTitle', "New table name"); +export const schemaTextboxTitleText = localize('flatFileImport.schemaTextboxTitle', "Table schema"); +export const importDataText = localize('flatFileImport.importData', "Import Data"); +export const nextText = localize('flatFileImport.next', "Next"); +export const columnNameText = localize('flatFileImport.columnName', "Column Name"); +export const dataTypeText = localize('flatFileImport.dataType', "Data Type"); +export const primaryKeyText = localize('flatFileImport.primaryKey', "Primary Key"); +export const allowNullsText = localize('flatFileImport.allowNulls', "Allow Nulls"); +export const successTitleText = localize('flatFileImport.prosePreviewMessage', "This operation analyzed the input file structure to generate the preview below for up to the first 50 rows."); +export const failureTitleText = localize('flatFileImport.prosePreviewMessageFail', "This operation was unsuccessful. Please try a different input file."); +export const refreshText = localize('flatFileImport.refresh', "Refresh"); +export const importInformationText = localize('flatFileImport.importInformation', "Import information"); +export const importStatusText = localize('flatFileImport.importStatus', "Import status"); +export const serverNameText = localize('flatFileImport.serverName', "Server name"); +export const databaseText = localize('flatFileImport.databaseName', "Database name"); +export const tableNameText = localize('flatFileImport.tableName', "Table name"); +export const tableSchemaText = localize('flatFileImport.tableSchema', "Table schema"); +export const fileImportText = localize('flatFileImport.fileImport', "File to be imported"); +export const updateText = localize('flatFileImport.success.norows', "✔ You have successfully inserted the data into a table."); +export const needConnectionText = localize('import.needConnection', "Please connect to a server before using this wizard."); +export const needSqlConnectionText = localize('import.needSQLConnection', "SQL Server Import extension does not support this type of connection"); +export const wizardNameText = localize('flatFileImport.wizardName', "Import flat file wizard"); +export const page1NameText = localize('flatFileImport.page1Name', "Specify Input File"); +export const page2NameText = localize('flatFileImport.page2Name', "Preview Data"); +export const page3NameText = localize('flatFileImport.page3Name', "Modify Columns"); +export const page4NameText = localize('flatFileImport.page4Name', "Summary"); +export const importNewFileText = localize('flatFileImport.importNewFile', "Import new file"); + +// SQL Queries +export const selectSchemaQuery = `SELECT name FROM sys.schemas`; diff --git a/extensions/import/src/constants.ts b/extensions/import/src/constants.ts deleted file mode 100644 index dcaa1848f1..0000000000 --- a/extensions/import/src/constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export const extensionConfigSectionName = 'flatFileImport'; -export const serviceName = 'Flat File Import Service'; -export const providerId = 'FlatFileImport'; -export const configLogDebugInfo = 'logDebugInfo'; -export const sqlConfigSectionName = 'sql'; - -export const serviceCrashLink = 'https://github.com/Microsoft/azuredatastudio/issues/2090'; diff --git a/extensions/import/src/controllers/mainController.ts b/extensions/import/src/controllers/mainController.ts index 82924daa5d..8b31f99fd7 100644 --- a/extensions/import/src/controllers/mainController.ts +++ b/extensions/import/src/controllers/mainController.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as constants from '../constants'; +import * as constants from '../common/constants'; import * as azdata from 'azdata'; import ControllerBase from './controllerBase'; import * as vscode from 'vscode'; @@ -11,14 +11,22 @@ import { FlatFileWizard } from '../wizard/flatFileWizard'; import { ServiceClient } from '../services/serviceClient'; import { ApiType, managerInstance } from '../services/serviceApiManager'; import { FlatFileProvider } from '../services/contracts'; +import { ApiWrapper } from '../common/apiWrapper'; /** * The main controller class that initializes the extension */ export default class MainController extends ControllerBase { + private _outputChannel: vscode.OutputChannel; + private _apiWrapper: ApiWrapper; - public constructor(context: vscode.ExtensionContext) { + public constructor( + context: vscode.ExtensionContext, + apiWrapper: ApiWrapper + ) { super(context); + this._apiWrapper = apiWrapper; + this._outputChannel = this._apiWrapper.createOutputChannel(constants.serviceName); } /** */ @@ -27,18 +35,17 @@ export default class MainController extends ControllerBase { public async activate(): Promise { return new Promise(async (resolve) => { - const outputChannel = vscode.window.createOutputChannel(constants.serviceName); managerInstance.onRegisteredApi(ApiType.FlatFileProvider)(provider => { this.initializeFlatFileProvider(provider); resolve(true); }); - await new ServiceClient(outputChannel).startService(this._context); + await new ServiceClient(this._outputChannel, this._apiWrapper).startService(this._context); }); } private initializeFlatFileProvider(provider: FlatFileProvider) { - azdata.tasks.registerTask('flatFileImport.start', (profile: azdata.IConnectionProfile, ...args: any[]) => new FlatFileWizard(provider).start(profile, args)); + this._apiWrapper.registerTask(constants.flatFileImportStartCommand, (profile: azdata.IConnectionProfile, ...args: any[]) => new FlatFileWizard(provider, this._apiWrapper).start(profile, args)); } } diff --git a/extensions/import/src/main.ts b/extensions/import/src/main.ts index 1809d220a1..074ef16f65 100644 --- a/extensions/import/src/main.ts +++ b/extensions/import/src/main.ts @@ -7,16 +7,20 @@ import * as vscode from 'vscode'; import ControllerBase from './controllers/controllerBase'; import MainController from './controllers/mainController'; +import { ApiWrapper } from './common/apiWrapper'; let controllers: ControllerBase[] = []; -export async function activate(context: vscode.ExtensionContext): Promise { +export async function activate(context: vscode.ExtensionContext): Promise { + + let apiWrapper = new ApiWrapper(); + // Start the main controller - let mainController = new MainController(context); + let mainController = new MainController(context, apiWrapper); controllers.push(mainController); context.subscriptions.push(mainController); + await mainController.activate(); - return true; } export function deactivate() { diff --git a/extensions/import/src/services/serviceClient.ts b/extensions/import/src/services/serviceClient.ts index 5c0efd9e1d..3f63eb2296 100644 --- a/extensions/import/src/services/serviceClient.ts +++ b/extensions/import/src/services/serviceClient.ts @@ -13,31 +13,28 @@ import * as path from 'path'; import { EventAndListener } from 'eventemitter2'; import { Telemetry, LanguageClientErrorHandler } from './telemetry'; -import * as Constants from '../constants'; +import * as Constants from '../common/constants'; import { TelemetryFeature, FlatFileImportFeature } from './features'; import { promises as fs } from 'fs'; +import { ApiWrapper } from '../common/apiWrapper'; export class ServiceClient { private statusView: vscode.StatusBarItem; - constructor(private outputChannel: vscode.OutputChannel) { + constructor( + private outputChannel: vscode.OutputChannel, + private _apiWrapper: ApiWrapper + ) { this.statusView = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); } public async startService(context: vscode.ExtensionContext): Promise { const rawConfig = await fs.readFile(path.join(context.extensionPath, 'config.json')); - const config = JSON.parse(rawConfig.toString()); - config.installDirectory = path.join(context.extensionPath, config.installDirectory); - config.proxy = vscode.workspace.getConfiguration('http').get('proxy'); - config.strictSSL = vscode.workspace.getConfiguration('http').get('proxyStrictSSL') || true; - const serverdownloader = new ServerProvider(config); - serverdownloader.eventEmitter.onAny(this.generateHandleServerProviderEvent()); let clientOptions: ClientOptions = this.createClientOptions(); - try { const installationStart = Date.now(); let client: SqlOpsDataClient; - let serviceBinaries = await serverdownloader.getOrDownloadServer(); + let serviceBinaries = await this.downloadBinaries(context, rawConfig); const installationComplete = Date.now(); let serverOptions = this.generateServerOptions(serviceBinaries, context); client = new SqlOpsDataClient(Constants.serviceName, serverOptions, clientOptions); @@ -69,6 +66,16 @@ export class ServiceClient { } } + public async downloadBinaries(context: vscode.ExtensionContext, rawConfig: Buffer): Promise { + const config = JSON.parse(rawConfig.toString()); + config.installDirectory = path.join(context.extensionPath, config.installDirectory); + config.proxy = this._apiWrapper.getConfiguration('http').get('proxy'); + config.strictSSL = this._apiWrapper.getConfiguration('http').get('proxyStrictSSL') || true; + const serverdownloader = new ServerProvider(config); + serverdownloader.eventEmitter.onAny(this.generateHandleServerProviderEvent()); + return serverdownloader.getOrDownloadServer(); + } + private createClientOptions(): ClientOptions { return { providerId: Constants.providerId, diff --git a/extensions/import/src/services/telemetry.ts b/extensions/import/src/services/telemetry.ts index 31c802dd6b..469c2e8952 100644 --- a/extensions/import/src/services/telemetry.ts +++ b/extensions/import/src/services/telemetry.ts @@ -6,10 +6,8 @@ import { ErrorAction, CloseAction } from 'vscode-languageclient'; import TelemetryReporter from 'vscode-extension-telemetry'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -const localize = nls.loadMessageBundle(); -import * as constants from '../constants'; +import * as constants from '../common/constants'; import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './contracts'; @@ -33,12 +31,11 @@ export class LanguageClientErrorHandler { showOnErrorPrompt(): void { // TODO add telemetry // Telemetry.sendTelemetryEvent('SqlToolsServiceCrash'); - let crashButtonText = localize('import.serviceCrashButton', "Give Feedback"); vscode.window.showErrorMessage( - localize('serviceCrashMessage', "service component could not start"), - crashButtonText + constants.serviceCrashMessageText, + constants.crashButtonText ).then(action => { - if (action && action === crashButtonText) { + if (action && action === constants.crashButtonText) { vscode.env.openExternal(vscode.Uri.parse(constants.serviceCrashLink)); } }); @@ -71,21 +68,7 @@ export class LanguageClientErrorHandler { } } -/** - * Filters error paths to only include source files. Exported to support testing - */ -function FilterErrorPath(line: string): string | undefined { - if (line) { - let values: string[] = line.split('/out/'); - if (values.length <= 1) { - // Didn't match expected format - return line; - } else { - return values[1]; - } - } - return undefined; -} + export class Telemetry { private static reporter: TelemetryReporter; @@ -113,25 +96,6 @@ export class Telemetry { } } - /** - * Send a telemetry event for an exception - */ - public static sendTelemetryEventForException( - err: any, methodName: string): void { - let stackArray: string[]; - let firstLine: string = ''; - if (err !== undefined && err.stack !== undefined) { - stackArray = err.stack.split('\n'); - if (stackArray !== undefined && stackArray.length >= 2) { - firstLine = stackArray[1]; // The fist line is the error message and we don't want to send that telemetry event - firstLine = FilterErrorPath(firstLine); - } - } - - // Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII - this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine }); - } - /** * Send a telemetry event using application insights */ diff --git a/extensions/import/src/test/import.test.ts b/extensions/import/src/test/import.test.ts new file mode 100644 index 0000000000..a6393181b0 --- /dev/null +++ b/extensions/import/src/test/import.test.ts @@ -0,0 +1,225 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'mocha'; +import * as TypeMoq from 'typemoq'; +import * as azdata from 'azdata'; +import { FlatFileWizard } from '../wizard/flatFileWizard'; +import { ImportDataModel } from '../wizard/api/models'; +import { ApiWrapper } from '../common/apiWrapper'; +import { FileConfigPage } from '../wizard/pages/fileConfigPage'; +import * as should from 'should'; + +describe('import extension tests', function (): void { + describe('import extension wizard pages', () => { + + let mockFlatFileWizard: TypeMoq.IMock; + let mockApiWrapper: TypeMoq.IMock; + let mockImportModel: TypeMoq.IMock; + + this.beforeEach(() => { + mockApiWrapper = TypeMoq.Mock.ofType(ApiWrapper); + mockFlatFileWizard = TypeMoq.Mock.ofType(FlatFileWizard, TypeMoq.MockBehavior.Loose, undefined, TypeMoq.It.isAny(), mockApiWrapper.object); + mockImportModel = TypeMoq.Mock.ofType(TestImportDataModel, TypeMoq.MockBehavior.Loose); + }); + + it('BasePage- getDatabaseValue returns active database first', async () => { + // setting up the environment + let databases: string[] = ['testdb1', 'testdb2', 'testdb3']; + let activeDatabase: string = 'testdb2'; + + // setting up mocks + let importPage = new FileConfigPage(mockFlatFileWizard.object, TypeMoq.It.isAny(), mockImportModel.object, TypeMoq.It.isAny(), TypeMoq.It.isAny(), mockApiWrapper.object); + mockApiWrapper.setup(x => x.listDatabases(TypeMoq.It.isAnyString())).returns(async () => { return databases; }); + mockImportModel.object.server = { + providerName: 'MSSQL', + connectionId: 'testConnectionId', + options: {} + }; + mockImportModel.object.database = activeDatabase; + + // Creating assert variables + let expectedDatabaseValues = [ + { displayName: 'testdb2', name: 'testdb2' }, // This should be the first database as it is active in the extension. + { displayName: 'testdb1', name: 'testdb1' }, + { displayName: 'testdb3', name: 'testdb3' } + ]; + + let actualDatabaseValues = await importPage.getDatabaseValues(); + should(expectedDatabaseValues).deepEqual(actualDatabaseValues); + }); + + it('BasePage- getServerValue returns null on no active connection', async () => { + + let importPage = new FileConfigPage(mockFlatFileWizard.object, TypeMoq.It.isAny(), mockImportModel.object, TypeMoq.It.isAny(), TypeMoq.It.isAny(), mockApiWrapper.object); + + // mocking getActive connection to return null + mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return undefined; }); + + let serverValues = await importPage.getServerValues(); + + should(serverValues).undefined(); + + // mocking getActive connection returns empty array + mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return [] as azdata.connection.Connection[]; }); + + serverValues = await importPage.getServerValues(); + should(serverValues).undefined(); + }); + + it('BasePage- getServerValue return active server value first', async () => { + // settign up the enviornment + let testActiveConnections: azdata.connection.Connection[] = [ + { + providerName: 'MSSQL', + connectionId: 'testConnection1Id', + options: { + user: 'testcon1user', + server: 'testcon1server' + } + }, + { + providerName: 'MSSQL', + connectionId: 'testConnection2Id', + options: { + user: 'testcon2user', + server: 'testcon2server' + } + }, + { + providerName: 'PGSQL', + connectionId: 'testConnection3Id', + options: { + user: null, // setting it null to check if function return user as 'default + server: 'testcon3server' + } + } + ]; + + let importPage = new FileConfigPage(mockFlatFileWizard.object, TypeMoq.It.isAny(), mockImportModel.object, TypeMoq.It.isAny(), TypeMoq.It.isAny(), mockApiWrapper.object); + mockApiWrapper.setup(x => x.getActiveConnections()).returns(async () => { return testActiveConnections; }); + mockImportModel.object.server = ImportTestUtils.getTestServer(); + + let expectedConnectionValues = [ + { + connection: testActiveConnections[1], + displayName: 'testcon2server (testcon2user)', + name: 'testConnection2Id' + }, + { + connection: testActiveConnections[0], + displayName: 'testcon1server (testcon1user)', + name: 'testConnection1Id' + }, + { + connection: testActiveConnections[2], + displayName: 'testcon3server (default)', + name: 'testConnection3Id' + } + ]; + let actualConnectionValues = await importPage.getServerValues(); + should(expectedConnectionValues).deepEqual(actualConnectionValues); + + }); + }); + + describe('import extension flat file wizard', () => { + it('FlatFileWizard opens connectionDialog when there are no active connections', async () => { + let testConnection: azdata.connection.Connection = { + providerName: 'MSSQL', + connectionId: 'testConnectionId', + options: {} + }; + + let mockApiWrapper: TypeMoq.IMock = TypeMoq.Mock.ofType(ApiWrapper); + // There is no current connection. + mockApiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return undefined; }); + + + // openConnectionDialog returns a test connection + mockApiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny())).returns(async () => { return testConnection; }); + + let testFlatFileWizard = new FlatFileWizard(TypeMoq.It.isAny(), mockApiWrapper.object); + + await testFlatFileWizard.getConnectionId(); + + // openConnectionDialog will be called once + mockApiWrapper.verify(x => x.openConnectionDialog(TypeMoq.It.isAny()), TypeMoq.Times.once()); + + }); + + it('FlatFileWizard- shows error message when an invalid connection is selected', async () => { + let mockApiWrapper: TypeMoq.IMock = TypeMoq.Mock.ofType(ApiWrapper); + // The active connection doesn't have a valid Provider + let testConnectionProfile: azdata.connection.ConnectionProfile = ImportTestUtils.getTestConnectionProfile(); + mockApiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return Promise.resolve(testConnectionProfile); }); + mockApiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny())).returns(() => { return undefined; }); + + let testFlatFileWizard = new FlatFileWizard(TypeMoq.It.isAny(), mockApiWrapper.object); + + await testFlatFileWizard.getConnectionId(); + + mockApiWrapper.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once()); + + }); + + it('FlatFileWizard- shows error message when no connection is selected', async () => { + let mockApiWrapper: TypeMoq.IMock = TypeMoq.Mock.ofType(ApiWrapper); + // The active connection doesn't have a valid Provider + mockApiWrapper.setup(x => x.getCurrentConnection()).returns(() => { return undefined; }); + mockApiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny())).returns(() => { return undefined; }); + + let testFlatFileWizard = new FlatFileWizard(TypeMoq.It.isAny(), mockApiWrapper.object); + + await testFlatFileWizard.getConnectionId(); + + mockApiWrapper.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once()); + + }); + }); + +}); + +export class ImportTestUtils { + + public static getTestServer(): azdata.connection.Connection { + return { + providerName: 'MSSQL', + connectionId: 'testConnection2Id', + options: {} + }; + } + + public static getTestConnectionProfile(): azdata.connection.ConnectionProfile { + return { + providerId: 'InvalidProvider', + databaseName: 'databaseName', + serverName: 'testServerName', + connectionId: 'testConnectionId', + groupId: 'testGroupId', + connectionName: 'testConnectionName', + userName: 'testUserName', + password: 'testPassword', + authenticationType: 'testAuthenticationType', + savePassword: true, + saveProfile: true, + groupFullName: 'testGroupFullName', + options: {} + } as azdata.connection.ConnectionProfile; + } +} + +export class TestImportDataModel implements ImportDataModel { + server: azdata.connection.Connection; + serverId: string; + ownerUri: string; + proseColumns: import("../wizard/api/models").ColumnMetadata[]; + proseDataPreview: string[][]; + database: string; + table: string; + schema: string; + filePath: string; + fileType: string; +} diff --git a/extensions/import/src/test/index.ts b/extensions/import/src/test/index.ts new file mode 100644 index 0000000000..868c91c723 --- /dev/null +++ b/extensions/import/src/test/index.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +const testRunner = require('vscodetestcover'); + +const suite = 'import Extension Tests'; + +const mochaOptions: any = { + ui: 'bdd', + useColors: true, + timeout: 10000 +}; + +// set relevant mocha options from the environment +if (process.env.ADS_TEST_GREP) { + mochaOptions.grep = process.env.ADS_TEST_GREP; + console.log(`setting options.grep to: ${mochaOptions.grep}`); +} +if (process.env.ADS_TEST_INVERT_GREP) { + mochaOptions.invert = parseInt(process.env.ADS_TEST_INVERT_GREP); + console.log(`setting options.invert to: ${mochaOptions.invert}`); +} +if (process.env.ADS_TEST_TIMEOUT) { + mochaOptions.timeout = parseInt(process.env.ADS_TEST_TIMEOUT); + console.log(`setting options.timeout to: ${mochaOptions.timeout}`); +} +if (process.env.ADS_TEST_RETRIES) { + mochaOptions.retries = parseInt(process.env.ADS_TEST_RETRIES); + console.log(`setting options.retries to: ${mochaOptions.retries}`); +} + +if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) { + mochaOptions.reporter = 'mocha-multi-reporters'; + mochaOptions.reporterOptions = { + reporterEnabled: 'spec, mocha-junit-reporter', + mochaJunitReporterReporterOptions: { + testsuitesTitle: `${suite} ${process.platform}`, + mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) + } + }; +} + +testRunner.configure(mochaOptions, { coverConfig: '../../coverConfig.json' }); + +export = testRunner; diff --git a/extensions/import/src/wizard/api/basePage.ts b/extensions/import/src/wizard/api/basePage.ts index a5747b1e90..5765315770 100644 --- a/extensions/import/src/wizard/api/basePage.ts +++ b/extensions/import/src/wizard/api/basePage.ts @@ -5,12 +5,14 @@ import * as azdata from 'azdata'; import { ImportDataModel } from './models'; +import { ApiWrapper } from '../../common/apiWrapper'; export abstract class BasePage { protected readonly wizardPage: azdata.window.WizardPage; protected readonly model: ImportDataModel; protected readonly view: azdata.ModelView; + protected _apiWrapper: ApiWrapper; /** * This method constructs all the elements of the page. @@ -42,8 +44,8 @@ export abstract class BasePage { */ public abstract setupNavigationValidator(): void; - protected async getServerValues(): Promise<{ connection: azdata.connection.Connection, displayName: string, name: string }[]> { - let cons = await azdata.connection.getActiveConnections(); + public async getServerValues(): Promise<{ connection: azdata.connection.Connection, displayName: string, name: string }[]> { + let cons = await this._apiWrapper.getActiveConnections(); // This user has no active connections ABORT MISSION if (!cons || cons.length === 0) { return undefined; @@ -90,10 +92,10 @@ export abstract class BasePage { return values; } - protected async getDatabaseValues(): Promise<{ displayName: string, name: string }[]> { + public async getDatabaseValues(): Promise<{ displayName: string, name: string }[]> { let idx = -1; let count = -1; - let values = (await azdata.connection.listDatabases(this.model.server.connectionId)).map(db => { + let values = (await this._apiWrapper.listDatabases(this.model.server.connectionId)).map(db => { count++; if (this.model.database && db === this.model.database) { idx = count; @@ -109,10 +111,7 @@ export abstract class BasePage { let tmp = values[0]; values[0] = values[idx]; values[idx] = tmp; - } else { - this.deleteDatabaseValues(); } - return values; } @@ -121,8 +120,4 @@ export abstract class BasePage { delete this.model.serverId; delete this.model.database; } - - protected deleteDatabaseValues() { - return; - } } diff --git a/extensions/import/src/wizard/api/importPage.ts b/extensions/import/src/wizard/api/importPage.ts index 05aeb318de..cb3be259d4 100644 --- a/extensions/import/src/wizard/api/importPage.ts +++ b/extensions/import/src/wizard/api/importPage.ts @@ -8,6 +8,7 @@ import * as azdata from 'azdata'; import { FlatFileProvider } from '../../services/contracts'; import { FlatFileWizard } from '../flatFileWizard'; import { BasePage } from './basePage'; +import { ApiWrapper } from '../../common/apiWrapper'; export abstract class ImportPage extends BasePage { @@ -17,12 +18,14 @@ export abstract class ImportPage extends BasePage { protected readonly view: azdata.ModelView; protected readonly provider: FlatFileProvider; - protected constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) { + + constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider, apiWrapper: ApiWrapper) { super(); this.instance = instance; this.wizardPage = wizardPage; this.model = model; this.view = view; this.provider = provider; + this._apiWrapper = apiWrapper; } } diff --git a/extensions/import/src/wizard/flatFileWizard.ts b/extensions/import/src/wizard/flatFileWizard.ts index 4462debd8c..a447b6d804 100644 --- a/extensions/import/src/wizard/flatFileWizard.ts +++ b/extensions/import/src/wizard/flatFileWizard.ts @@ -3,8 +3,6 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; import * as azdata from 'azdata'; import { FlatFileProvider } from '../services/contracts'; import { ImportDataModel } from './api/models'; @@ -14,16 +12,23 @@ import { FileConfigPage } from './pages/fileConfigPage'; import { ProsePreviewPage } from './pages/prosePreviewPage'; import { ModifyColumnsPage } from './pages/modifyColumnsPage'; import { SummaryPage } from './pages/summaryPage'; - -const localize = nls.loadMessageBundle(); +import { ApiWrapper } from '../common/apiWrapper'; +import * as constants from '../common/constants'; export class FlatFileWizard { private readonly provider: FlatFileProvider; - private wizard: azdata.window.Wizard; + public wizard: azdata.window.Wizard; + public page1: azdata.window.WizardPage; + public page2: azdata.window.WizardPage; + public page3: azdata.window.WizardPage; + public page4: azdata.window.WizardPage; private importAnotherFileButton: azdata.window.Button; - constructor(provider: FlatFileProvider) { + constructor( + provider: FlatFileProvider, + private _apiWrapper: ApiWrapper + ) { this.provider = provider; } @@ -38,37 +43,24 @@ export class FlatFileWizard { let pages: Map = new Map(); - let currentConnection = await azdata.connection.getCurrentConnection(); + let connectionId: string = await this.getConnectionId(); - let connectionId: string; - - if (!currentConnection) { - connectionId = (await azdata.connection.openConnectionDialog(['MSSQL'])).connectionId; - if (!connectionId) { - vscode.window.showErrorMessage(localize('import.needConnection', "Please connect to a server before using this wizard.")); - return; - } - } else { - if (currentConnection.providerId !== 'MSSQL') { - vscode.window.showErrorMessage(localize('import.needSQLConnection', "SQL Server Import extension does not support this type of connection")); - return; - } - connectionId = currentConnection.connectionId; + if (!connectionId) { + return; } - model.serverId = connectionId; - this.wizard = azdata.window.createWizard(localize('flatFileImport.wizardName', "Import flat file wizard")); - let page1 = azdata.window.createWizardPage(localize('flatFileImport.page1Name', "Specify Input File")); - let page2 = azdata.window.createWizardPage(localize('flatFileImport.page2Name', "Preview Data")); - let page3 = azdata.window.createWizardPage(localize('flatFileImport.page3Name', "Modify Columns")); - let page4 = azdata.window.createWizardPage(localize('flatFileImport.page4Name', "Summary")); + this.wizard = this._apiWrapper.createWizard(constants.wizardNameText); + this.page1 = this._apiWrapper.createWizardPage(constants.page1NameText); + this.page2 = this._apiWrapper.createWizardPage(constants.page2NameText); + this.page3 = this._apiWrapper.createWizardPage(constants.page3NameText); + this.page4 = this._apiWrapper.createWizardPage(constants.page4NameText); let fileConfigPage: FileConfigPage; - page1.registerContent(async (view) => { - fileConfigPage = new FileConfigPage(this, page1, model, view, this.provider); + this.page1.registerContent(async (view) => { + fileConfigPage = new FileConfigPage(this, this.page1, model, view, this.provider, this._apiWrapper); pages.set(0, fileConfigPage); await fileConfigPage.start().then(() => { fileConfigPage.setupNavigationValidator(); @@ -77,29 +69,29 @@ export class FlatFileWizard { }); let prosePreviewPage: ProsePreviewPage; - page2.registerContent(async (view) => { - prosePreviewPage = new ProsePreviewPage(this, page2, model, view, this.provider); + this.page2.registerContent(async (view) => { + prosePreviewPage = new ProsePreviewPage(this, this.page2, model, view, this.provider, this._apiWrapper); pages.set(1, prosePreviewPage); await prosePreviewPage.start(); }); let modifyColumnsPage: ModifyColumnsPage; - page3.registerContent(async (view) => { - modifyColumnsPage = new ModifyColumnsPage(this, page3, model, view, this.provider); + this.page3.registerContent(async (view) => { + modifyColumnsPage = new ModifyColumnsPage(this, this.page3, model, view, this.provider, this._apiWrapper); pages.set(2, modifyColumnsPage); await modifyColumnsPage.start(); }); let summaryPage: SummaryPage; - page4.registerContent(async (view) => { - summaryPage = new SummaryPage(this, page4, model, view, this.provider); + this.page4.registerContent(async (view) => { + summaryPage = new SummaryPage(this, this.page4, model, view, this.provider, this._apiWrapper); pages.set(3, summaryPage); await summaryPage.start(); }); - this.importAnotherFileButton = azdata.window.createButton(localize('flatFileImport.importNewFile', "Import new file")); + this.importAnotherFileButton = this._apiWrapper.createButton(constants.importNewFileText); this.importAnotherFileButton.onClick(() => { //TODO replace this with proper cleanup for all the pages this.wizard.close(); @@ -126,11 +118,33 @@ export class FlatFileWizard { //not needed for this wizard this.wizard.generateScriptButton.hidden = true; - this.wizard.pages = [page1, page2, page3, page4]; + this.wizard.pages = [this.page1, this.page2, this.page3, this.page4]; this.wizard.open(); } + public async getConnectionId(): Promise { + let currentConnection = await this._apiWrapper.getCurrentConnection(); + + let connectionId: string; + + if (!currentConnection) { + let connection = await this._apiWrapper.openConnectionDialog(constants.supportedProviders); + if (!connection) { + this._apiWrapper.showErrorMessage(constants.needConnectionText); + return undefined; + } + connectionId = connection.connectionId; + } else { + if (currentConnection.providerId !== 'MSSQL') { + this._apiWrapper.showErrorMessage(constants.needSqlConnectionText); + return undefined; + } + connectionId = currentConnection.connectionId; + } + return connectionId; + } + public setImportAnotherFileVisibility(visibility: boolean) { this.importAnotherFileButton.hidden = !visibility; } diff --git a/extensions/import/src/wizard/pages/fileConfigPage.ts b/extensions/import/src/wizard/pages/fileConfigPage.ts index 1d19b6a52e..298d276a7f 100644 --- a/extensions/import/src/wizard/pages/fileConfigPage.ts +++ b/extensions/import/src/wizard/pages/fileConfigPage.ts @@ -5,13 +5,8 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; -import { ImportDataModel } from '../api/models'; import { ImportPage } from '../api/importPage'; -import { FlatFileProvider } from '../../services/contracts'; -import { FlatFileWizard } from '../flatFileWizard'; - -const localize = nls.loadMessageBundle(); +import * as constants from '../../common/constants'; export class FileConfigPage extends ImportPage { @@ -28,10 +23,6 @@ export class FileConfigPage extends ImportPage { private tableNames: string[] = []; - public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) { - super(instance, wizardPage, model, view, provider); - } - async start(): Promise { let schemaComponent = await this.createSchemaDropdown(); let tableNameComponent = await this.createTableNameBox(); @@ -96,7 +87,7 @@ export class FileConfigPage extends ImportPage { return { component: this.serverDropdown, - title: localize('flatFileImport.serverDropdownTitle', "Server the database is in") + title: constants.serverDropDownTitleText }; } @@ -124,8 +115,8 @@ export class FileConfigPage extends ImportPage { this.databaseDropdown.onValueChanged(async (db) => { this.model.database = (this.databaseDropdown.value).name; //this.populateTableNames(); - let connectionProvider = azdata.dataprotocol.getProvider(this.model.server.providerName, azdata.DataProviderType.ConnectionProvider); - let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); + let connectionProvider = this._apiWrapper.getProvider(this.model.server.providerName, azdata.DataProviderType.ConnectionProvider); + let connectionUri = await this._apiWrapper.getUriForConnection(this.model.server.connectionId); connectionProvider.changeDatabase(connectionUri, this.model.database); this.populateSchemaDropdown(); }); @@ -134,7 +125,7 @@ export class FileConfigPage extends ImportPage { return { component: this.databaseLoader, - title: localize('flatFileImport.databaseDropdownTitle', "Database the table is created in") + title: constants.databaseDropdownTitleText }; } @@ -178,7 +169,7 @@ export class FileConfigPage extends ImportPage { required: true }).component(); this.fileButton = this.view.modelBuilder.button().withProperties({ - label: localize('flatFileImport.browseFiles', "Browse"), + label: constants.browseFilesText, }).component(); this.fileButton.onDidClick(async (click) => { @@ -187,7 +178,7 @@ export class FileConfigPage extends ImportPage { canSelectFiles: true, canSelectFolders: false, canSelectMany: false, - openLabel: localize('flatFileImport.openFile', "Open"), + openLabel: constants.openFileText, filters: { 'CSV/TXT Files': ['csv', 'txt'], 'All Files': ['*'] @@ -227,7 +218,7 @@ export class FileConfigPage extends ImportPage { return { component: this.fileTextBox, - title: localize('flatFileImport.fileTextboxTitle', "Location of the file to be imported"), + title: constants.fileTextboxTitleText, actions: [this.fileButton] }; } @@ -256,7 +247,7 @@ export class FileConfigPage extends ImportPage { return { component: this.tableNameTextBox, - title: localize('flatFileImport.tableTextboxTitle', "New table name"), + title: constants.tableTextboxTitleText, }; } @@ -274,20 +265,31 @@ export class FileConfigPage extends ImportPage { return { component: this.schemaLoader, - title: localize('flatFileImport.schemaTextboxTitle', "Table schema"), + title: constants.schemaTextboxTitleText, }; } - private async populateSchemaDropdown(): Promise { + public async populateSchemaDropdown(): Promise { this.schemaLoader.loading = true; - let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); - let queryProvider = azdata.dataprotocol.getProvider(this.model.server.providerName, azdata.DataProviderType.QueryProvider); + let values = await this.getSchemaValues(); - const query = `SELECT name FROM sys.schemas`; + this.model.schema = values[0].name; - let results = await queryProvider.runQueryAndReturn(connectionUri, query); + this.schemaDropdown.updateProperties({ + values: values + }); + + this.schemaLoader.loading = false; + return true; + } + + public async getSchemaValues(): Promise<{ displayName: string, name: string }[]> { + let connectionUri = await this._apiWrapper.getUriForConnection(this.model.server.connectionId); + let queryProvider = this._apiWrapper.getProvider(this.model.server.providerName, azdata.DataProviderType.QueryProvider); + + let results = await queryProvider.runQueryAndReturn(connectionUri, constants.selectSchemaQuery); let idx = -1; let count = -1; @@ -311,15 +313,7 @@ export class FileConfigPage extends ImportPage { values[0] = values[idx]; values[idx] = tmp; } - - this.model.schema = values[0].name; - - this.schemaDropdown.updateProperties({ - values: values - }); - - this.schemaLoader.loading = false; - return true; + return values; } protected deleteServerValues() { diff --git a/extensions/import/src/wizard/pages/modifyColumnsPage.ts b/extensions/import/src/wizard/pages/modifyColumnsPage.ts index 78205ffe6b..9d96d5c5e0 100644 --- a/extensions/import/src/wizard/pages/modifyColumnsPage.ts +++ b/extensions/import/src/wizard/pages/modifyColumnsPage.ts @@ -4,13 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import * as nls from 'vscode-nls'; -import { ColumnMetadata, ImportDataModel } from '../api/models'; +import { ColumnMetadata } from '../api/models'; import { ImportPage } from '../api/importPage'; -import { FlatFileProvider } from '../../services/contracts'; -import { FlatFileWizard } from '../flatFileWizard'; - -const localize = nls.loadMessageBundle(); +import * as constants from '../../common/constants'; export class ModifyColumnsPage extends ImportPage { private readonly categoryValues = [ @@ -54,11 +50,6 @@ export class ModifyColumnsPage extends ImportPage { private text: azdata.TextComponent; private form: azdata.FormContainer; - public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) { - super(instance, wizardPage, model, view, provider); - } - - private static convertMetadata(column: ColumnMetadata): any[] { return [column.columnName, column.dataType, false, column.nullable]; } @@ -105,20 +96,20 @@ export class ModifyColumnsPage extends ImportPage { async onPageEnter(): Promise { this.loading.loading = true; await this.populateTable(); - this.instance.changeNextButtonLabel(localize('flatFileImport.importData', "Import Data")); + this.instance.changeNextButtonLabel(constants.importDataText); this.loading.loading = false; return true; } async onPageLeave(): Promise { - this.instance.changeNextButtonLabel(localize('flatFileImport.next', "Next")); + this.instance.changeNextButtonLabel(constants.nextText); return undefined; } async cleanup(): Promise { delete this.model.proseColumns; - this.instance.changeNextButtonLabel(localize('flatFileImport.next', "Next")); + this.instance.changeNextButtonLabel(constants.nextText); return true; } @@ -139,23 +130,23 @@ export class ModifyColumnsPage extends ImportPage { this.table.updateProperties({ height: 400, columns: [{ - displayName: localize('flatFileImport.columnName', "Column Name"), + displayName: constants.columnNameText, valueType: azdata.DeclarativeDataType.string, width: '150px', isReadOnly: false }, { - displayName: localize('flatFileImport.dataType', "Data Type"), + displayName: constants.dataTypeText, valueType: azdata.DeclarativeDataType.editableCategory, width: '150px', isReadOnly: false, categoryValues: this.categoryValues }, { - displayName: localize('flatFileImport.primaryKey', "Primary Key"), + displayName: constants.primaryKeyText, valueType: azdata.DeclarativeDataType.boolean, width: '100px', isReadOnly: false }, { - displayName: localize('flatFileImport.allowNulls', "Allow Nulls"), + displayName: constants.allowNullsText, valueType: azdata.DeclarativeDataType.boolean, isReadOnly: false, width: '100px' diff --git a/extensions/import/src/wizard/pages/prosePreviewPage.ts b/extensions/import/src/wizard/pages/prosePreviewPage.ts index 62f0e4448f..b7e16663ea 100644 --- a/extensions/import/src/wizard/pages/prosePreviewPage.ts +++ b/extensions/import/src/wizard/pages/prosePreviewPage.ts @@ -4,19 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import * as nls from 'vscode-nls'; -import { ImportDataModel } from '../api/models'; import { ImportPage } from '../api/importPage'; -import { FlatFileProvider } from '../../services/contracts'; -import { FlatFileWizard } from '../flatFileWizard'; - -const localize = nls.loadMessageBundle(); +import * as constants from '../../common/constants'; export class ProsePreviewPage extends ImportPage { - private readonly successTitle: string = localize('flatFileImport.prosePreviewMessage', "This operation analyzed the input file structure to generate the preview below for up to the first 50 rows."); - private readonly failureTitle: string = localize('flatFileImport.prosePreviewMessageFail', "This operation was unsuccessful. Please try a different input file."); - private table: azdata.TableComponent; private loading: azdata.LoadingComponent; private form: azdata.FormContainer; @@ -24,10 +16,6 @@ export class ProsePreviewPage extends ImportPage { private resultTextComponent: azdata.TextComponent; private isSuccess: boolean; - public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) { - super(instance, wizardPage, model, view, provider); - } - async start(): Promise { this.table = this.view.modelBuilder.table().withProperties({ data: undefined, @@ -35,7 +23,7 @@ export class ProsePreviewPage extends ImportPage { forceFitColumns: azdata.ColumnSizingMode.DataFit }).component(); this.refresh = this.view.modelBuilder.button().withProperties({ - label: localize('flatFileImport.refresh', "Refresh"), + label: constants.refreshText, isFile: false }).component(); @@ -47,7 +35,7 @@ export class ProsePreviewPage extends ImportPage { this.resultTextComponent = this.view.modelBuilder.text() .withProperties({ - value: this.isSuccess ? this.successTitle : this.failureTitle + value: this.isSuccess ? constants.successTitleText : constants.failureTitleText }).component(); this.form = this.view.modelBuilder.formContainer().withFormItems([ @@ -84,14 +72,14 @@ export class ProsePreviewPage extends ImportPage { await this.populateTable(this.model.proseDataPreview, this.model.proseColumns.map(c => c.columnName)); this.isSuccess = true; if (this.form) { - this.resultTextComponent.value = this.successTitle; + this.resultTextComponent.value = constants.successTitleText; } return true; } else { await this.populateTable([], []); this.isSuccess = false; if (this.form) { - this.resultTextComponent.value = this.failureTitle + '\n' + (error ?? ''); + this.resultTextComponent.value = constants.failureTitleText + '\n' + (error ?? ''); } return false; } diff --git a/extensions/import/src/wizard/pages/summaryPage.ts b/extensions/import/src/wizard/pages/summaryPage.ts index b810f0e1ec..51dc2cb87f 100644 --- a/extensions/import/src/wizard/pages/summaryPage.ts +++ b/extensions/import/src/wizard/pages/summaryPage.ts @@ -4,15 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import * as nls from 'vscode-nls'; -import { ImportDataModel } from '../api/models'; import { ImportPage } from '../api/importPage'; -import { FlatFileProvider, InsertDataResponse } from '../../services/contracts'; -import { FlatFileWizard } from '../flatFileWizard'; - -const localize = nls.loadMessageBundle(); - +import { InsertDataResponse } from '../../services/contracts'; +import * as constants from '../../common/constants'; export class SummaryPage extends ImportPage { private table: azdata.TableComponent; @@ -20,10 +15,6 @@ export class SummaryPage extends ImportPage { private loading: azdata.LoadingComponent; private form: azdata.FormContainer; - public constructor(instance: FlatFileWizard, wizardPage: azdata.window.WizardPage, model: ImportDataModel, view: azdata.ModelView, provider: FlatFileProvider) { - super(instance, wizardPage, model, view, provider); - } - async start(): Promise { this.table = this.view.modelBuilder.table().component(); this.statusText = this.view.modelBuilder.text().component(); @@ -33,11 +24,11 @@ export class SummaryPage extends ImportPage { [ { component: this.table, - title: localize('flatFileImport.importInformation', "Import information") + title: constants.importInformationText }, { component: this.loading, - title: localize('flatFileImport.importStatus', "Import status") + title: constants.importStatusText } ] ).component(); @@ -70,11 +61,11 @@ export class SummaryPage extends ImportPage { private populateTable() { this.table.updateProperties({ data: [ - [localize('flatFileImport.serverName', "Server name"), this.model.server.providerName], - [localize('flatFileImport.databaseName', "Database name"), this.model.database], - [localize('flatFileImport.tableName', "Table name"), this.model.table], - [localize('flatFileImport.tableSchema', "Table schema"), this.model.schema], - [localize('flatFileImport.fileImport', "File to be imported"), this.model.filePath]], + [constants.serverNameText, this.model.server.providerName], + [constants.databaseText, this.model.database], + [constants.tableNameText, this.model.table], + [constants.tableSchemaText, this.model.schema], + [constants.fileImportText, this.model.filePath]], columns: ['Object type', 'Name'], width: 600, height: 200 @@ -96,9 +87,11 @@ export class SummaryPage extends ImportPage { let result: InsertDataResponse; let err; + let includePasswordInConnectionString = (this.model.server.options.connectionId === 'Integrated') ? false : true; + try { result = await this.provider.sendInsertDataRequest({ - connectionString: await this.getConnectionString(), + connectionString: await this._apiWrapper.getConnectionString(this.model.server.connectionId, includePasswordInConnectionString), //TODO check what SSMS uses as batch size batchSize: 500 }); @@ -118,7 +111,7 @@ export class SummaryPage extends ImportPage { // TODO: When sql statements are in, implement this. //let rows = await this.getCountRowsInserted(); //if (rows < 0) { - updateText = localize('flatFileImport.success.norows', "✔ You have successfully inserted the data into a table."); + updateText = constants.updateText; //} else { //updateText = localize('flatFileImport.success.rows', '✔ You have successfully inserted {0} rows.', rows); //} @@ -129,25 +122,6 @@ export class SummaryPage extends ImportPage { return true; } - /** - * Gets the connection string to send to the middleware - */ - private async getConnectionString(): Promise { - let options = this.model.server.options; - let connectionString: string; - - if (options.authenticationType === 'Integrated') { - connectionString = `Data Source=${options.server + (options.port ? `,${options.port}` : '')};Initial Catalog=${this.model.database};Integrated Security=True`; - } else { - let credentials = await azdata.connection.getCredentials(this.model.server.connectionId); - connectionString = `Data Source=${options.server + (options.port ? `,${options.port}` : '')};Initial Catalog=${this.model.database};Integrated Security=False;User Id=${options.user};Password=${credentials.password}`; - } - - // TODO: Fix this, it's returning undefined string. - //await azdata.connection.getConnectionString(this.model.server.connectionId, true); - return connectionString; - } - // private async getCountRowsInserted(): Promise { // let connectionUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); // let queryProvider = azdata.dataprotocol.getProvider(this.model.server.providerName, azdata.DataProviderType.QueryProvider); diff --git a/extensions/import/yarn.lock b/extensions/import/yarn.lock index 7716b39cc8..06ec129a42 100644 --- a/extensions/import/yarn.lock +++ b/extensions/import/yarn.lock @@ -2,6 +2,191 @@ # yarn lockfile v1 +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/core@^7.7.5": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.6.tgz#d9aa1f580abf3b2286ef40b6904d390904c63376" + integrity sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.6" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.6" + "@babel/parser" "^7.9.6" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.6.tgz#5408c82ac5de98cda0d77d8124e99fa1f2170a43" + integrity sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ== + dependencies: + "@babel/types" "^7.9.6" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-function-name@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" + integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.9.5" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz#03149d7e6a5586ab6764996cd31d6981a17e1444" + integrity sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" + integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== + +"@babel/helpers@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.6.tgz#092c774743471d0bb6c7de3ad465ab3d3486d580" + integrity sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + +"@babel/highlight@^7.8.3": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.6.tgz#3b1bbb30dabe600cd72db58720998376ff653bc7" + integrity sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q== + +"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/traverse@^7.7.4", "@babel/traverse@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442" + integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.6" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7" + integrity sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA== + dependencies: + "@babel/helper-validator-identifier" "^7.9.5" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + +"@types/mocha@^5.2.5": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== + "@types/node@^12.11.7": version "12.12.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11" @@ -21,6 +206,25 @@ agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +append-transform@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" + integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== + dependencies: + default-require-extensions "^3.0.0" + applicationinsights@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927" @@ -37,16 +241,92 @@ async-retry@^1.2.3: dependencies: retry "0.12.0" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= +callsite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + chownr@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + "dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.3.0": version "0.3.0" resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/21487d15a5f753ba885ce1e489abc0af03487544" @@ -60,6 +340,13 @@ debug@3.1.0: dependencies: ms "2.0.0" +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -67,6 +354,27 @@ debug@^3.1.0: dependencies: ms "^2.1.1" +debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decache@^4.4.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/decache/-/decache-4.5.1.tgz#94a977a88a4188672c96550ec4889582ceecdf49" + integrity sha512-5J37nATc6FmOTLbcsr9qx7Nm28qQyg1SK4xyEHqM0IBkNhWFp0Sm+vKoWYHD8wq+OUEb9jLyaKFfzzd1A9hcoA== + dependencies: + callsite "^1.0.0" + +default-require-extensions@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" + integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg== + dependencies: + strip-bom "^4.0.0" + diagnostic-channel-publishers@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" @@ -79,6 +387,11 @@ diagnostic-channel@0.2.0: dependencies: semver "^5.3.0" +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + dom-serializer@0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" @@ -124,6 +437,11 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + eventemitter2@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-5.0.1.tgz#6197a095d5fb6b57e8942f6fd7eaad63a09c9452" @@ -143,6 +461,70 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + htmlparser2@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" @@ -171,16 +553,150 @@ https-proxy-agent@^2.2.3: agent-base "^4.3.0" debug "^3.1.0" +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + inherits@^2.0.1, inherits@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +is-buffer@~1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-hook@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" + integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== + dependencies: + append-transform "^2.0.0" + +istanbul-lib-instrument@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" + integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== + dependencies: + "@babel/core" "^7.7.5" + "@babel/parser" "^7.7.5" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +md5@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minipass@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" @@ -196,7 +712,7 @@ minizlib@^2.1.0: minipass "^3.0.0" yallist "^4.0.0" -mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -208,6 +724,49 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea" integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g== +mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mocha-junit-reporter@^1.17.0: + version "1.23.3" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981" + integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA== + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.0" + +mocha-multi-reporters@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" + integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= + dependencies: + debug "^3.1.0" + lodash "^4.16.4" + +mocha@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -218,16 +777,43 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +postinstall-build@^5.0.1: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postinstall-build/-/postinstall-build-5.0.3.tgz#238692f712a481d8f5bc8960e94786036241efc7" + integrity sha512-vPvPe8TKgp4FLgY3+DfxCE5PIfoXBK2lyLfNCxsRbDsV6vS4oU5RG/IWxrblMn6heagbnMED3MemUQllQ2bQUg== + readable-stream@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" @@ -237,12 +823,26 @@ readable-stream@^3.1.1: string_decoder "^1.1.1" util-deprecate "^1.0.1" +resolve@^1.3.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + retry@0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -safe-buffer@~5.1.0: +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -252,6 +852,16 @@ semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^5.4.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + service-downloader@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/service-downloader/-/service-downloader-0.2.1.tgz#8bd756bc4bc0cbfdf04fe71d4337f19ce6196203" @@ -266,6 +876,60 @@ service-downloader@0.2.1: tmp "^0.0.33" yauzl "^2.10.0" +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + integrity sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA== + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + integrity sha1-m/yPdPo5IFxT04w01xcwPidxJPE= + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + integrity sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA== + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + integrity sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM= + +should-util@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.1.tgz#fb0d71338f532a3a149213639e2d32cbea8bcb28" + integrity sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g== + +should@^13.2.1: + version "13.2.3" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.3.tgz#96d8e5acf3e97b49d89b51feaa5ae8d07ef58f10" + integrity sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ== + dependencies: + should-equal "^2.0.0" + should-format "^3.0.3" + should-type "^1.4.0" + should-type-adaptors "^1.0.1" + should-util "^1.0.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + string_decoder@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" @@ -273,6 +937,39 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +supports-color@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + tar@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.1.tgz#7b3bd6c313cb6e0153770108f8d70ac298607efa" @@ -292,6 +989,20 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +typemoq@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8" + integrity sha512-DtRNLb7x8yCTv/KHlwes+NI+aGb4Vl1iPC63Hhtcvk1DpxSAZzKWQv0RQFY0jX2Uqj0SDBNl8Na4e6MV6TNDgw== + dependencies: + circular-json "^0.3.1" + lodash "^4.17.4" + postinstall-build "^5.0.1" + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -334,6 +1045,31 @@ vscode-nls@^3.2.1: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.5.tgz#25520c1955108036dec607c85e00a522f247f1a4" integrity sha512-ITtoh3V4AkWXMmp3TB97vsMaHRgHhsSFPsUdzlueSL+dRZbSNTZeOmdQv60kjCV306ghPxhDeoNUEm3+EZMuyw== +vscodetestcover@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/vscodetestcover/-/vscodetestcover-1.0.9.tgz#0191f403dd59ba1153fc57979e281e992ce63731" + integrity sha512-8z2961KF9Tuz5XdHAC6RMV3CrzAoUcfIK7wLYjLIXD4dbHIT7ceZMhoxToW1olyi3pFnThlS4lRXtx8Q5iyMMQ== + dependencies: + decache "^4.4.0" + glob "^7.1.2" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-hook "^3.0.0" + istanbul-lib-instrument "^4.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^3.0.6" + istanbul-reports "^3.0.0" + mocha "^5.2.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" diff --git a/scripts/test-extensions-unit.bat b/scripts/test-extensions-unit.bat index 4f18a5b192..82bc294277 100755 --- a/scripts/test-extensions-unit.bat +++ b/scripts/test-extensions-unit.bat @@ -22,6 +22,7 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( call yarn gulp compile-extension:azurecore call yarn gulp compile-extension:cms call yarn gulp compile-extension:dacpac + call yarn gulp compile-extension:import call yarn gulp compile-extension:schema-compare call yarn gulp compile-extension:mssql call yarn gulp compile-extension:notebook @@ -66,6 +67,11 @@ echo *** starting dacpac tests *** echo ***************************** call "%INTEGRATION_TEST_ELECTRON_PATH%" --extensionDevelopmentPath=%~dp0\..\extensions\dacpac --extensionTestsPath=%~dp0\..\extensions\dacpac\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222 --disable-telemetry --disable-crash-reporter --disable-updates --nogpu +echo ***************************** +echo *** starting import tests *** +echo ***************************** +call "%INTEGRATION_TEST_ELECTRON_PATH%" --extensionDevelopmentPath=%~dp0\..\extensions\import --extensionTestsPath=%~dp0\..\extensions\import\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222 --disable-telemetry --disable-crash-reporter --disable-updates --nogpu + echo ************************************* echo *** starting schema compare tests *** echo ************************************* diff --git a/scripts/test-extensions-unit.js b/scripts/test-extensions-unit.js index 37ecc4f80d..38f3835ea1 100644 --- a/scripts/test-extensions-unit.js +++ b/scripts/test-extensions-unit.js @@ -15,6 +15,7 @@ const extensionList = [ 'azurecore', 'cms', 'dacpac', + 'import', 'schema-compare', //'mssql', 'notebook', diff --git a/scripts/test-extensions-unit.sh b/scripts/test-extensions-unit.sh index 9009b7f925..08e26a2af5 100755 --- a/scripts/test-extensions-unit.sh +++ b/scripts/test-extensions-unit.sh @@ -64,6 +64,11 @@ echo *** starting dacpac tests *** echo ***************************** "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX --extensionDevelopmentPath=$ROOT/extensions/dacpac --extensionTestsPath=$ROOT/extensions/dacpac/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR --disable-telemetry --disable-crash-reporter --disable-updates --nogpu +echo ***************************** +echo *** starting import tests *** +echo ***************************** +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX --extensionDevelopmentPath=$ROOT/extensions/import --extensionTestsPath=$ROOT/extensions/import/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR --disable-telemetry --disable-crash-reporter --disable-updates --nogpu + echo ************************************* echo *** starting schema compare tests *** echo *************************************