Skip to content

Commit 13182aa

Browse files
committed
added some unit test
1 parent 7aa08bb commit 13182aa

File tree

5 files changed

+277
-7
lines changed

5 files changed

+277
-7
lines changed

vscode/src/telemetry/impl/telemetryEventQueue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export class TelemetryEventQueue {
3737
return queue;
3838
}
3939

40-
public decreaseSizeOnMaxOverflow = (maxNumberOfEventsToBeKept: number) => {
41-
const excess = this.size() - maxNumberOfEventsToBeKept;
40+
public adjustQueueSize = (maxNumOfEventsToRetain: number) => {
41+
const excess = this.size() - maxNumOfEventsToRetain;
4242

4343
if (excess > 0) {
4444
LOGGER.debug('Decreasing size of the queue as max capacity reached');

vscode/src/telemetry/impl/telemetryReporterImpl.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ export class TelemetryReporterImpl implements TelemetryReporter {
6363
this.queue.enqueue(event);
6464
if (this.retryManager.isQueueOverflow(this.queue.size())) {
6565
LOGGER.debug(`Send triggered to queue size overflow`);
66-
const numOfeventsToBeDropped = this.retryManager.getNumberOfEventsToBeDropped();
66+
const numOfEventsToBeRetained = this.retryManager.getNumberOfEventsToBeRetained();
6767
this.sendEvents();
68-
if (numOfeventsToBeDropped) {
69-
this.queue.decreaseSizeOnMaxOverflow(numOfeventsToBeDropped);
68+
if (numOfEventsToBeRetained !== -1) {
69+
this.queue.adjustQueueSize(numOfEventsToBeRetained);
7070
}
7171
}
7272
}

vscode/src/telemetry/impl/telemetryRetry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ export class TelemetryRetry {
9191
LOGGER.debug("Keeping queue capacity same as max capacity reached");
9292
}
9393

94-
public getNumberOfEventsToBeDropped = (): number =>
94+
public getNumberOfEventsToBeRetained = (): number =>
9595
this.numOfAttemptsWhenQueueIsFull >= this.TELEMETRY_RETRY_CONFIG.maxRetries ?
96-
this.queueCapacity/2 : 0;
96+
this.queueCapacity/2 : -1;
9797

9898
private resetQueueCapacity = (): void => {
9999
LOGGER.debug("Resetting queue capacity to default");
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Copyright (c) 2025, Oracle and/or its affiliates.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { expect } from "chai";
18+
import * as sinon from "sinon";
19+
import { globalState } from "../../../globalState";
20+
import { LOGGER } from "../../../logger";
21+
import { describe, it, beforeEach, afterEach } from "mocha";
22+
import { cacheService } from "../../../telemetry/impl/cacheServiceImpl";
23+
24+
describe("CacheServiceImpl", () => {
25+
let getStub: sinon.SinonStub;
26+
let updateStub: sinon.SinonStub;
27+
let loggerErrorStub: sinon.SinonStub;
28+
let loggerDebugStub: sinon.SinonStub;
29+
30+
const fakeState = {
31+
get: (key: string) => `value-${key}`,
32+
update: async (key: string, value: string) => {},
33+
};
34+
35+
beforeEach(() => {
36+
getStub = sinon.stub(fakeState, "get").callThrough();
37+
updateStub = sinon.stub(fakeState, "update").resolves();
38+
39+
sinon.stub(globalState, "getExtensionContextInfo").returns({
40+
getVscGlobalState: () => fakeState,
41+
} as any);
42+
43+
loggerErrorStub = sinon.stub(LOGGER, "error");
44+
loggerDebugStub = sinon.stub(LOGGER, "debug");
45+
});
46+
47+
afterEach(() => {
48+
sinon.restore();
49+
});
50+
51+
describe("get", () => {
52+
it("should return the cached value for a key", () => {
53+
const key = "example";
54+
const value = cacheService.get(key);
55+
expect(value).to.equal(`value-${key}`);
56+
expect(getStub.calledOnceWith(key)).to.be.true;
57+
});
58+
59+
it("should log and return undefined on error", () => {
60+
getStub.throws(new Error("key not found error"));
61+
62+
const result = cacheService.get("notPresent");
63+
expect(result).to.be.undefined;
64+
expect(loggerErrorStub.calledOnce).to.be.true;
65+
});
66+
});
67+
68+
describe("put", () => {
69+
it("should store the value and return true", async () => {
70+
const key = "example";
71+
const value = "example-value"
72+
const result = await cacheService.put(key, value);
73+
expect(result).to.be.true;
74+
expect(updateStub.calledOnceWith(key, value)).to.be.true;
75+
expect(loggerDebugStub.calledOnce).to.be.true;
76+
});
77+
78+
it("should log and return false on error", async () => {
79+
updateStub.rejects(new Error("Error while storing key"));
80+
81+
const result = await cacheService.put("badKey", "value");
82+
expect(result).to.be.false;
83+
expect(loggerErrorStub.calledOnce).to.be.true;
84+
});
85+
});
86+
});
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
Copyright (c) 2025, Oracle and/or its affiliates.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { expect } from 'chai';
18+
import * as sinon from 'sinon';
19+
import { TelemetryEventQueue } from '../../../telemetry/impl/telemetryEventQueue';
20+
import { BaseEvent } from '../../../telemetry/events/baseEvent';
21+
import { LOGGER } from '../../../logger';
22+
import { describe, it, beforeEach, afterEach } from 'mocha';
23+
24+
describe('TelemetryEventQueue', () => {
25+
let queue: TelemetryEventQueue;
26+
let loggerStub: sinon.SinonStub;
27+
28+
class MockEvent extends BaseEvent<any> {
29+
public static readonly NAME = "mock";
30+
public static readonly ENDPOINT = "/mock";
31+
32+
33+
constructor(name?: string, data?: any) {
34+
super(name || MockEvent.NAME, MockEvent.ENDPOINT, data || {});
35+
}
36+
}
37+
38+
beforeEach(() => {
39+
queue = new TelemetryEventQueue();
40+
41+
loggerStub = sinon.stub(LOGGER, 'debug');
42+
});
43+
44+
afterEach(() => {
45+
sinon.restore();
46+
});
47+
48+
describe('enqueue', () => {
49+
it('should add an event to the queue', () => {
50+
const event = new MockEvent();
51+
queue.enqueue(event);
52+
expect(queue.size()).to.equal(1);
53+
});
54+
55+
it('should add multiple events in order', () => {
56+
const event1 = new MockEvent('event1');
57+
const event2 = new MockEvent('event2');
58+
59+
queue.enqueue(event1);
60+
queue.enqueue(event2);
61+
62+
const firstEvent = queue.dequeue();
63+
expect(firstEvent).to.equal(event1);
64+
expect(queue.size()).to.equal(1);
65+
});
66+
});
67+
68+
describe('dequeue', () => {
69+
it('should remove and return the first event from the queue', () => {
70+
const event = new MockEvent();
71+
queue.enqueue(event);
72+
73+
const dequeuedEvent = queue.dequeue();
74+
expect(dequeuedEvent).to.equal(event);
75+
expect(queue.size()).to.equal(0);
76+
});
77+
78+
it('should return undefined if queue is empty', () => {
79+
const dequeuedEvent = queue.dequeue();
80+
expect(dequeuedEvent).to.be.undefined;
81+
});
82+
});
83+
84+
describe('concatQueue', () => {
85+
it('should append events to the end of the queue by default', () => {
86+
const event1 = new MockEvent('event1');
87+
const event2 = new MockEvent('event2');
88+
const event3 = new MockEvent('event3');
89+
90+
queue.enqueue(event1);
91+
queue.concatQueue([event2, event3]);
92+
93+
expect(queue.size()).to.equal(3);
94+
expect(queue.dequeue()).to.equal(event1);
95+
expect(queue.dequeue()).to.equal(event2);
96+
expect(queue.dequeue()).to.equal(event3);
97+
});
98+
99+
it('should prepend events to the start of the queue when mergeAtStarting is true', () => {
100+
const event1 = new MockEvent('event1');
101+
const event2 = new MockEvent('event2');
102+
const event3 = new MockEvent('event3');
103+
104+
queue.enqueue(event1);
105+
queue.concatQueue([event2, event3], true);
106+
107+
expect(queue.size()).to.equal(3);
108+
expect(queue.dequeue()).to.equal(event2);
109+
expect(queue.dequeue()).to.equal(event3);
110+
expect(queue.dequeue()).to.equal(event1);
111+
});
112+
});
113+
114+
describe('size', () => {
115+
it('should return the number of events in the queue', () => {
116+
expect(queue.size()).to.equal(0);
117+
118+
queue.enqueue(new MockEvent('event1'));
119+
expect(queue.size()).to.equal(1);
120+
121+
queue.enqueue(new MockEvent('event2'));
122+
expect(queue.size()).to.equal(2);
123+
124+
queue.dequeue();
125+
expect(queue.size()).to.equal(1);
126+
});
127+
});
128+
129+
describe('flush', () => {
130+
it('should return all events and empty the queue', () => {
131+
const event1 = new MockEvent('event1');
132+
const event2 = new MockEvent('event2');
133+
134+
queue.enqueue(event1);
135+
queue.enqueue(event2);
136+
137+
const flushedEvents = queue.flush();
138+
139+
expect(flushedEvents).to.deep.equal([event1, event2]);
140+
expect(queue.size()).to.equal(0);
141+
});
142+
});
143+
144+
describe('decreaseSizeOnMaxOverflow', () => {
145+
it('should do nothing if queue size is below the max', () => {
146+
const event1 = new MockEvent('event1');
147+
const event2 = new MockEvent('event2');
148+
149+
queue.enqueue(event1);
150+
queue.enqueue(event2);
151+
152+
queue.adjustQueueSize(5);
153+
154+
expect(queue.size()).to.equal(2);
155+
expect(loggerStub.called).to.be.false;
156+
});
157+
158+
it('should log and deduplicate events when queue exceeds max size', () => {
159+
const event1 = new MockEvent('event1');
160+
const event2 = new MockEvent('event2');
161+
const event3 = new MockEvent('event1');
162+
const event4 = new MockEvent('event3');
163+
const event5 = new MockEvent('event4');
164+
const event6 = new MockEvent('event5');
165+
166+
queue.enqueue(event1);
167+
queue.enqueue(event2);
168+
queue.enqueue(event3);
169+
queue.enqueue(event4);
170+
queue.enqueue(event5);
171+
queue.enqueue(event6);
172+
173+
queue.adjustQueueSize(3);
174+
175+
expect(queue.size()).to.equal(5);
176+
expect(loggerStub.calledOnce).to.be.true;
177+
178+
const remainingEvents = queue.flush();
179+
const eventNames = remainingEvents.map(e => e.NAME);
180+
expect(eventNames).to.deep.equal(['event1', 'event2', 'event3', 'event4', 'event5']);
181+
});
182+
});
183+
184+
});

0 commit comments

Comments
 (0)