diff --git a/build/azure-pipelines/darwin/sql-product-build-darwin.yml b/build/azure-pipelines/darwin/sql-product-build-darwin.yml index 96c4e861d2..b1d78cff33 100644 --- a/build/azure-pipelines/darwin/sql-product-build-darwin.yml +++ b/build/azure-pipelines/darwin/sql-product-build-darwin.yml @@ -113,6 +113,21 @@ steps: displayName: Run unit tests condition: and(succeeded(), eq(variables['RUN_TESTS'], 'true')) + - script: | + set -e + APP_ROOT=$(agent.builddirectory)/azuredatastudio-darwin + APP_NAME="`ls $APP_ROOT | head -n 1`" + yarn smoketest --build "$APP_ROOT/$APP_NAME" --screenshots "$(build.artifactstagingdirectory)/smokeshots" + displayName: Run smoke tests (Electron) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + + - script: | + set -e + VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/azuredatastudio-reh-web-darwin" \ + yarn smoketest --web --headless --screenshots "$(build.artifactstagingdirectory)/smokeshots" + displayName: Run smoke tests (Browser) + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + - script: | set -e pushd ../azuredatastudio-darwin diff --git a/extensions/integration-tests/package.json b/extensions/integration-tests/package.json index dc21a80dee..d34987d36d 100644 --- a/extensions/integration-tests/package.json +++ b/extensions/integration-tests/package.json @@ -9,7 +9,8 @@ "azdata": "*" }, "activationEvents": [ - "*" + "onFileSystem:memfs", + "onDebug" ], "main": "./out/main", "extensionDependencies": [ @@ -17,7 +18,8 @@ "Microsoft.import", "Microsoft.profiler", "Microsoft.mssql", - "Microsoft.notebook" + "Microsoft.notebook", + "Microsoft.azuredatastudio-postgresql" ], "contributes": { "configuration": { diff --git a/extensions/integration-tests/src/main.ts b/extensions/integration-tests/src/main.ts index 59cc50ddb8..19c844f9ea 100644 --- a/extensions/integration-tests/src/main.ts +++ b/extensions/integration-tests/src/main.ts @@ -4,122 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import * as azdata from 'azdata'; -import { normalize, join } from 'path'; -import * as fs from 'fs'; - -const TEST_SETUP_COMPLETED_TEXT: string = 'Test Setup Completed'; -const EXTENSION_LOADED_TEXT: string = 'Test Extension Loaded'; -const ALL_EXTENSION_LOADED_TEXT: string = 'All Extensions Loaded'; - -let statusBarItemTimer: NodeJS.Timer; export function activate(context: vscode.ExtensionContext) { - let statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - vscode.commands.registerCommand('test.setupIntegrationTest', async () => { - let extensionInstallersFolder = normalize(join(__dirname, '../extensionInstallers')); - console.info(`extensionInstallersFolder=${extensionInstallersFolder}`); - // eslint-disable-next-line no-sync - let installers = fs.readdirSync(extensionInstallersFolder); - for (let i = 0; i < installers.length; i++) { - if (installers[i].endsWith('.vsix')) { - let installerFullPath = join(extensionInstallersFolder, installers[i]); - console.info(`installing extension at ${installerFullPath}`); - await azdata.extensions.install(installerFullPath); - console.info(`extension has been installed successfully. vsix: ${installers[i]}`); - } - } - await setConfiguration('workbench.enablePreviewFeatures', true); - await setConfiguration('workbench.showConnectDialogOnStartup', false); - await setConfiguration('test.testSetupCompleted', true); - showStatusBarItem(statusBarItem, TEST_SETUP_COMPLETED_TEXT); - }); - - vscode.commands.registerCommand('test.waitForExtensionsToLoad', async () => { - const expectedExtensions = ['Microsoft.agent', 'Microsoft.import', 'Microsoft.mssql', 'Microsoft.profiler', 'Microsoft.azuredatastudio-postgresql']; - const commonFeatures: azdata.DataProviderType[] = [ - azdata.DataProviderType.AdminServicesProvider, - azdata.DataProviderType.BackupProvider, - azdata.DataProviderType.CapabilitiesProvider, - azdata.DataProviderType.ConnectionProvider, - azdata.DataProviderType.FileBrowserProvider, - azdata.DataProviderType.MetadataProvider, - azdata.DataProviderType.ObjectExplorerProvider, - azdata.DataProviderType.ProfilerProvider, - azdata.DataProviderType.QueryProvider, - azdata.DataProviderType.RestoreProvider, - azdata.DataProviderType.ScriptingProvider, - azdata.DataProviderType.TaskServicesProvider]; - - const features_mssql: azdata.DataProviderType[] = [ - azdata.DataProviderType.AgentServicesProvider, - azdata.DataProviderType.IconProvider - ]; - - features_mssql.push(...commonFeatures); - - const providerFeatureMapping: { providerId: string, features: azdata.DataProviderType[] }[] = [ - { - providerId: 'MSSQL', - features: features_mssql - }, { - providerId: 'PGSQL', - features: commonFeatures - }]; - - do { - let extensions = vscode.extensions.all.filter(ext => { return expectedExtensions.indexOf(ext.id) !== -1; }); - const extensionsNotInReadyState: string[] = []; - - extensions.forEach(extension => { - if (!extension.isActive) { - extensionsNotInReadyState.push(extension.id); - } - }); - - const providerTypesNotInReadyState: string[] = []; - if (extensionsNotInReadyState.length === 0) { - providerFeatureMapping.forEach(entry => { - entry.features.forEach(feature => { - const provider = azdata.dataprotocol.getProvider(entry.providerId, feature); - if (!provider) { - providerTypesNotInReadyState.push(`${entry.providerId}:${feature}`); - } - }); - }); - } - - if (extensionsNotInReadyState.length === 0 && providerTypesNotInReadyState.length === 0) { - console.info('All extensions are ready'); - showStatusBarItem(statusBarItem, ALL_EXTENSION_LOADED_TEXT); - break; - } else if (extensionsNotInReadyState.length !== 0) { - console.warn(`the following extensions are not ready: ${extensionsNotInReadyState.join(',')}`); - } else { - console.warn(`the following providers are not ready: ${providerTypesNotInReadyState.join(',')}`); - } - await new Promise(resolve => { setTimeout(resolve, 2000); }); - } - while (true); - }); - showStatusBarItem(statusBarItem, EXTENSION_LOADED_TEXT); -} - -function showStatusBarItem(statusBarItem: vscode.StatusBarItem, text: string) { - statusBarItem.text = text; - statusBarItem.tooltip = text; - statusBarItem.show(); - clearTimeout(statusBarItemTimer); - statusBarItemTimer = setTimeout(function () { - statusBarItem.hide(); - }, 5000); } // this method is called when your extension is deactivated export function deactivate(): void { } - -async function setConfiguration(name: string, value: any) { - await vscode.workspace.getConfiguration().update(name, value, true); -} diff --git a/extensions/integration-tests/src/setup.test.ts b/extensions/integration-tests/src/setup.test.ts deleted file mode 100644 index 9d81f7cd21..0000000000 --- a/extensions/integration-tests/src/setup.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import 'mocha'; -import * as vscode from 'vscode'; -import { isTestSetupCompleted } from './testContext'; -import * as assert from 'assert'; -import { getConfigValue, EnvironmentVariable_BDC_SERVER, EnvironmentVariable_BDC_USERNAME, EnvironmentVariable_BDC_PASSWORD, EnvironmentVariable_AZURE_PASSWORD, EnvironmentVariable_AZURE_SERVER, EnvironmentVariable_AZURE_USERNAME, EnvironmentVariable_STANDALONE_PASSWORD, EnvironmentVariable_STANDALONE_SERVER, EnvironmentVariable_STANDALONE_USERNAME, EnvironmentVariable_PYTHON_PATH } from './testConfig'; - -assert(getConfigValue(EnvironmentVariable_BDC_SERVER) !== undefined && - getConfigValue(EnvironmentVariable_BDC_USERNAME) !== undefined && - getConfigValue(EnvironmentVariable_BDC_PASSWORD) !== undefined && - getConfigValue(EnvironmentVariable_AZURE_PASSWORD) !== undefined && - getConfigValue(EnvironmentVariable_AZURE_SERVER) !== undefined && - getConfigValue(EnvironmentVariable_AZURE_USERNAME) !== undefined && - getConfigValue(EnvironmentVariable_STANDALONE_PASSWORD) !== undefined && - getConfigValue(EnvironmentVariable_STANDALONE_SERVER) !== undefined && - getConfigValue(EnvironmentVariable_STANDALONE_USERNAME) !== undefined && - getConfigValue(EnvironmentVariable_PYTHON_PATH) !== undefined, 'Required environment variables are not set, if you see this error in the build pipeline, make sure the environment variables are set properly in the build definition, otherwise for local dev environment make sure you follow the instructions in the readme file.'); - -if (!isTestSetupCompleted()) { - suite('integration test setup', () => { - test('test setup', async function () { - this.timeout(5 * 60 * 1000); - // Prepare the environment and make it ready for testing - await vscode.commands.executeCommand('test.setupIntegrationTest'); - // Wait for the extensions to load - await vscode.commands.executeCommand('test.waitForExtensionsToLoad'); - // Reload the window, this is required for some changes made by the 'test.setupIntegrationTest' to work - await vscode.commands.executeCommand('workbench.action.reloadWindow'); - }); - }); -} diff --git a/extensions/integration-tests/src/cms.test.ts b/extensions/integration-tests/src/tests/cms.test.ts similarity index 96% rename from extensions/integration-tests/src/cms.test.ts rename to extensions/integration-tests/src/tests/cms.test.ts index e0b5d0db4d..e439d7fb67 100644 --- a/extensions/integration-tests/src/cms.test.ts +++ b/extensions/integration-tests/src/tests/cms.test.ts @@ -6,12 +6,12 @@ import 'mocha'; import * as vscode from 'vscode'; import * as azdata from 'azdata'; -import * as mssql from '../../mssql'; -import * as utils from './utils'; -import * as uuid from './uuid'; -import { isTestSetupCompleted } from './testContext'; +import * as mssql from '../../../mssql'; +import * as utils from '../utils'; +import * as uuid from '../uuid'; +import { isTestSetupCompleted } from '../testContext'; import assert = require('assert'); -import { getStandaloneServer, TestServerProfile } from './testConfig'; +import { getStandaloneServer, TestServerProfile } from '../testConfig'; let cmsService: mssql.ICmsService; let server: TestServerProfile; diff --git a/extensions/integration-tests/src/dacpac.test.ts b/extensions/integration-tests/src/tests/dacpac.test.ts similarity index 97% rename from extensions/integration-tests/src/dacpac.test.ts rename to extensions/integration-tests/src/tests/dacpac.test.ts index aa472fb2a0..a541f83a52 100644 --- a/extensions/integration-tests/src/dacpac.test.ts +++ b/extensions/integration-tests/src/tests/dacpac.test.ts @@ -5,14 +5,14 @@ import 'mocha'; import * as azdata from 'azdata'; -import * as utils from './utils'; +import * as utils from '../utils'; import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; -import * as mssql from '../../mssql'; +import * as mssql from '../../../mssql'; import * as vscode from 'vscode'; -import { isTestSetupCompleted } from './testContext'; -import { getStandaloneServer } from './testConfig'; +import { isTestSetupCompleted } from '../testContext'; +import { getStandaloneServer } from '../testConfig'; import * as assert from 'assert'; import { promisify } from 'util'; diff --git a/extensions/integration-tests/src/index.ts b/extensions/integration-tests/src/tests/index.ts similarity index 100% rename from extensions/integration-tests/src/index.ts rename to extensions/integration-tests/src/tests/index.ts diff --git a/extensions/integration-tests/src/notebook.test.ts b/extensions/integration-tests/src/tests/notebook.test.ts similarity index 99% rename from extensions/integration-tests/src/notebook.test.ts rename to extensions/integration-tests/src/tests/notebook.test.ts index c62aa9b1f3..3fe406aa27 100644 --- a/extensions/integration-tests/src/notebook.test.ts +++ b/extensions/integration-tests/src/tests/notebook.test.ts @@ -7,10 +7,10 @@ import 'mocha'; import * as assert from 'assert'; import * as azdata from 'azdata'; import * as vscode from 'vscode'; -import { isTestSetupCompleted } from './testContext'; -import { sqlNotebookContent, writeNotebookToFile, sqlKernelMetadata, getFileName, pySparkNotebookContent, pySparkKernelMetadata, pythonKernelMetadata, sqlNotebookMultipleCellsContent, notebookContentForCellLanguageTest, sqlKernelSpec, pythonKernelSpec, pySparkKernelSpec, CellTypes } from './notebook.util'; -import { getConfigValue, EnvironmentVariable_PYTHON_PATH, TestServerProfile, getStandaloneServer } from './testConfig'; -import { connectToServer, sleep, testServerProfileToIConnectionProfile } from './utils'; +import { isTestSetupCompleted } from '../testContext'; +import { sqlNotebookContent, writeNotebookToFile, sqlKernelMetadata, getFileName, pySparkNotebookContent, pySparkKernelMetadata, pythonKernelMetadata, sqlNotebookMultipleCellsContent, notebookContentForCellLanguageTest, sqlKernelSpec, pythonKernelSpec, pySparkKernelSpec, CellTypes } from '../notebook.util'; +import { getConfigValue, EnvironmentVariable_PYTHON_PATH, TestServerProfile, getStandaloneServer } from '../testConfig'; +import { connectToServer, sleep, testServerProfileToIConnectionProfile } from '../utils'; import * as fs from 'fs'; import { stressify } from 'adstest'; import { isNullOrUndefined, promisify } from 'util'; diff --git a/extensions/integration-tests/src/objectExplorer.test.ts b/extensions/integration-tests/src/tests/objectExplorer.test.ts similarity index 98% rename from extensions/integration-tests/src/objectExplorer.test.ts rename to extensions/integration-tests/src/tests/objectExplorer.test.ts index db3a2fcad2..309e5a1d80 100644 --- a/extensions/integration-tests/src/objectExplorer.test.ts +++ b/extensions/integration-tests/src/tests/objectExplorer.test.ts @@ -5,9 +5,9 @@ import 'mocha'; import * as azdata from 'azdata'; -import { isTestSetupCompleted } from './testContext'; -import { getBdcServer, TestServerProfile, getAzureServer, getStandaloneServer } from './testConfig'; -import { connectToServer, createDB, deleteDB, DefaultConnectTimeoutInMs, asyncTimeout } from './utils'; +import { isTestSetupCompleted } from '../testContext'; +import { getBdcServer, TestServerProfile, getAzureServer, getStandaloneServer } from '../testConfig'; +import { connectToServer, createDB, deleteDB, DefaultConnectTimeoutInMs, asyncTimeout } from '../utils'; import * as assert from 'assert'; import { stressify } from 'adstest'; diff --git a/extensions/integration-tests/src/schemaCompare.test.ts b/extensions/integration-tests/src/tests/schemaCompare.test.ts similarity index 99% rename from extensions/integration-tests/src/schemaCompare.test.ts rename to extensions/integration-tests/src/tests/schemaCompare.test.ts index 59aef7cfb8..79ca3788ae 100644 --- a/extensions/integration-tests/src/schemaCompare.test.ts +++ b/extensions/integration-tests/src/tests/schemaCompare.test.ts @@ -6,14 +6,14 @@ import 'mocha'; import * as azdata from 'azdata'; import * as vscode from 'vscode'; -import * as utils from './utils'; -import * as mssql from '../../mssql'; +import * as utils from '../utils'; +import * as mssql from '../../../mssql'; import * as os from 'os'; import * as fs from 'fs'; const path = require('path'); -import { isTestSetupCompleted } from './testContext'; +import { isTestSetupCompleted } from '../testContext'; import * as assert from 'assert'; -import { getStandaloneServer } from './testConfig'; +import { getStandaloneServer } from '../testConfig'; import { stressify } from 'adstest'; import { promisify } from 'util'; diff --git a/extensions/integration-tests/test-workspace/.vscode/settings.json b/extensions/integration-tests/test-workspace/.vscode/settings.json new file mode 100644 index 0000000000..e59a76cf46 --- /dev/null +++ b/extensions/integration-tests/test-workspace/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "workbench.enablePreviewFeatures": true, + "workbench.showConnectDialogOnStartup": false +} diff --git a/extensions/machine-learning-services/src/externalLanguage/languageService.ts b/extensions/machine-learning-services/src/externalLanguage/languageService.ts index c8a8e289a9..12c452cd59 100644 --- a/extensions/machine-learning-services/src/externalLanguage/languageService.ts +++ b/extensions/machine-learning-services/src/externalLanguage/languageService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import * as mssql from '../../../mssql/src/mssql'; +import * as mssql from '../../../mssql'; import { ApiWrapper } from '../common/apiWrapper'; /** diff --git a/extensions/machine-learning-services/src/test/views/externalLanguages/languageController.test.ts b/extensions/machine-learning-services/src/test/views/externalLanguages/languageController.test.ts index 61c998b942..c0d0e3e898 100644 --- a/extensions/machine-learning-services/src/test/views/externalLanguages/languageController.test.ts +++ b/extensions/machine-learning-services/src/test/views/externalLanguages/languageController.test.ts @@ -8,7 +8,7 @@ import 'mocha'; import * as TypeMoq from 'typemoq'; import { createContext } from './utils'; import { LanguageController } from '../../../views/externalLanguages/languageController'; -import * as mssql from '../../../../../mssql/src/mssql'; +import * as mssql from '../../../../../mssql'; describe('External Languages Controller', () => { it('Should open dialog for manage languages successfully ', async function (): Promise { diff --git a/extensions/machine-learning-services/src/test/views/externalLanguages/languagesDialogModel.test.ts b/extensions/machine-learning-services/src/test/views/externalLanguages/languagesDialogModel.test.ts index b41b44f898..b6c8d78249 100644 --- a/extensions/machine-learning-services/src/test/views/externalLanguages/languagesDialogModel.test.ts +++ b/extensions/machine-learning-services/src/test/views/externalLanguages/languagesDialogModel.test.ts @@ -6,7 +6,7 @@ import * as should from 'should'; import 'mocha'; import { createContext } from './utils'; -import * as mssql from '../../../../../mssql/src/mssql'; +import * as mssql from '../../../../../mssql'; import { LanguageService } from '../../../externalLanguage/languageService'; describe('External Languages Dialog Model', () => { diff --git a/extensions/machine-learning-services/src/test/views/externalLanguages/utils.ts b/extensions/machine-learning-services/src/test/views/externalLanguages/utils.ts index 95420783b7..c3aa267494 100644 --- a/extensions/machine-learning-services/src/test/views/externalLanguages/utils.ts +++ b/extensions/machine-learning-services/src/test/views/externalLanguages/utils.ts @@ -8,7 +8,7 @@ import * as vscode from 'vscode'; import * as TypeMoq from 'typemoq'; import { ApiWrapper } from '../../../common/apiWrapper'; import { LanguageViewBase } from '../../../views/externalLanguages/languageViewBase'; -import * as mssql from '../../../../../mssql/src/mssql'; +import * as mssql from '../../../../../mssql'; import { LanguageService } from '../../../externalLanguage/languageService'; import { createViewContext } from '../utils'; diff --git a/extensions/machine-learning-services/src/views/externalLanguages/languageContentView.ts b/extensions/machine-learning-services/src/views/externalLanguages/languageContentView.ts index 3be3d04c04..1df7404d49 100644 --- a/extensions/machine-learning-services/src/views/externalLanguages/languageContentView.ts +++ b/extensions/machine-learning-services/src/views/externalLanguages/languageContentView.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as azdata from 'azdata'; -import * as mssql from '../../../../mssql/src/mssql'; +import * as mssql from '../../../../mssql'; import { LanguageViewBase } from './languageViewBase'; import * as constants from '../../common/constants'; import { ApiWrapper } from '../../common/apiWrapper'; diff --git a/extensions/machine-learning-services/src/views/externalLanguages/languageController.ts b/extensions/machine-learning-services/src/views/externalLanguages/languageController.ts index 63ad405bd4..7d18ee14b7 100644 --- a/extensions/machine-learning-services/src/views/externalLanguages/languageController.ts +++ b/extensions/machine-learning-services/src/views/externalLanguages/languageController.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as mssql from '../../../../mssql/src/mssql'; +import * as mssql from '../../../../mssql'; import { ApiWrapper } from '../../common/apiWrapper'; import { LanguageService } from '../../externalLanguage/languageService'; import { LanguagesDialog } from './languagesDialog'; diff --git a/extensions/machine-learning-services/src/views/externalLanguages/languageViewBase.ts b/extensions/machine-learning-services/src/views/externalLanguages/languageViewBase.ts index 9e3cc04550..df432451a5 100644 --- a/extensions/machine-learning-services/src/views/externalLanguages/languageViewBase.ts +++ b/extensions/machine-learning-services/src/views/externalLanguages/languageViewBase.ts @@ -7,7 +7,7 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import * as constants from '../../common/constants'; import { ApiWrapper } from '../../common/apiWrapper'; -import * as mssql from '../../../../mssql/src/mssql'; +import * as mssql from '../../../../mssql'; import * as path from 'path'; export interface LanguageUpdateModel { diff --git a/extensions/machine-learning-services/src/views/externalLanguages/languagesTable.ts b/extensions/machine-learning-services/src/views/externalLanguages/languagesTable.ts index 838afc5542..3fe1dda8a1 100644 --- a/extensions/machine-learning-services/src/views/externalLanguages/languagesTable.ts +++ b/extensions/machine-learning-services/src/views/externalLanguages/languagesTable.ts @@ -5,7 +5,7 @@ import * as azdata from 'azdata'; import * as constants from '../../common/constants'; -import * as mssql from '../../../../mssql/src/mssql'; +import * as mssql from '../../../../mssql'; import { LanguageViewBase } from './languageViewBase'; import { ApiWrapper } from '../../common/apiWrapper'; diff --git a/scripts/sql-test-integration.bat b/scripts/sql-test-integration.bat index b96bce3804..0bc551b0a8 100644 --- a/scripts/sql-test-integration.bat +++ b/scripts/sql-test-integration.bat @@ -47,7 +47,7 @@ if "%SKIP_PYTHON_INSTALL_TEST%" == "1" ( ) call %INTEGRATION_TEST_ELECTRON_PATH% --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222 ^ ---extensionDevelopmentPath=%~dp0\..\extensions\integration-tests --extensionTestsPath=%~dp0\..\extensions\integration-tests\out --disable-telemetry --disable-crash-reporter --disable-updates -nogpu +--extensionDevelopmentPath=%~dp0\..\extensions\integration-tests --extensionTestsPath=%~dp0\..\extensions\integration-tests\out\tests --disable-telemetry --disable-crash-reporter --disable-updates -nogpu rmdir /s /q %VSCODEUSERDATADIR% rmdir /s /q %VSCODEEXTENSIONSDIR% diff --git a/scripts/sql-test-integration.sh b/scripts/sql-test-integration.sh index 43e1a4a18e..fafaebe858 100755 --- a/scripts/sql-test-integration.sh +++ b/scripts/sql-test-integration.sh @@ -60,7 +60,7 @@ fi --extensionDevelopmentPath=$ROOT/extensions/profiler \ --extensionDevelopmentPath=$ROOT/extensions/resource-deployment \ --extensionDevelopmentPath=$ROOT/extensions/schema-compare \ ---extensionTestsPath=$ROOT/extensions/integration-tests/out \ +--extensionTestsPath=$ROOT/extensions/integration-tests/out/tests \ --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR \ --disable-telemetry --disable-crash-reporter --disable-updates --skip-getting-started --disable-inspect diff --git a/src/sql/workbench/services/connection/browser/connectionManagementService.ts b/src/sql/workbench/services/connection/browser/connectionManagementService.ts index 909906d1a3..952b1aa3e8 100644 --- a/src/sql/workbench/services/connection/browser/connectionManagementService.ts +++ b/src/sql/workbench/services/connection/browser/connectionManagementService.ts @@ -50,6 +50,7 @@ import { find } from 'vs/base/common/arrays'; import { values } from 'vs/base/common/collections'; import { assign } from 'vs/base/common/objects'; import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; export class ConnectionManagementService extends Disposable implements IConnectionManagementService { @@ -90,7 +91,8 @@ export class ConnectionManagementService extends Disposable implements IConnecti @IAccountManagementService private _accountManagementService: IAccountManagementService, @ILogService private _logService: ILogService, @IStorageService private _storageService: IStorageService, - @IEnvironmentService private _environmentService: IEnvironmentService + @IEnvironmentService private _environmentService: IEnvironmentService, + @IExtensionService private readonly extensionService: IExtensionService ) { super(); @@ -819,6 +821,8 @@ export class ConnectionManagementService extends Disposable implements IConnecti options: connection.options }); + await this.extensionService.activateByEvent(`onConnect:${connection.providerName}`); + return this._providers.get(connection.providerName).onReady.then((provider) => { provider.connect(uri, connectionInfo); this._onConnectRequestSent.fire(); diff --git a/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts b/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts index e04431f2ca..254e627d0f 100644 --- a/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts +++ b/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts @@ -35,6 +35,7 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { assign } from 'vs/base/common/objects'; import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; suite('SQL ConnectionManagementService tests', () => { @@ -164,7 +165,8 @@ suite('SQL ConnectionManagementService tests', () => { accountManagementService.object, new NullLogService(), // ILogService undefined, // IStorageService - TestEnvironmentService + TestEnvironmentService, + getBasicExtensionService() ); return connectionManagementService; } @@ -922,7 +924,7 @@ suite('SQL ConnectionManagementService tests', () => { connectionStoreMock.setup(x => x.getConnectionProfileGroups(TypeMoq.It.isAny(), undefined)).returns(() => { return [group1]; }); - const connectionManagementService = new ConnectionManagementService(connectionStoreMock.object, connectionStatusManagerMock.object, undefined, undefined, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined); + const connectionManagementService = new ConnectionManagementService(connectionStoreMock.object, connectionStatusManagerMock.object, undefined, undefined, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService()); // dupe connections have been seeded the numbers below already reflected the de-duped results @@ -968,3 +970,9 @@ function createConnectionProfile(id: string): ConnectionProfile { function createConnectionGroup(id: string): ConnectionProfileGroup { return new ConnectionProfileGroup(id, undefined, id, undefined, undefined); } + +function getBasicExtensionService(): IExtensionService { + return { + activateByEvent: () => Promise.resolve() + }; +} diff --git a/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts index 5f4a3b4634..e5cd680a29 100644 --- a/src/vs/platform/driver/browser/baseDriver.ts +++ b/src/vs/platform/driver/browser/baseDriver.ts @@ -53,10 +53,10 @@ export abstract class BaseWindowDriver implements IWindowDriver { return Promise.reject(new Error(`Element not found: ${selector}`)); } - const inputElement = element as HTMLInputElement; + const inputElement = element as HTMLInputElement | HTMLSelectElement; // {{SQL CARBON EDIT}} handle select element inputElement.value = text; - const event = new Event('input', { bubbles: true, cancelable: true }); + const event = new Event(inputElement.tagName === 'INPUT' ? 'input' : 'change', { bubbles: true, cancelable: true }); // {{SQL CARBON EDIT}} handle select element inputElement.dispatchEvent(event); } diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index 4c791bcf07..1ef57ecb67 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -121,7 +121,7 @@ export async function spawn(options: SpawnOptions): Promise { let connectDriver: typeof connectElectronDriver; if (options.web) { - await launch(options.userDataDir, options.workspacePath, options.codePath); + await launch(options.userDataDir, options.workspacePath, options.extensionsPath, options.codePath); connectDriver = connectPlaywrightDriver.bind(connectPlaywrightDriver, options.browser); return connect(connectDriver, child, '', handle, options.logger); } diff --git a/test/automation/src/playwrightDriver.ts b/test/automation/src/playwrightDriver.ts index 2560cf75ee..69af0616d3 100644 --- a/test/automation/src/playwrightDriver.ts +++ b/test/automation/src/playwrightDriver.ts @@ -92,7 +92,7 @@ let server: ChildProcess | undefined; let endpoint: string | undefined; let workspacePath: string | undefined; -export async function launch(userDataDir: string, _workspacePath: string, codeServerPath = process.env.VSCODE_REMOTE_SERVER_PATH): Promise { +export async function launch(userDataDir: string, _workspacePath: string, extensionsDir: string, codeServerPath = process.env.VSCODE_REMOTE_SERVER_PATH): Promise { workspacePath = _workspacePath; const agentFolder = userDataDir; @@ -110,7 +110,7 @@ export async function launch(userDataDir: string, _workspacePath: string, codeSe } server = spawn( serverLocation, - ['--browser', 'none', '--driver', 'web'], + ['--browser', 'none', '--driver', 'web', '--extensions-dir', `${extensionsDir}`], { env } ); server.stderr?.on('data', error => console.log(`Server stderr: ${error}`)); diff --git a/test/automation/src/sql/queryEditor.ts b/test/automation/src/sql/queryEditor.ts new file mode 100644 index 0000000000..ef1c34333a --- /dev/null +++ b/test/automation/src/sql/queryEditor.ts @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Code } from '../code'; + +export class QueryEditor { + + public readonly commandBar: CommandBar; + + constructor(code: Code) { + this.commandBar = new CommandBar(code); + } + +} + +export class CommandBar { + + private static readonly COMMAND_BAR_BUTTON = '.query-editor .carbon-taskbar ul>:nth-child(${INDEX})'; + + constructor(private code: Code) { } + + public async clickButton(index: number): Promise { + await this.code.waitAndClick(CommandBar.COMMAND_BAR_BUTTON.replace('${INDEX}', '' + index)); + } + + public async waitForButton(index: number, label: string): Promise { + await this.code.waitForTextContent(CommandBar.COMMAND_BAR_BUTTON.replace('${INDEX}', '' + index), label); + } +} diff --git a/test/automation/src/workbench.ts b/test/automation/src/workbench.ts index 4057e0ee68..917032c5d6 100644 --- a/test/automation/src/workbench.ts +++ b/test/automation/src/workbench.ts @@ -24,6 +24,7 @@ import { Terminal } from './terminal'; import { ConnectionDialog } from './sql/connectionDialog'; import { Profiler } from './sql/profiler'; import { QueryEditors } from './sql/queryEditors'; +import { QueryEditor } from './sql/queryEditor'; // {{END}} export interface Commands { @@ -52,6 +53,7 @@ export class Workbench { readonly connectionDialog: ConnectionDialog; readonly profiler: Profiler; readonly queryEditors: QueryEditors; + readonly queryEditor: QueryEditor; // {{END}} constructor(code: Code, userDataPath: string) { @@ -74,6 +76,7 @@ export class Workbench { this.connectionDialog = new ConnectionDialog(code); this.profiler = new Profiler(code, this.quickaccess); this.queryEditors = new QueryEditors(code); + this.queryEditor = new QueryEditor(code); // {{END}} } } diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 14928553ec..b146fa3ce2 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -21,13 +21,8 @@ import { FileLogger, } from '../../automation'; -//{{SQL CARBON EDIT}} -import { setup as runProfilerTests } from './sql/profiler/profiler.test'; -import { setup as runQueryEditorTests } from './sql/queryEditor/queryEditor.test'; - -//Original -/* -import { setup as setupDataMigrationTests } from './areas/workbench/data-migration.test'; +import { main as sqlMain, setup as sqlSetup } from './sql/main'; //{{SQL CARBON EDIT}} +/*import { setup as setupDataMigrationTests } from './areas/workbench/data-migration.test'; import { setup as setupDataLossTests } from './areas/workbench/data-loss.test'; import { setup as setupDataPreferencesTests } from './areas/preferences/preferences.test'; import { setup as setupDataSearchTests } from './areas/search/search.test'; @@ -38,7 +33,7 @@ import { setup as setupDataExtensionTests } from './areas/extensions/extensions. import { setup as setupTerminalTests } from './areas/terminal/terminal.test'; import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test'; import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test'; -import { setup as setupLaunchTests } from './areas/workbench/launch.test';*///{{END}} +import { setup as setupLaunchTests } from './areas/workbench/launch.test';*/ if (!/^v10/.test(process.version) && !/^v12/.test(process.version)) { console.error('Error: Smoketest must be run using Node 10/12. Currently running', process.version); @@ -70,8 +65,8 @@ const opts = minimist(args, { } }); -const testRepoUrl = 'https://github.com/Microsoft/vscode-smoketest-express'; -const workspacePath = path.join(testDataPath, 'vscode-smoketest-express'); +const testRepoUrl = 'https://github.com/anthonydresser/azuredatastudio-smoke-test-repo.git'; +const workspacePath = path.join(testDataPath, 'azuredatastudio-smoke-test-repo'); const extensionsPath = path.join(testDataPath, 'extensions-dir'); mkdirp.sync(extensionsPath); @@ -210,8 +205,8 @@ async function setupRepository(): Promise { cp.spawnSync('git', ['clean', '-xdf'], { cwd: workspacePath }); } - console.log('*** Running yarn...'); - cp.execSync('yarn', { cwd: workspacePath, stdio: 'inherit' }); + // console.log('*** Running yarn...'); + // cp.execSync('yarn', { cwd: workspacePath, stdio: 'inherit' }); } } @@ -258,6 +253,7 @@ before(async function () { this.timeout(2 * 60 * 1000); // allow two minutes for setup await setup(); this.defaultOptions = createOptions(); + await sqlSetup(this.defaultOptions); }); after(async function () { @@ -272,25 +268,11 @@ after(async function () { await new Promise((c, e) => rimraf(testDataPath, { maxBusyTries: 10 }, err => err ? e(err) : c())); }); -describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { +describe(`Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { before(async function () { const app = new Application(this.defaultOptions); await app!.start(opts.web ? false : undefined); this.app = app; - //{{SQL CARBON EDIT}} - const testExtLoadedText = 'Test Extension Loaded'; - const testSetupCompletedText = 'Test Setup Completed'; - const allExtensionsLoadedText = 'All Extensions Loaded'; - const setupTestCommand = 'Test: Setup Integration Test'; - const waitForExtensionsCommand = 'Test: Wait For Extensions To Load'; - await app.workbench.statusbar.waitForStatusbarText(testExtLoadedText, testExtLoadedText); - await app.workbench.quickaccess.runCommand(setupTestCommand); - await app.workbench.statusbar.waitForStatusbarText(testSetupCompletedText, testSetupCompletedText); - await app!.reload(); - await app.workbench.statusbar.waitForStatusbarText(testExtLoadedText, testExtLoadedText); - await app.workbench.quickaccess.runCommand(waitForExtensionsCommand); - await app.workbench.statusbar.waitForStatusbarText(allExtensionsLoadedText, allExtensionsLoadedText); - //{{END}} }); after(async function () { @@ -318,6 +300,7 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { }); } + sqlMain(); /*if (!opts.web) { setupDataMigrationTests(opts['stable-build'], testDataPath); } if (!opts.web) { setupDataLossTests(); } if (!opts.web) { setupDataPreferencesTests(); } @@ -330,6 +313,4 @@ describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => { if (!opts.web) { setupDataMultirootTests(); } if (!opts.web) { setupDataLocalizationTests(); } if (!opts.web) { setupLaunchTests(); }*/ - runProfilerTests(); // {{SQL CARBON EDIT}} add our tests - runQueryEditorTests(); // {{SQL CARBON EDIT}} add our tests }); diff --git a/test/smoke/src/sql/profiler/profiler.test.ts b/test/smoke/src/sql/areas/profiler/profiler.test.ts similarity index 90% rename from test/smoke/src/sql/profiler/profiler.test.ts rename to test/smoke/src/sql/areas/profiler/profiler.test.ts index c96b2004ed..1e21766399 100644 --- a/test/smoke/src/sql/profiler/profiler.test.ts +++ b/test/smoke/src/sql/areas/profiler/profiler.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Application, getStandaloneServer } from '../../../../automation'; +import { Application, getStandaloneServer } from '../../../../../automation'; export function setup() { describe('profiler test suite', () => { diff --git a/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts b/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts new file mode 100644 index 0000000000..9445ae6da6 --- /dev/null +++ b/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Application } from '../../../../../automation'; + +export function setup() { + describe('Query Editor', () => { + + it('can open and connect file', async function () { + const app = this.app as Application; + await app.workbench.quickaccess.openFile('test.sql'); + await app.workbench.queryEditor.commandBar.clickButton(3); + await app.workbench.connectionDialog.waitForConnectionDialog(); + await app.code.waitForSetValue('.modal .modal-body select[aria-label="Connection type"]', 'Sqlite'); + await app.code.waitForSetValue('.modal .modal-body input[aria-label="File"]', 'chinook.db'); + await app.code.waitAndClick('.modal .modal-footer a[aria-label="Connect"]'); + await app.workbench.queryEditor.commandBar.waitForButton(3, 'Disconnect'); + }); + }); +} diff --git a/test/smoke/src/sql/main.ts b/test/smoke/src/sql/main.ts new file mode 100644 index 0000000000..8f66476c87 --- /dev/null +++ b/test/smoke/src/sql/main.ts @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { setup as setupQueryEditorTest } from './areas/queryEditor/queryEditor.test'; +import { ApplicationOptions } from '../../../automation'; +import * as yazl from 'yauzl'; +import * as fs from 'fs'; +import * as path from 'path'; +import { request } from 'https'; +import * as mkdirp from 'mkdirp'; + +export function main(): void { + setupQueryEditorTest(); +} + +/* eslint-disable no-sync */ +const PLATFORM = '${PLATFORM}'; +const RUNTIME = '${RUNTIME}'; +const VERSION = '${VERSION}'; + +const sqliteUrl = `https://github.com/anthonydresser/azuredatastudio-sqlite/releases/download/1.0.5/azuredatastudio-sqlite-${PLATFORM}-${RUNTIME}-${VERSION}.zip`; + +export async function setup(app: ApplicationOptions): Promise { + const requestUrl = sqliteUrl.replace(PLATFORM, process.platform).replace(RUNTIME, getRuntime(app.web || app.remote || false)).replace(VERSION, getVersion(app.web || app.remote || false)); + const zip = await fetch(requestUrl); + return new Promise((resolve, reject) => { + yazl.fromBuffer(zip, (e, zipFile) => { + if (e || !zipFile) { + reject(e); + return; + } + + zipFile.on('entry', (entry: yazl.Entry) => { + if (/\/$/.test(entry.fileName)) { + return; + } + zipFile.openReadStream(entry, (err, readStream) => { + if (err || !readStream) { + reject(err); + return; + } + const destination = path.join(app.extensionsPath, 'azuredatastudio-sqlite', entry.fileName); + if (fs.existsSync(path.dirname(destination))) { + readStream.pipe(fs.createWriteStream(destination)); + return; + } + + mkdirp(path.dirname(destination), err => { + if (err) { + reject(err); + return; + } + readStream.pipe(fs.createWriteStream(destination)); + }); + }); + }).once('end', () => resolve()); + }); + }); +} + +const root = path.dirname(path.dirname(path.dirname(path.dirname(__dirname)))); + +function getRuntime(remote: boolean) { + // eslint-disable-next-line no-sync + const yarnrc = fs.readFileSync(remote ? path.join(root, 'remote', '.yarnrc') : path.join(root, '.yarnrc'), 'utf8'); + const runtime = /^runtime "(.*)"$/m.exec(yarnrc)![1]; + return runtime; +} + +function getVersion(remote: boolean) { + // eslint-disable-next-line no-sync + const yarnrc = fs.readFileSync(remote ? path.join(root, 'remote', '.yarnrc') : path.join(root, '.yarnrc'), 'utf8'); + const target = /^target "(.*)"$/m.exec(yarnrc)![1]; + return target; +} + +function fetch(url: string): Promise { + return new Promise((resolve, reject) => { + const buffers: Buffer[] = []; + const req = request(url, res => { + if (res.headers.location) { + resolve(fetch(res.headers.location)); + } else { + res.on('data', chunk => buffers.push(chunk)); + res.on('end', () => resolve(Buffer.concat(buffers))); + res.on('error', e => reject(e)); + } + }); + + req.end(); + }); +} diff --git a/test/smoke/src/sql/queryEditor/queryEditor.test.ts b/test/smoke/src/sql/queryEditor/queryEditor.test.ts deleted file mode 100644 index 96b09ef889..0000000000 --- a/test/smoke/src/sql/queryEditor/queryEditor.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Application } from '../../../../automation'; -import { promises as fs } from 'fs'; -import * as os from 'os'; -import * as path from 'path'; - -export function setup() { - describe('Query Editor Test Suite', () => { - - it('Can open and edit existing file', async function () { - const testFilePath = path.join(os.tmpdir(), 'QueryEditorSmokeTest.sql'); - await fs.writeFile(testFilePath, ''); - try { - const app = this.app as Application; - await app.workbench.quickaccess.openFile(testFilePath); - const fileBaseName = path.basename(testFilePath); - await app.workbench.editor.waitForTypeInEditor(fileBaseName, 'SELECT * FROM sys.tables'); - } - finally { - await fs.unlink(testFilePath); - } - }); - }); -}