diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index d1a6e3490c..fae1d0fcd3 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "3.0.0-release.93", + "version": "3.0.0-release.94", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp3.1.zip", "Windows_64": "win-x64-netcoreapp3.1.zip", diff --git a/package.json b/package.json index 707cdb2c0f..ff1b64bd8a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "azuredatastudio", "version": "1.29.0", - "distro": "4a6a8dea5e72ce892b5fc16c2cec0c43a3775f7b", + "distro": "2c6adba5d5c27f8119165dfa988b318cfe91a208", "author": { "name": "Microsoft Corporation" }, diff --git a/src/sql/workbench/api/common/extHostDataProtocol.ts b/src/sql/workbench/api/common/extHostDataProtocol.ts index c74d2e6821..96ca04566e 100644 --- a/src/sql/workbench/api/common/extHostDataProtocol.ts +++ b/src/sql/workbench/api/common/extHostDataProtocol.ts @@ -11,7 +11,7 @@ import { Disposable } from 'vs/workbench/api/common/extHostTypes'; import { SqlMainContext, MainThreadDataProtocolShape, ExtHostDataProtocolShape } from 'sql/workbench/api/common/sqlExtHost.protocol'; import { DataProviderType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { IURITransformer } from 'vs/base/common/uriIpc'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { RunOnceScheduler } from 'vs/base/common/async'; import { mapToSerializable } from 'sql/base/common/map'; @@ -38,6 +38,11 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { this._proxy = mainContext.getProxy(SqlMainContext.MainThreadDataProtocol); } + private _getTransformedUri(uri: string, transformMethod: (uri: UriComponents) => UriComponents): string { + let encodedUri = URI.parse(encodeURI(uri)); + return URI.from(transformMethod(encodedUri)).toString(true); + } + private _createDisposable(handle: number): Disposable { return new Disposable(() => { this._adapter.delete(handle); @@ -197,7 +202,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { // Connection Management handlers $connect(handle: number, connectionUri: string, connection: azdata.ConnectionInfo): Thenable { if (this.uriTransformer) { - connectionUri = URI.from(this.uriTransformer.transformIncoming(URI.parse(connectionUri))).toString(true); + connectionUri = this._getTransformedUri(connectionUri, this.uriTransformer.transformIncoming); } return this._resolveProvider(handle).connect(connectionUri, connection); } @@ -237,7 +242,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { $onConnectComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void { if (this.uriTransformer) { - connectionInfoSummary.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(connectionInfoSummary.ownerUri))).toString(true); + connectionInfoSummary.ownerUri = this._getTransformedUri(connectionInfoSummary.ownerUri, this.uriTransformer.transformOutgoing); } this._proxy.$onConnectionComplete(handle, connectionInfoSummary); } @@ -263,7 +268,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { $runQuery(handle: number, ownerUri: string, selection: azdata.ISelectionData, runOptions?: azdata.ExecutionPlanOptions): Thenable { if (this.uriTransformer) { - ownerUri = URI.from(this.uriTransformer.transformIncoming(URI.parse(ownerUri))).toString(true); + ownerUri = this._getTransformedUri(ownerUri, this.uriTransformer.transformIncoming); } return this._resolveProvider(handle).runQuery(ownerUri, selection, runOptions); @@ -299,21 +304,21 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { $getQueryRows(handle: number, rowData: azdata.QueryExecuteSubsetParams): Thenable { if (this.uriTransformer) { - rowData.ownerUri = URI.from(this.uriTransformer.transformIncoming(URI.parse(rowData.ownerUri))).toString(true); + rowData.ownerUri = this._getTransformedUri(rowData.ownerUri, this.uriTransformer.transformIncoming); } return this._resolveProvider(handle).getQueryRows(rowData); } $disposeQuery(handle: number, ownerUri: string): Thenable { if (this.uriTransformer) { - ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(ownerUri))).toString(true); + ownerUri = this._getTransformedUri(ownerUri, this.uriTransformer.transformOutgoing); } return this._resolveProvider(handle).disposeQuery(ownerUri); } $onQueryComplete(handle: number, result: azdata.QueryExecuteCompleteNotificationResult): void { if (this.uriTransformer) { - result.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(result.ownerUri))).toString(true); + result.ownerUri = this._getTransformedUri(result.ownerUri, this.uriTransformer.transformOutgoing); } // clear messages to maintain the order of things if (this.messageRunner.isScheduled()) { @@ -324,13 +329,13 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { } $onBatchStart(handle: number, batchInfo: azdata.QueryExecuteBatchNotificationParams): void { if (this.uriTransformer) { - batchInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(batchInfo.ownerUri))).toString(true); + batchInfo.ownerUri = this._getTransformedUri(batchInfo.ownerUri, this.uriTransformer.transformOutgoing); } this._proxy.$onBatchStart(handle, batchInfo); } $onBatchComplete(handle: number, batchInfo: azdata.QueryExecuteBatchNotificationParams): void { if (this.uriTransformer) { - batchInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(batchInfo.ownerUri))).toString(true); + batchInfo.ownerUri = this._getTransformedUri(batchInfo.ownerUri, this.uriTransformer.transformOutgoing); } this.messageRunner.cancel(); // clear batch messages before saying we completed the batch this.sendMessages(); @@ -338,19 +343,19 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { } $onResultSetAvailable(handle: number, resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void { if (this.uriTransformer) { - resultSetInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(resultSetInfo.ownerUri))).toString(true); + resultSetInfo.ownerUri = this._getTransformedUri(resultSetInfo.ownerUri, this.uriTransformer.transformOutgoing); } this._proxy.$onResultSetAvailable(handle, resultSetInfo); } $onResultSetUpdated(handle: number, resultSetInfo: azdata.QueryExecuteResultSetNotificationParams): void { if (this.uriTransformer) { - resultSetInfo.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(resultSetInfo.ownerUri))).toString(true); + resultSetInfo.ownerUri = this._getTransformedUri(resultSetInfo.ownerUri, this.uriTransformer.transformOutgoing); } this._proxy.$onResultSetUpdated(handle, resultSetInfo); } $onQueryMessage(message: azdata.QueryExecuteMessageParams): void { if (this.uriTransformer) { - message.ownerUri = URI.from(this.uriTransformer.transformOutgoing(URI.parse(message.ownerUri))).toString(true); + message.ownerUri = this._getTransformedUri(message.ownerUri, this.uriTransformer.transformOutgoing); } if (!this.queuedMessages.has(message.ownerUri)) { this.queuedMessages.set(message.ownerUri, []); diff --git a/test/smoke/src/sql/areas/notebook/notebook.test.ts b/test/smoke/src/sql/areas/notebook/notebook.test.ts index e836b67fbe..c18ca387d5 100644 --- a/test/smoke/src/sql/areas/notebook/notebook.test.ts +++ b/test/smoke/src/sql/areas/notebook/notebook.test.ts @@ -26,20 +26,17 @@ export function setup() { it('can open ipynb file, run all, and save notebook with outputs', async function () { const app = this.app as Application; - await app.workbench.sqlNotebook.openFile('hello.ipynb'); - await app.workbench.sqlNotebook.waitForKernel('Python 3'); + await openAndRunNotebook(app, 'hello.ipynb'); + }); - await app.workbench.sqlNotebook.clearResults(); - await app.workbench.sqlNotebook.waitForAllResultsGone(); - await app.workbench.sqlNotebook.runAllCells(); - await app.workbench.sqlNotebook.waitForAllResults(); + it('can open ipynb file from path with spaces, run all, and save notebook with outputs', async function () { + const app = this.app as Application; + await openAndRunNotebook(app, 'helloWithSpaces.ipynb'); + }); - await app.workbench.quickaccess.runCommand('workbench.action.files.save'); - await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor'); - - await app.workbench.sqlNotebook.openFile('hello.ipynb'); - await app.workbench.sqlNotebook.waitForKernel('Python 3'); - await app.workbench.sqlNotebook.waitForAllResults(); + it('can open ipynb file from path with escaped spaces, run all, and save notebook with outputs', async function () { + const app = this.app as Application; + await openAndRunNotebook(app, 'helloWithEscapedSpaces.ipynb'); }); it('can open untrusted notebook, trust, save, and reopen trusted notebook', async function () { @@ -64,3 +61,20 @@ export function setup() { }); }); } + +async function openAndRunNotebook(app: Application, filename: string): Promise { + await app.workbench.sqlNotebook.openFile(filename); + await app.workbench.sqlNotebook.waitForKernel('Python 3'); + + await app.workbench.sqlNotebook.clearResults(); + await app.workbench.sqlNotebook.waitForAllResultsGone(); + await app.workbench.sqlNotebook.runAllCells(); + await app.workbench.sqlNotebook.waitForAllResults(); + + await app.workbench.quickaccess.runCommand('workbench.action.files.save'); + await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor'); + + await app.workbench.sqlNotebook.openFile(filename); + await app.workbench.sqlNotebook.waitForKernel('Python 3'); + await app.workbench.sqlNotebook.waitForAllResults(); +} diff --git a/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts b/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts index 67198386aa..277287b873 100644 --- a/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts +++ b/test/smoke/src/sql/areas/queryEditor/queryEditor.test.ts @@ -21,22 +21,39 @@ export function setup() { await app.workbench.connectionDialog.connect(); await app.workbench.queryEditor.commandBar.run(); await app.workbench.queryEditor.waitForResults(); - await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors'); }); }); } export function setupWeb() { - it('can open, connect and execute file', async function () { + afterEach(async function (): Promise { const app = this.app as Application; - await app.workbench.quickaccess.openFile('test.sql'); - await app.workbench.queryEditor.commandBar.connect(); - await app.workbench.connectionDialog.waitForConnectionDialog(); - await app.workbench.connectionDialog.setProvider('Sqlite'); - await app.workbench.connectionDialog.setTarget('File', 'chinook.db'); - await app.workbench.connectionDialog.connect(); - await app.workbench.queryEditor.commandBar.run(); - await app.workbench.queryEditor.waitForResults(); await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors'); }); + + it('can open, connect and execute file', async function () { + const app = this.app as Application; + await openAndExecuteFile(app, 'test.sql'); + }); + + it('can open, connect and execute file with spaces', async function () { + const app = this.app as Application; + await openAndExecuteFile(app, 'testWithSpaces.sql'); + }); + it('can open, connect and execute file with escaped spaces', async function () { + const app = this.app as Application; + await openAndExecuteFile(app, 'testWithEscapedSpaces.sql'); + }); +} + +async function openAndExecuteFile(app: Application, filename: string): Promise { + await app.workbench.quickaccess.openFile(filename); + await app.workbench.queryEditor.commandBar.connect(); + await app.workbench.connectionDialog.waitForConnectionDialog(); + await app.workbench.connectionDialog.setProvider('Sqlite'); + await app.workbench.connectionDialog.setTarget('File', 'chinook.db'); + await app.workbench.connectionDialog.connect(); + + await app.workbench.queryEditor.commandBar.run(); + await app.workbench.queryEditor.waitForResults(); } diff --git a/test/smoke/src/sql/main.ts b/test/smoke/src/sql/main.ts index 7f5da6e2ac..22bbdf7640 100644 --- a/test/smoke/src/sql/main.ts +++ b/test/smoke/src/sql/main.ts @@ -31,7 +31,7 @@ const PLATFORM = '${PLATFORM}'; const RUNTIME = '${RUNTIME}'; const VERSION = '${VERSION}'; -const sqliteUrl = `https://github.com/Microsoft/azuredatastudio-sqlite/releases/download/1.1.1/azuredatastudio-sqlite-${PLATFORM}-${RUNTIME}-${VERSION}.zip`; +const sqliteUrl = `https://github.com/Microsoft/azuredatastudio-sqlite/releases/download/1.1.2/azuredatastudio-sqlite-${PLATFORM}-${RUNTIME}-${VERSION}.zip`; export async function setup(app: ApplicationOptions): Promise { console.log('*** Downloading test extensions');