Skip to content

Commit fb0e690

Browse files
authored
chore(cli): updates to telemetry sink classes (#696)
Follow up to #585 --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 90579c3 commit fb0e690

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

packages/aws-cdk/lib/cli/telemetry/endpoint-sink.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { IncomingMessage } from 'http';
22
import type { Agent } from 'https';
33
import { request } from 'https';
4-
import type { UrlWithStringQuery } from 'url';
4+
import { parse, type UrlWithStringQuery } from 'url';
55
import { ToolkitError } from '@aws-cdk/toolkit-lib';
66
import { IoHelper } from '../../api-private';
77
import type { IIoHost } from '../io-host';
@@ -17,7 +17,7 @@ export interface EndpointTelemetrySinkProps {
1717
/**
1818
* The external endpoint to hit
1919
*/
20-
readonly endpoint: UrlWithStringQuery;
20+
readonly endpoint: string;
2121

2222
/**
2323
* Where messages are going to be sent
@@ -44,7 +44,7 @@ export class EndpointTelemetrySink implements ITelemetrySink {
4444
private agent?: Agent;
4545

4646
public constructor(props: EndpointTelemetrySinkProps) {
47-
this.endpoint = props.endpoint;
47+
this.endpoint = parse(props.endpoint);
4848
this.ioHelper = IoHelper.fromActionAwareIoHost(props.ioHost);
4949
this.agent = props.agent;
5050

@@ -70,7 +70,7 @@ export class EndpointTelemetrySink implements ITelemetrySink {
7070
return;
7171
}
7272

73-
const res = await this.https(this.endpoint, this.events);
73+
const res = await this.https(this.endpoint, { events: this.events });
7474

7575
// Clear the events array after successful output
7676
if (res) {
@@ -87,7 +87,7 @@ export class EndpointTelemetrySink implements ITelemetrySink {
8787
*/
8888
private async https(
8989
url: UrlWithStringQuery,
90-
body: TelemetrySchema[],
90+
body: { events: TelemetrySchema[] },
9191
): Promise<boolean> {
9292
try {
9393
const res = await doRequest(url, body, this.agent);
@@ -112,7 +112,7 @@ export class EndpointTelemetrySink implements ITelemetrySink {
112112
*/
113113
function doRequest(
114114
url: UrlWithStringQuery,
115-
data: TelemetrySchema[],
115+
data: { events: TelemetrySchema[] },
116116
agent?: Agent,
117117
) {
118118
return new Promise<IncomingMessage>((ok, ko) => {

packages/aws-cdk/test/cli/telemetry/endpoint-sink.test.ts

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as https from 'https';
2-
import { parse } from 'url';
32
import { IoHelper } from '../../../lib/api-private';
43
import { CliIoHost } from '../../../lib/cli/io-host';
54
import { EndpointTelemetrySink } from '../../../lib/cli/telemetry/endpoint-sink';
@@ -88,16 +87,15 @@ describe('EndpointTelemetrySink', () => {
8887
test('makes a POST request to the specified endpoint', async () => {
8988
// GIVEN
9089
const mockRequest = setupMockRequest();
91-
const endpoint = parse('https://example.com/telemetry');
9290
const testEvent = createTestEvent('test', { foo: 'bar' });
93-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
91+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
9492

9593
// WHEN
9694
await client.emit(testEvent);
9795
await client.flush();
9896

9997
// THEN
100-
const expectedPayload = JSON.stringify([testEvent]);
98+
const expectedPayload = JSON.stringify({ events: [testEvent] });
10199
expect(https.request).toHaveBeenCalledWith({
102100
hostname: 'example.com',
103101
port: null,
@@ -117,9 +115,8 @@ describe('EndpointTelemetrySink', () => {
117115
test('silently catches request errors', async () => {
118116
// GIVEN
119117
const mockRequest = setupMockRequest();
120-
const endpoint = parse('https://example.com/telemetry');
121118
const testEvent = createTestEvent('test');
122-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
119+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
123120

124121
mockRequest.on.mockImplementation((event, callback) => {
125122
if (event === 'error') {
@@ -137,18 +134,17 @@ describe('EndpointTelemetrySink', () => {
137134
test('multiple events sent as one', async () => {
138135
// GIVEN
139136
const mockRequest = setupMockRequest();
140-
const endpoint = parse('https://example.com/telemetry');
141137
const testEvent1 = createTestEvent('test1', { foo: 'bar' });
142138
const testEvent2 = createTestEvent('test2', { foo: 'bazoo' });
143-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
139+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
144140

145141
// WHEN
146142
await client.emit(testEvent1);
147143
await client.emit(testEvent2);
148144
await client.flush();
149145

150146
// THEN
151-
const expectedPayload = JSON.stringify([testEvent1, testEvent2]);
147+
const expectedPayload = JSON.stringify({ events: [testEvent1, testEvent2] });
152148
expect(https.request).toHaveBeenCalledTimes(1);
153149
expect(https.request).toHaveBeenCalledWith({
154150
hostname: 'example.com',
@@ -169,10 +165,9 @@ describe('EndpointTelemetrySink', () => {
169165
test('successful flush clears events cache', async () => {
170166
// GIVEN
171167
setupMockRequest();
172-
const endpoint = parse('https://example.com/telemetry');
173168
const testEvent1 = createTestEvent('test1', { foo: 'bar' });
174169
const testEvent2 = createTestEvent('test2', { foo: 'bazoo' });
175-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
170+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
176171

177172
// WHEN
178173
await client.emit(testEvent1);
@@ -181,7 +176,7 @@ describe('EndpointTelemetrySink', () => {
181176
await client.flush();
182177

183178
// THEN
184-
const expectedPayload1 = JSON.stringify([testEvent1]);
179+
const expectedPayload1 = JSON.stringify({ events: [testEvent1] });
185180
expect(https.request).toHaveBeenCalledTimes(2);
186181
expect(https.request).toHaveBeenCalledWith({
187182
hostname: 'example.com',
@@ -196,7 +191,7 @@ describe('EndpointTelemetrySink', () => {
196191
timeout: 500,
197192
}, expect.anything());
198193

199-
const expectedPayload2 = JSON.stringify([testEvent2]);
194+
const expectedPayload2 = JSON.stringify({ events: [testEvent2] });
200195
expect(https.request).toHaveBeenCalledWith({
201196
hostname: 'example.com',
202197
port: null,
@@ -238,10 +233,9 @@ describe('EndpointTelemetrySink', () => {
238233
return mockRequest;
239234
});
240235

241-
const endpoint = parse('https://example.com/telemetry');
242236
const testEvent1 = createTestEvent('test1', { foo: 'bar' });
243237
const testEvent2 = createTestEvent('test2', { foo: 'bazoo' });
244-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
238+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
245239

246240
// WHEN
247241
await client.emit(testEvent1);
@@ -255,7 +249,7 @@ describe('EndpointTelemetrySink', () => {
255249
await client.flush();
256250

257251
// THEN
258-
const expectedPayload1 = JSON.stringify([testEvent1]);
252+
const expectedPayload1 = JSON.stringify({ events: [testEvent1] });
259253
expect(https.request).toHaveBeenCalledTimes(2);
260254
expect(https.request).toHaveBeenCalledWith({
261255
hostname: 'example.com',
@@ -270,15 +264,15 @@ describe('EndpointTelemetrySink', () => {
270264
timeout: 500,
271265
}, expect.anything());
272266

273-
const expectedPayload2 = JSON.stringify([testEvent2]);
267+
const expectedPayload2 = JSON.stringify({ events: [testEvent1, testEvent2] });
274268
expect(https.request).toHaveBeenCalledWith({
275269
hostname: 'example.com',
276270
port: null,
277271
path: '/telemetry',
278272
method: 'POST',
279273
headers: {
280274
'content-type': 'application/json',
281-
'content-length': expectedPayload1.length + expectedPayload2.length - 1,
275+
'content-length': expectedPayload2.length,
282276
},
283277
agent: undefined,
284278
timeout: 500,
@@ -289,13 +283,12 @@ describe('EndpointTelemetrySink', () => {
289283
// GIVEN
290284
jest.useFakeTimers();
291285
setupMockRequest(); // Setup the mock request but we don't need the return value
292-
const endpoint = parse('https://example.com/telemetry');
293286

294287
// Create a spy on setInterval
295288
const setIntervalSpy = jest.spyOn(global, 'setInterval');
296289

297290
// Create the client
298-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
291+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
299292

300293
// Create a spy on the flush method
301294
const flushSpy = jest.spyOn(client, 'flush');
@@ -337,8 +330,7 @@ describe('EndpointTelemetrySink', () => {
337330
// Mock IoHelper.fromActionAwareIoHost to return our mock
338331
jest.spyOn(IoHelper, 'fromActionAwareIoHost').mockReturnValue(mockIoHelper as any);
339332

340-
const endpoint = parse('https://example.com/telemetry');
341-
const client = new EndpointTelemetrySink({ endpoint, ioHost });
333+
const client = new EndpointTelemetrySink({ endpoint: 'https://example.com/telemetry', ioHost });
342334

343335
// Mock https.request to throw an error
344336
(https.request as jest.Mock).mockImplementation(() => {

packages/aws-cdk/test/cli/telemetry/file-sink.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ describe('FileTelemetrySink', () => {
123123
expect(fileContent).toBe(expectedSingleEvent + expectedSingleEvent);
124124
});
125125

126+
test('constructor throws if file already exists', async () => {
127+
// GIVEN
128+
fs.writeFileSync(logFilePath, 'exists');
129+
130+
// WHEN & THEN
131+
expect(() => new FileTelemetrySink({ logFilePath, ioHost })).toThrow(/Telemetry file already exists/);
132+
});
133+
126134
test('handles errors gracefully and logs to trace without throwing', async () => {
127135
// GIVEN
128136
const testEvent: TelemetrySchema = {

0 commit comments

Comments
 (0)