项目文件夹

文件
yulunz e14a74c859 chore: disallow underscores followed by numbers in metrics names (#2058)
Underscore followed by numbers is not encouraged in the proto style
guide. See "Underscores in Identifiers" in
https://protobuf.dev/programming-guides/style/.

This recently became an issue because we have `list_3p_developer_tools`
and `execute_3p_developer_tool` which would have been dis-allowed. This
change replaces them with `list3p_developer_tools` and
`execute3p_developer_tool` respectively, as suggested by the style
guide.

This only affects the logged version. The tool name is still the
existing one.

This transformation is also applied to other similar places, like flag
names, tool name in error logging, and tool args.

The `tool_name_metrics.json` was manually updated because we never
landed the server side change because it was disallowed by proto style
check.
2026-05-14 20:31:44 +00:00

172 行
5.6 KiB
TypeScript

/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import assert from 'node:assert/strict';
import {describe, it} from 'node:test';
import type {cliOptions} from '../../src/bin/chrome-devtools-mcp-cli-options.js';
import {
computeFlagUsage,
getPossibleFlagMetrics,
} from '../../src/telemetry/flagUtils.js';
describe('computeFlagUsage', () => {
const mockOptions = {
boolFlag: {
type: 'boolean' as const,
description: 'A boolean flag',
},
stringFlag: {
type: 'string' as const,
description: 'A string flag',
},
enumFlag: {
type: 'string' as const,
description: 'An enum flag',
choices: ['a', 'b'],
},
flagWithDefault: {
type: 'boolean' as const,
description: 'A flag with a default value',
default: false,
},
} as unknown as typeof cliOptions;
it('logs boolean flags directly with snake_case keys', () => {
const args = {boolFlag: true};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.bool_flag, true);
});
it('logs boolean flags as false when false', () => {
const args = {boolFlag: false};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.bool_flag, false);
});
it('logs enum flags as uppercase strings prefixed by snake case flag name', () => {
const args = {enumFlag: 'a'};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.enum_flag, 'ENUM_FLAG_A');
});
it('logs other flags as present with snake_case keys', () => {
const args = {stringFlag: 'value'};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.string_flag, undefined);
assert.equal(usage.string_flag_present, true);
});
it('handles undefined/null values', () => {
const args = {stringFlag: undefined};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.string_flag_present, false);
});
describe('defaults behavior', () => {
it('logs presence when default exists and user provides different value', () => {
// Case 1: Default exists, and a value is provided by the user.
// default is false, user provides true.
const args = {flagWithDefault: true};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.flag_with_default, true);
assert.equal(usage.flag_with_default_present, true);
});
it('does not log presence when default exists and user provides no value', () => {
// Case 2a: Default exists, and a value is not provided by the user.
// Argument parsing would populate with default.
const args = {flagWithDefault: false};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.flag_with_default, false);
assert.equal(usage.flag_with_default_present, undefined);
});
it('does not log presence when default exists and user explicitly provides the default value', () => {
// Case 2b: User explicitly provides 'false', which matches default.
const args = {flagWithDefault: false};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.flag_with_default, false);
assert.equal(usage.flag_with_default_present, undefined);
});
it('logs presence when no default exists and user provides value', () => {
// Case 3: No default, user provides value.
const args = {stringFlag: 'value'};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.string_flag_present, true);
});
it('logs non-presence when no default exists and user provides no value', () => {
// Case 4: No default, user provides nothing.
const args = {};
const usage = computeFlagUsage(args, mockOptions);
assert.equal(usage.string_flag_present, false);
});
it('sanitizes flag names containing underscores before numbers', () => {
const mock3pOptions = {
experimental3pTool: {
type: 'boolean' as const,
description: 'A 3p flag',
},
} as unknown as typeof cliOptions;
const args = {experimental3pTool: true};
const usage = computeFlagUsage(args, mock3pOptions);
assert.equal(usage.experimental3p_tool, true);
});
});
});
describe('getPossibleFlagMetrics', () => {
const mockOptions = {
boolFlag: {
type: 'boolean' as const,
description: 'A boolean flag',
},
stringFlag: {
type: 'string' as const,
description: 'A string flag',
},
enumFlag: {
type: 'string' as const,
description: 'An enum flag',
choices: ['a', 'b'],
},
} as unknown as typeof cliOptions;
it('returns all possible metrics for given options', () => {
const metrics = getPossibleFlagMetrics(mockOptions);
assert.deepEqual(metrics, [
{name: 'bool_flag_present', flagType: 'boolean'},
{name: 'bool_flag', flagType: 'boolean'},
{name: 'string_flag_present', flagType: 'boolean'},
{name: 'enum_flag_present', flagType: 'boolean'},
{
name: 'enum_flag',
flagType: 'enum',
choices: ['ENUM_FLAG_UNSPECIFIED', 'ENUM_FLAG_A', 'ENUM_FLAG_B'],
},
]);
});
it('sanitizes flag names containing underscores before numbers', () => {
const mock3pOptions = {
experimental3pTool: {
type: 'boolean' as const,
description: 'A 3p flag',
},
} as unknown as typeof cliOptions;
const metrics = getPossibleFlagMetrics(mock3pOptions);
assert.deepEqual(metrics, [
{name: 'experimental3p_tool_present', flagType: 'boolean'},
{name: 'experimental3p_tool', flagType: 'boolean'},
]);
});
});