From 409794e08592bba69541bd8c825ac1ca6ef7c420 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Thu, 24 Jan 2019 10:39:26 -0800 Subject: [PATCH] Register test services after starting LS --- .../languageServer/languageServer.ts | 17 ++++++++++-- .../languageServer.unit.test.ts | 26 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/client/activation/languageServer/languageServer.ts b/src/client/activation/languageServer/languageServer.ts index 3e2aa86cac73..56d7144431a4 100644 --- a/src/client/activation/languageServer/languageServer.ts +++ b/src/client/activation/languageServer/languageServer.ts @@ -9,9 +9,12 @@ import '../../common/extensions'; import { traceDecorators, traceError } from '../../common/logger'; import { Resource } from '../../common/types'; import { createDeferred, Deferred, sleep } from '../../common/utils/async'; +import { swallowExceptions } from '../../common/utils/decorators'; import { noop } from '../../common/utils/misc'; +import { LanguageServerSymbolProvider } from '../../providers/symbolProvider'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; +import { IUnitTestManagementService } from '../../unittests/types'; import { ILanguageClientFactory, ILanguageServer, LanguageClientFactory } from '../types'; import { ProgressReporting } from './progress'; @@ -26,7 +29,8 @@ export class LanguageServer implements ILanguageServer { constructor( @inject(ILanguageClientFactory) @named(LanguageClientFactory.base) - private readonly factory: ILanguageClientFactory + private readonly factory: ILanguageClientFactory, + @inject(IUnitTestManagementService) private readonly testManager: IUnitTestManagementService ) { this.startupCompleted = createDeferred(); } @@ -58,6 +62,7 @@ export class LanguageServer implements ILanguageServer { const eventName = telemetryEvent.EventName || EventName.PYTHON_LANGUAGE_SERVER_TELEMETRY; sendTelemetryEvent(eventName, telemetryEvent.Measurements, telemetryEvent.Properties); }); + await this.registerTestServices(); } @traceDecorators.error('Failed to load Language Server extension') public loadExtension(args?: {}) { @@ -74,10 +79,18 @@ export class LanguageServer implements ILanguageServer { .ignoreErrors(); } @captureTelemetry(EventName.PYTHON_LANGUAGE_SERVER_READY, undefined, true) - private async serverReady(): Promise { + protected async serverReady(): Promise { while (this.languageClient && !this.languageClient!.initializeResult) { await sleep(100); } this.startupCompleted.resolve(); } + @swallowExceptions('Activating Unit Tests Manager for Language Server') + protected async registerTestServices() { + if (!this.languageClient) { + throw new Error('languageClient not initialized'); + } + await this.testManager.activate(); + await this.testManager.activateCodeLenses(new LanguageServerSymbolProvider(this.languageClient!)); + } } diff --git a/src/test/activation/languageServer/languageServer.unit.test.ts b/src/test/activation/languageServer/languageServer.unit.test.ts index f5d35c2d7a61..9c4f2d4c11de 100644 --- a/src/test/activation/languageServer/languageServer.unit.test.ts +++ b/src/test/activation/languageServer/languageServer.unit.test.ts @@ -4,27 +4,37 @@ 'use strict'; import { expect } from 'chai'; -import { instance, mock, when } from 'ts-mockito'; +import { anything, instance, mock, verify, when } from 'ts-mockito'; import * as typemoq from 'typemoq'; import { Uri } from 'vscode'; import { LanguageClient, LanguageClientOptions } from 'vscode-languageclient'; import { BaseLanguageClientFactory } from '../../../client/activation/languageServer/languageClientFactory'; import { LanguageServer } from '../../../client/activation/languageServer/languageServer'; -import { ILanguageClientFactory, ILanguageServer } from '../../../client/activation/types'; +import { ILanguageClientFactory } from '../../../client/activation/types'; import '../../../client/common/extensions'; import { IDisposable } from '../../../client/common/types'; import { sleep } from '../../../client/common/utils/async'; +import { UnitTestManagementService } from '../../../client/unittests/main'; +import { IUnitTestManagementService } from '../../../client/unittests/types'; //tslint:disable:no-require-imports no-require-imports no-var-requires no-any no-unnecessary-class max-func-body-length suite('Language Server - LanguageServer', () => { + class LanguageServerTest extends LanguageServer{ + // tslint:disable-next-line:no-unnecessary-override + public async registerTestServices() { + return super.registerTestServices(); + } + } let clientFactory: ILanguageClientFactory; - let server: ILanguageServer; + let server: LanguageServerTest; let client: typemoq.IMock; + let testManager: IUnitTestManagementService; setup(() => { client = typemoq.Mock.ofType(); clientFactory = mock(BaseLanguageClientFactory); - server = new LanguageServer(instance(clientFactory)); + testManager = mock(UnitTestManagementService); + server = new LanguageServerTest(instance(clientFactory), instance(testManager)); }); teardown(() => { client.setup(c => c.stop()).returns(() => Promise.resolve()); @@ -77,6 +87,8 @@ suite('Language Server - LanguageServer', () => { .verifiable(typemoq.Times.once()); await sleep(120); + verify(testManager.activate()).once(); + verify(testManager.activateCodeLenses(anything())).once(); client.verify(c => c.sendRequest(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.atLeast(2)); }); test('Send telemetry when LS has started and disposes appropriately', async () => { @@ -117,6 +129,9 @@ suite('Language Server - LanguageServer', () => { .returns(() => true as any) .verifiable(typemoq.Times.once()); await sleep(120); + + verify(testManager.activate()).once(); + verify(testManager.activateCodeLenses(anything())).once(); expect(() => server.loadExtension(loadExtensionArgs)).to.not.throw(); client.verify(c => c.sendRequest(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.once()); client.verify(c => c.stop(), typemoq.Times.never()); @@ -127,4 +142,7 @@ suite('Language Server - LanguageServer', () => { client.verify(c => c.stop(), typemoq.Times.once()); startDisposable.verify(d => d.dispose(), typemoq.Times.once()); }); + test('Ensure Errors raised when starting test manager are not bubbled up', async () => { + await server.registerTestServices(); + }); });