diff --git a/extensions/notebook/src/jupyter/jupyterSessionManager.ts b/extensions/notebook/src/jupyter/jupyterSessionManager.ts index 14a91f699f..777edf208f 100644 --- a/extensions/notebook/src/jupyter/jupyterSessionManager.ts +++ b/extensions/notebook/src/jupyter/jupyterSessionManager.ts @@ -318,7 +318,6 @@ export class JupyterSession implements nb.ISession { if (this.isIntegratedAuth(connectionProfile)) { doNotCallChangeEndpointParams = `%_do_not_call_change_endpoint --server=${server} --auth=Kerberos`; } else { - doNotCallChangeEndpointParams = `%_do_not_call_change_endpoint --username=${connectionProfile.options[USER]} --password=${credentials.password} --server=${server} --auth=Basic_Access`; } let future = this.sessionImpl.kernel.requestExecute({ diff --git a/extensions/notebook/src/test/model/sessionManager.test.ts b/extensions/notebook/src/test/model/sessionManager.test.ts index 844fc22f09..751cf10dc3 100644 --- a/extensions/notebook/src/test/model/sessionManager.test.ts +++ b/extensions/notebook/src/test/model/sessionManager.test.ts @@ -5,13 +5,28 @@ import * as should from 'should'; import * as TypeMoq from 'typemoq'; -import { nb } from 'azdata'; +import * as utils from '../../common/utils'; +import * as sinon from 'sinon'; +import * as os from 'os'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as bdc from 'bdc'; +import * as vscode from 'vscode'; +import { nb, IConnectionProfile, connection, ConnectionOptionSpecialType, ServerInfo } from 'azdata'; import { SessionManager, Session, Kernel } from '@jupyterlab/services'; import 'mocha'; - import { JupyterSessionManager, JupyterSession } from '../../jupyter/jupyterSessionManager'; import { Deferred } from '../../common/promise'; -import { SessionStub, KernelStub } from '../common'; +import { SessionStub, KernelStub, FutureStub } from '../common'; + +export class TestClusterController implements bdc.IClusterController { + getClusterConfig(): Promise { + throw new Error('Method not implemented.'); + } + getKnoxUsername(clusterUsername: string): Promise { + return Promise.resolve('knoxUsername'); + } +} describe('Jupyter Session Manager', function (): void { let mockJupyterManager = TypeMoq.Mock.ofType(); @@ -111,6 +126,10 @@ describe('Jupyter Session', function (): void { session = new JupyterSession(mockJupyterSession.object, undefined, true); }); + afterEach(() => { + sinon.restore(); + }); + it('should always be able to change kernels', function (): void { should(session.canChangeKernels).be.true(); }); @@ -166,4 +185,125 @@ describe('Jupyter Session', function (): void { should(kernel.id).equal('id'); should(options.name).equal('python'); }); + + it('should write configuration to config.json file', async function (): Promise { + let tempDir = os.tmpdir(); + let configPath = path.join(tempDir, '.sparkmagic', 'config.json'); + const expectedResult = { + 'kernel_python_credentials': { + 'url': 'http://localhost:8088' + }, + 'kernel_scala_credentials': { + 'url': 'http://localhost:8088' + }, + 'kernel_r_credentials': { + 'url': 'http://localhost:8088' + }, + 'livy_session_startup_timeout_seconds': 100, + 'logging_config': { + 'version': 1, + 'formatters': { + 'magicsFormatter': { + 'format': '%(asctime)s\t%(levelname)s\t%(message)s', + 'datefmt': '' + } + }, + 'handlers': { + 'magicsHandler': { + 'class': 'hdijupyterutils.filehandler.MagicsFileHandler', + 'formatter': 'magicsFormatter', + 'home_path': '' + } + }, + 'loggers': { + 'magicsLogger': { + 'handlers': ['magicsHandler'], + 'level': 'DEBUG', + 'propagate': 0 + } + } + }, + 'ignore_ssl_errors': true, + }; + expectedResult.logging_config.handlers.magicsHandler.home_path = path.join(tempDir, '.sparkmagic'); + sinon.stub(utils, 'getUserHome').returns(tempDir); + await session.configureKernel(); + let result = await fs.promises.readFile(configPath, 'utf-8'); + should(JSON.parse(result) === expectedResult); + }); + + it('should configure connection correctly', async function (): Promise { + let connectionProfile: IConnectionProfile = { + authenticationType: '', + connectionName: '', + databaseName: '', + id: 'id', + providerName: 'MSSQL', + options: { + authenticationType: 'SqlLogin', + }, + password: '', + savePassword: false, + saveProfile: false, + serverName: '', + userName: '' + }; + let futureMock = TypeMoq.Mock.ofType(FutureStub); + let kernelMock = TypeMoq.Mock.ofType(KernelStub); + kernelMock.setup(k => k.name).returns(() => 'spark'); + kernelMock.setup(m => m.requestExecute(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => futureMock.object); + mockJupyterSession.setup(s => s.kernel).returns(() => kernelMock.object); + let credentials = { [ConnectionOptionSpecialType.password]: 'password' }; + sinon.stub(connection, 'getCredentials').returns(Promise.resolve(credentials)); + + // Should throw error if there is no connection to big data cluster + await should(session.configureConnection(connectionProfile)).be.rejectedWith('Spark kernels require a connection to a SQL Server Big Data Cluster master instance.'); + + // Set up connection info to big data cluster + const mockServerInfo: ServerInfo = { + serverMajorVersion: 0, + serverMinorVersion: 0, + serverReleaseVersion: 0, + engineEditionId: 0, + serverVersion: '', + serverLevel: '', + serverEdition: '', + isCloud: false, + azureVersion: 0, + osVersion: '', + options: {} + }; + const mockGatewayEndpoint: utils.IEndpoint = { + serviceName: 'gateway', + description: '', + endpoint: '', + protocol: '', + }; + const mockControllerEndpoint: utils.IEndpoint = { + serviceName: 'controller', + description: '', + endpoint: '', + protocol: '', + }; + const mockHostAndIp: utils.HostAndIp = { + host: 'host', + port: 'port' + }; + const mockClustercontroller = new TestClusterController(); + let mockBdcExtension: TypeMoq.IMock = TypeMoq.Mock.ofType(); + let mockExtension: TypeMoq.IMock> = TypeMoq.Mock.ofType>(); + mockBdcExtension.setup(m => m.getClusterController(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => mockClustercontroller); + mockBdcExtension.setup((m: any) => m.then).returns(() => mockBdcExtension); + mockExtension.setup(m => m.activate()).returns(() => Promise.resolve(mockBdcExtension.object)); + mockExtension.setup((m: any) => m.then).returns(() => mockExtension); + sinon.stub(vscode.extensions, 'getExtension').returns(mockExtension.object); + sinon.stub(connection, 'getServerInfo').returns(Promise.resolve(mockServerInfo)); + sinon.stub(utils, 'getClusterEndpoints').returns([mockGatewayEndpoint, mockControllerEndpoint]); + sinon.stub(utils, 'getHostAndPortFromEndpoint').returns(mockHostAndIp); + + await session.configureConnection(connectionProfile); + should(connectionProfile.options['host']).equal('host'); + should(connectionProfile.options['knoxport']).equal('port'); + should(connectionProfile.options['user']).equal('knoxUsername'); + }); });