From f18e95a5a84201d24444407b2ede2158675eb0d2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 10 Oct 2024 13:57:33 +0200 Subject: [PATCH] test(transport): high-traffic RPC Problem: In https://github.com/vscode-neovim/vscode-neovim/issues/2184#issuecomment-2369880327 it was reported that "Github Copilot Chat opens MANY buffers while writing code, and that somehow breaks the vscode-neovim extension". Solution: - Add test coverage for high amounts of RPC traffic. - TODO: this doesn't cover complex scenarios such as a looping `OptionSet` handler. --- packages/neovim/src/api/Base.ts | 1 + packages/neovim/src/api/client.ts | 3 +++ packages/neovim/src/attach/attach.test.ts | 26 ++++++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/neovim/src/api/Base.ts b/packages/neovim/src/api/Base.ts index 4f29c631..b88eaf29 100644 --- a/packages/neovim/src/api/Base.ts +++ b/packages/neovim/src/api/Base.ts @@ -118,6 +118,7 @@ export class BaseApi extends EventEmitter { }); } + /** Sends a request to Nvim (the peer). */ request(name: string, args: any[] = []): Promise { return this.asyncRequest(name, args); } diff --git a/packages/neovim/src/api/client.ts b/packages/neovim/src/api/client.ts index 672dff9e..15a9acb5 100644 --- a/packages/neovim/src/api/client.ts +++ b/packages/neovim/src/api/client.ts @@ -63,6 +63,7 @@ export class NeovimClient extends Neovim { return this.attachedBuffers.has(key); } + /** Handles incoming request (from the peer). */ handleRequest( method: string, args: VimValue[], @@ -85,6 +86,7 @@ export class NeovimClient extends Neovim { } } + /** Publishes to (local) subscribers of this `EventEmitter`. */ emitNotification(method: string, args: any[]) { if (method.endsWith('_event')) { if (!method.startsWith('nvim_buf_')) { @@ -114,6 +116,7 @@ export class NeovimClient extends Neovim { } } + /** Handles incoming notification (from the peer). */ handleNotification(method: string, args: VimValue[], ...restArgs: any[]) { this.logger.info('handleNotification: %s', method); // If neovim API is not generated yet then queue up requests diff --git a/packages/neovim/src/attach/attach.test.ts b/packages/neovim/src/attach/attach.test.ts index 5fa3ae13..8f01d5ee 100644 --- a/packages/neovim/src/attach/attach.test.ts +++ b/packages/neovim/src/attach/attach.test.ts @@ -7,16 +7,21 @@ import { NeovimClient } from '../api/client'; describe('Nvim API', () => { let proc: ReturnType[0]; let nvim: ReturnType[1]; + /** Incoming requests (from Nvim). */ let requests: { method: string; args: number[] }[]; + /** Incoming notifications (from Nvim). */ let notifications: { method: string; args: number[] }[]; beforeAll(async () => { [proc, nvim] = testUtil.startNvim(); + // Incoming requests (from Nvim). nvim.on('request', (method, args, resp) => { requests.push({ method, args }); resp.send(`received ${method}(${args})`); }); + + // Incoming notifications (from Nvim). nvim.on('notification', (method, args) => { notifications.push({ method, args }); }); @@ -95,6 +100,25 @@ describe('Nvim API', () => { testUtil.stopNvim(nvim2); }); + it('very high traffic RPC', async () => { + let request_count = 0; + const old_request = nvim.request; + nvim.request = function (this: any, name: string, args: any[] = []): Promise { + request_count += 1; + return old_request.call(this, name, args); + }; + + for (let i = 0; i < 999; i++) { + nvim.command('edit test-node-client.lua') + nvim.command('bwipeout!') + } + + expect(request_count).toEqual(999 * 2); + + // Still alive? + expect(await nvim.eval('1+1')).toEqual(2); + }); + it('can send requests and receive response', async () => { const result = await nvim.eval('{"k1": "v1", "k2": 2}'); expect(result).toEqual({ k1: 'v1', k2: 2 }); @@ -143,7 +167,7 @@ describe('Nvim API', () => { end: -1, strictIndexing: true, }); - expect(lines).toEqual([]); + expect(lines).toEqual(['']); buf.setLines(['line1', 'line2'], { start: 0, end: 1 }); const newLines = await buf.getLines({