Skip to content

Commit f9fed75

Browse files
committed
add more tests
1 parent f506b47 commit f9fed75

File tree

3 files changed

+66
-24
lines changed

3 files changed

+66
-24
lines changed

packages/core/src/shared/awsClientBuilderV3.ts

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
import { HttpResponse } from '@aws-sdk/protocol-http'
2121
import { telemetry } from './telemetry'
2222
import { getRequestId } from './errors'
23-
import { extensionVersion, getLogger } from '.'
23+
import { extensionVersion } from '.'
24+
import { getLogger } from './logger'
2425

2526
export type AwsClient = IClient<any, any, any>
2627
interface AwsConfigOptions {
@@ -87,22 +88,15 @@ export class DefaultAWSClientBuilderV3 implements AWSClientBuilderV3 {
8788
}
8889
}
8990

90-
function getServiceId(context: { clientName?: string; commandName?: string }) {
91-
return context.clientName?.toLowerCase().replace(/client$/, '')
91+
export function getServiceId(context: { clientName?: string; commandName?: string }): string {
92+
return context.clientName?.toLowerCase().replace(/client$/, '') ?? 'unknown-service'
9293
}
9394

94-
function isExcludedError(e: Error, ignoredErrors: (string | typeof Error)[]) {
95-
return (
96-
ignoredErrors?.find((x) => e.name === x) ||
97-
('code' in e && ignoredErrors?.find((x) => e.code === x)) ||
98-
ignoredErrors?.find((x) => typeof x !== 'string' && e instanceof x)
99-
)
100-
}
10195
/**
10296
* Record request IDs to the current context, potentially overriding the field if
10397
* multiple API calls are made in the same context. We only do failures as successes are generally uninteresting and noisy.
10498
*/
105-
function recordErrorTelemetry(err: Error, serviceName?: string) {
99+
export function recordErrorTelemetry(err: Error, serviceName?: string) {
106100
interface RequestData {
107101
requestId?: string
108102
requestServiceType?: string
@@ -114,7 +108,7 @@ function recordErrorTelemetry(err: Error, serviceName?: string) {
114108
} satisfies RequestData as any)
115109
}
116110

117-
function omitIfPresent<T extends Record<string, unknown>>(obj: T, keys: string[]): T {
111+
export function omitIfPresent<T extends Record<string, unknown>>(obj: T, keys: string[]): T {
118112
const objCopy = { ...obj }
119113
for (const key of keys) {
120114
if (key in objCopy) {
@@ -124,25 +118,32 @@ function omitIfPresent<T extends Record<string, unknown>>(obj: T, keys: string[]
124118
return objCopy
125119
}
126120

121+
function logAndThrow(e: any, serviceId: string, errorMessageAppend: string): never {
122+
if (e instanceof Error) {
123+
recordErrorTelemetry(e, serviceId)
124+
const err = { ...e }
125+
delete err['stack']
126+
getLogger().error('API Response %s: %O', errorMessageAppend, err)
127+
}
128+
throw e
129+
}
130+
/**
131+
* Telemetry logic to be added to all created clients. Adds logging and emitting metric on errors.
132+
*/
133+
127134
const telemetryMiddleware: DeserializeMiddleware<any, any> =
128135
(next: DeserializeHandler<any, any>, context: HandlerExecutionContext) => async (args: any) => {
129136
if (!HttpResponse.isInstance(args.request)) {
130137
return next(args)
131138
}
132-
139+
const serviceId = getServiceId(context as object)
133140
const { hostname, path } = args.request
134-
const result = await next(args).catch((e: any) => {
135-
if (e instanceof Error && !isExcludedError(e, [])) {
136-
recordErrorTelemetry(e, getServiceId(context as object))
137-
const err = { ...e }
138-
delete err['stack']
139-
getLogger().error('API Response (%s %s): %O', hostname, path, err)
140-
}
141-
throw e
142-
})
141+
const logTail = `(${hostname} ${path})`
142+
const result = await next(args).catch((e: any) => logAndThrow(e, serviceId, logTail))
143143
if (HttpResponse.isInstance(result.response)) {
144+
// TODO: omit credentials / sensitive info from the logs / telemetry.
144145
const output = omitIfPresent(result.output, [])
145-
getLogger().debug('API Response (%s %s): %O', hostname, path, output)
146+
getLogger().debug('API Response %s: %O', logTail, output)
146147
}
147148

148149
return result

packages/core/src/shared/clients/ec2Client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export class Ec2Client {
5353
public constructor(public readonly regionCode: string) {}
5454

5555
private async createSdkClient(): Promise<EC2Client> {
56+
console.log('Creating EC2 client')
5657
return await globals.sdkClientBuilderV3.createAwsService(EC2Client, undefined, this.regionCode)
5758
}
5859

packages/core/src/test/shared/defaultAwsClientBuilderV3.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@ import { getClientId } from '../../shared/telemetry/util'
99
import { FakeMemento } from '../fakeExtensionContext'
1010
import { FakeAwsContext } from '../utilities/fakeAwsContext'
1111
import { GlobalState } from '../../shared/globalState'
12-
import { AWSClientBuilderV3, DefaultAWSClientBuilderV3 } from '../../shared/awsClientBuilderV3'
12+
import {
13+
AWSClientBuilderV3,
14+
DefaultAWSClientBuilderV3,
15+
getServiceId,
16+
omitIfPresent,
17+
recordErrorTelemetry,
18+
} from '../../shared/awsClientBuilderV3'
1319
import { Client } from '@aws-sdk/smithy-client'
1420
import { extensionVersion } from '../../shared'
21+
import { assertTelemetry } from '../testUtil'
22+
import { telemetry } from '../../shared/telemetry'
1523

1624
describe('DefaultAwsClientBuilderV3', function () {
1725
let builder: AWSClientBuilderV3
@@ -56,3 +64,35 @@ describe('DefaultAwsClientBuilderV3', function () {
5664
})
5765
})
5866
})
67+
68+
describe('getServiceId', function () {
69+
it('returns the service ID', function () {
70+
assert.strictEqual(getServiceId({ clientName: 'ec2' }), 'ec2')
71+
assert.strictEqual(getServiceId({ clientName: 'ec2client' }), 'ec2')
72+
assert.strictEqual(getServiceId({ clientName: 's3client' }), 's3')
73+
})
74+
})
75+
76+
describe('recordErrorTelemetry', function () {
77+
it('includes requestServiceType in span', function () {
78+
const e = new Error('test error')
79+
telemetry.vscode_executeCommand.run((span) => {
80+
recordErrorTelemetry(e, 'aws-service')
81+
})
82+
assertTelemetry('vscode_executeCommand', { requestServiceType: 'aws-service' })
83+
})
84+
})
85+
86+
describe('omitIfPresent', function () {
87+
it('returns a new object with value replace by [omitted]', function () {
88+
const obj = { a: 1, b: 2 }
89+
const result = omitIfPresent(obj, ['a'])
90+
assert.deepStrictEqual(result, { a: '[omitted]', b: 2 })
91+
})
92+
93+
it('returns the original object if the key is not present', function () {
94+
const obj = { a: 1, b: 2 }
95+
const result = omitIfPresent(obj, ['c'])
96+
assert.deepStrictEqual(result, obj)
97+
})
98+
})

0 commit comments

Comments
 (0)