Skip to content

Commit 5199aaa

Browse files
committed
fix(test): telemetry settings errors
many settings errors like this in the test logs: Failed to read key "telemetry": TypeError: Failed to cast type "object" to convertLegacy: TypeError: Unknown telemetry setting: [object Object],[object Object]: Error: at TelemetryConfig.get (/Users/runner/work/aws-toolkit-vscode/aws-toolkit-vscode/src/shared/settings.ts:193:27)
1 parent 4950c77 commit 5199aaa

File tree

4 files changed

+41
-37
lines changed

4 files changed

+41
-37
lines changed

src/shared/settings.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -166,18 +166,26 @@ function createSettingsClass<T extends TypeDescriptor>(section: string, descript
166166
type Inner = FromDescriptor<T>
167167

168168
// Class names are not always stable, especially when bundling
169-
function makeLogger(name = 'Settings') {
169+
function makeLogger(name = 'Settings', loglevel: 'debug' | 'error') {
170170
const prefix = `${isNameMangled() ? 'Settings' : name} (${section})`
171-
return (message: string) => getLogger().debug(`${prefix}: ${message}`)
171+
return (message: string) =>
172+
loglevel === 'debug'
173+
? getLogger().debug(`${prefix}: ${message}`)
174+
: getLogger().error(`${prefix}: ${message}`)
172175
}
173176

174177
return class AnonymousSettings implements TypedSettings<Inner> {
175178
private readonly config = this.settings.getSection(section)
176179
private readonly disposables: vscode.Disposable[] = []
177180
// TODO(sijaden): add metadata prop to `Logger` so we don't need to make one-off log functions
178-
protected readonly log = makeLogger(Object.getPrototypeOf(this)?.constructor?.name)
181+
protected readonly log = makeLogger(Object.getPrototypeOf(this)?.constructor?.name, 'debug')
182+
protected readonly logErr = makeLogger(Object.getPrototypeOf(this)?.constructor?.name, 'error')
179183

180-
public constructor(private readonly settings: ClassToInterfaceType<Settings> = Settings.instance) {}
184+
public constructor(
185+
private readonly settings: ClassToInterfaceType<Settings> = Settings.instance,
186+
/** Throw an exception if the user config is invalid or the caller type doesn't match the stored type. */
187+
private readonly throwInvalid: boolean = isAutomation()
188+
) {}
181189

182190
public get onDidChange() {
183191
return this.getChangedEmitter().event
@@ -186,14 +194,11 @@ function createSettingsClass<T extends TypeDescriptor>(section: string, descript
186194
public get<K extends keyof Inner>(key: K & string, defaultValue?: Inner[K]) {
187195
try {
188196
return this.getOrThrow(key, defaultValue)
189-
} catch (error) {
190-
this.log(`failed to read key "${key}": ${error}`)
191-
192-
if (isAutomation() || defaultValue === undefined) {
193-
throw new Error(`Failed to read key "${key}": ${error}`)
197+
} catch (e) {
198+
if (this.throwInvalid || defaultValue === undefined) {
199+
throw new Error(`Failed to read key "${key}": ${e}`)
194200
}
195-
196-
this.log(`using default value for "${key}"`)
201+
this.logErr(`using default for key "${key}", read failed: ${(e as Error).message ?? '?'}`)
197202

198203
return defaultValue
199204
}
@@ -255,8 +260,13 @@ function createSettingsClass<T extends TypeDescriptor>(section: string, descript
255260

256261
for (const key of props.filter(isDifferent)) {
257262
this.log(`key "${key}" changed`)
258-
store[key] = this.get(key)
259-
emitter.fire({ key })
263+
try {
264+
store[key] = this.get(key)
265+
emitter.fire({ key })
266+
} catch {
267+
// getChangedEmitter() can't provide a default value so
268+
// we must silence errors here. Logging is done by this.get().
269+
}
260270
}
261271
})
262272

src/shared/telemetry/activation.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { fromExtensionManifest, openSettings, Settings } from '../settings'
1717

1818
const LEGACY_SETTINGS_TELEMETRY_VALUE_DISABLE = 'Disable'
1919
const LEGACY_SETTINGS_TELEMETRY_VALUE_ENABLE = 'Enable'
20-
const TELEMETRY_SETTING_DEFAULT = true
2120

2221
export const noticeResponseViewSettings = localize('AWS.telemetry.notificationViewSettings', 'Settings')
2322
export const noticeResponseOk = localize('AWS.telemetry.notificationOk', 'OK')
@@ -37,7 +36,13 @@ const CURRENT_TELEMETRY_NOTICE_VERSION = 2
3736
export async function activate(extensionContext: vscode.ExtensionContext, awsContext: AwsContext, settings: Settings) {
3837
globals.telemetry = new DefaultTelemetryService(extensionContext, awsContext, getComputeRegion())
3938

40-
const config = new TelemetryConfig(settings)
39+
const config = new TelemetryConfig(
40+
settings,
41+
// Disable `throwInvalid` because:
42+
// 1. Telemetry must never prevent normal Toolkit operation.
43+
// 2. For tests, bad data is intentional, so these errors add unwanted noise in the test logs.
44+
false
45+
)
4146
globals.telemetry.telemetryEnabled = config.isEnabled()
4247

4348
extensionContext.subscriptions.push(
@@ -50,7 +55,7 @@ export async function activate(extensionContext: vscode.ExtensionContext, awsCon
5055

5156
// Prompt user about telemetry if they haven't been
5257
if (!isCloud9() && !hasUserSeenTelemetryNotice(extensionContext)) {
53-
showTelemetryNotice(extensionContext, config)
58+
showTelemetryNotice(extensionContext)
5459
}
5560
}
5661

@@ -71,17 +76,7 @@ export function convertLegacy(value: unknown): boolean {
7176

7277
export class TelemetryConfig extends fromExtensionManifest('aws', { telemetry: convertLegacy }) {
7378
public isEnabled(): boolean {
74-
try {
75-
return this.get('telemetry', TELEMETRY_SETTING_DEFAULT)
76-
} catch (error) {
77-
vscode.window.showErrorMessage(
78-
localize(
79-
'AWS.message.error.settings.telemetry.invalid_type',
80-
'The aws.telemetry value must be a boolean'
81-
)
82-
)
83-
return TELEMETRY_SETTING_DEFAULT
84-
}
79+
return this.get('telemetry', true)
8580
}
8681
}
8782

@@ -101,7 +96,7 @@ export async function setHasUserSeenTelemetryNotice(extensionContext: vscode.Ext
10196
* Prompts user to Enable/Disable/Defer on Telemetry, then
10297
* handles the response appropriately.
10398
*/
104-
function showTelemetryNotice(extensionContext: vscode.ExtensionContext, config: TelemetryConfig) {
99+
function showTelemetryNotice(extensionContext: vscode.ExtensionContext) {
105100
getLogger().verbose('Showing telemetry notice')
106101

107102
const telemetryNoticeText: string = localize(

src/test/shared/settingsConfiguration.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import * as assert from 'assert'
77
import * as vscode from 'vscode'
8-
import * as env from '../../shared/vscode/env'
98
import { DevSettings, Experiments, fromExtensionManifest, PromptSettings, Settings } from '../../shared/settings'
109
import { TestSettings } from '../utilities/testSettingsConfiguration'
1110
import { ClassToInterfaceType } from '../../shared/utilities/tsUtils'
@@ -208,14 +207,9 @@ describe('DevSetting', function () {
208207
})
209208

210209
it('only throws in automation', async function () {
211-
const previousDesc = Object.getOwnPropertyDescriptor(env, 'isAutomation')
212-
assert.ok(previousDesc)
213-
210+
const noAutomation = new DevSettings(settings, false)
214211
await settings.update(`aws.dev.${TEST_SETTING}`, 'junk')
215-
Object.defineProperty(env, 'isAutomation', { value: () => false })
216-
assert.strictEqual(sut.get(TEST_SETTING, true), true)
217-
218-
Object.defineProperty(env, 'isAutomation', previousDesc)
212+
assert.strictEqual(noAutomation.get(TEST_SETTING, true), true)
219213
})
220214
})
221215

src/test/shared/telemetry/activation.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ describe('Telemetry on activation', function () {
7979
let sut: TelemetryConfig
8080

8181
beforeEach(function () {
82-
sut = new TelemetryConfig(settings)
82+
sut = new TelemetryConfig(
83+
settings,
84+
// Disable `throwInvalid`. These tests intentionally try invalid
85+
// data, so the errors are unwanted noise in the test logs.
86+
false
87+
)
8388
})
8489

8590
afterEach(async function () {

0 commit comments

Comments
 (0)