Skip to content

Commit 5003528

Browse files
committed
Improved getVersion + tests
1 parent 0afb2ad commit 5003528

2 files changed

Lines changed: 74 additions & 15 deletions

File tree

src/json-rpc/csolution-rpc-client.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as manifest from '../manifest';
99
import { ChildProcess, spawn } from 'node:child_process';
1010
import { MessageConnection } from 'vscode-jsonrpc';
1111
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from 'vscode-jsonrpc/node';
12-
import { RpcMethods, RpcInterface } from './interface/rpc-interface';
12+
import { RpcMethods, RpcInterface, GetVersionResult } from './interface/rpc-interface';
1313
import { constructor } from '../generic/constructor';
1414
import { Optional } from '../generic/type-helper';
1515
import { debounce } from 'lodash';
@@ -43,7 +43,7 @@ class CsolutionServiceImpl extends RpcMethods implements CsolutionService {
4343
private readonly debouncedLoadPacks = debounce(super.loadPacks.bind(this), 1000);
4444
private csolutionBin = 'csolution';
4545
private exitPromise: Promise<void> | undefined;
46-
private hasReportedVersionForSession = false;
46+
private cachedVersion: GetVersionResult = { success: false };
4747
private readonly mutex: Mutex;
4848

4949
constructor(
@@ -72,22 +72,21 @@ class CsolutionServiceImpl extends RpcMethods implements CsolutionService {
7272
return (response ?? {}) as TResponse;
7373
}
7474

75+
public async getVersion(): Promise<GetVersionResult> {
76+
if (!this.cachedVersion.success) {
77+
// Query daemon version once per launched session
78+
this.cachedVersion = await super.getVersion();
79+
console.log('csolution version:', this.cachedVersion);
80+
}
81+
return this.cachedVersion;
82+
}
83+
7584
public async loadPacks() {
7685
if (this.idxWatcher === undefined) {
7786
this.watchPackIdxFile();
7887
}
79-
80-
// Query daemon version once per launched session right before first LoadPacks.
81-
if (!this.hasReportedVersionForSession) {
82-
try {
83-
const version = await super.getVersion();
84-
console.log('csolution version:', version);
85-
} catch (error) {
86-
console.warn('Unable to query csolution version before loadPacks:', error);
87-
} finally {
88-
this.hasReportedVersionForSession = true;
89-
}
90-
}
88+
// ensure version is cached
89+
await this.getVersion();
9190

9291
return super.loadPacks();
9392
}
@@ -145,7 +144,7 @@ class CsolutionServiceImpl extends RpcMethods implements CsolutionService {
145144
this.idxWatcher = undefined;
146145
this.connection?.dispose();
147146
this.connection = undefined;
148-
this.hasReportedVersionForSession = false;
147+
this.cachedVersion = { success: false };
149148
}
150149

151150
private async launch(): Promise<boolean> {

src/json-rpc/csolution-rpc-helper.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,66 @@ describe('csolution-rpc-client', () => {
207207
});
208208
});
209209

210+
describe('csolution-rpc-client getVersion cache', () => {
211+
let service: AnyService;
212+
213+
beforeEach(() => {
214+
service = createService();
215+
service.cachedVersion = { success: false };
216+
});
217+
218+
it('caches version after first request and reuses it', async () => {
219+
const transceiveSpy = jest.spyOn(service as any, 'transceive')
220+
.mockResolvedValue({ success: true, version: '1.2.3', apiVersion: '0.0.9' });
221+
222+
const first = await service.getVersion();
223+
const second = await service.getVersion();
224+
225+
expect(first).toEqual({ success: true, version: '1.2.3', apiVersion: '0.0.9' });
226+
expect(second).toEqual({ success: true, version: '1.2.3', apiVersion: '0.0.9' });
227+
expect(transceiveSpy).toHaveBeenCalledTimes(1);
228+
expect(transceiveSpy).toHaveBeenCalledWith('GetVersion', undefined);
229+
});
230+
231+
it('resets cached version on terminate and fetches again on next getVersion', async () => {
232+
const transceiveSpy = jest.spyOn(service as any, 'transceive')
233+
.mockResolvedValue({ success: true, version: '1.2.3', apiVersion: '0.0.9' });
234+
235+
await service.getVersion();
236+
expect(transceiveSpy).toHaveBeenCalledTimes(1);
237+
238+
// Simulate daemon termination lifecycle.
239+
service.onTerminate();
240+
expect(service.cachedVersion).toEqual({ success: false });
241+
242+
await service.getVersion();
243+
expect(transceiveSpy).toHaveBeenCalledTimes(2);
244+
});
245+
246+
it('primes version cache in loadPacks before LoadPacks RPC', async () => {
247+
service.idxWatcher = { close: jest.fn() };
248+
const sequence: string[] = [];
249+
250+
const transceiveSpy = jest.spyOn(service as any, 'transceive').mockImplementation(async (...args: unknown[]) => {
251+
const method = String(args[0]);
252+
sequence.push(method);
253+
if (method === 'GetVersion') {
254+
return { success: true, version: '1.2.3', apiVersion: '0.0.9' };
255+
}
256+
if (method === 'LoadPacks') {
257+
return { success: true };
258+
}
259+
return { success: false };
260+
});
261+
262+
await service.loadPacks();
263+
264+
expect(transceiveSpy).toHaveBeenCalledWith('GetVersion', undefined);
265+
expect(transceiveSpy).toHaveBeenCalledWith('LoadPacks', undefined);
266+
expect(sequence.indexOf('GetVersion')).toBeLessThan(sequence.indexOf('LoadPacks'));
267+
});
268+
});
269+
210270

211271
describe('csolution-rpc-client watchPackIdxFile', () => {
212272
let service: AnyService;

0 commit comments

Comments
 (0)