Skip to content

Commit

Permalink
Add more study validation from processed_study.cc. (#1183)
Browse files Browse the repository at this point in the history
Implement additional validation that exists in
[processed_study.cc](https://source.chromium.org/chromium/chromium/src/+/main:components/variations/processed_study.cc;l=38;drc=f9d386e085b36b0118ab74f9a3d6dc18934de430).

Important ones:
* study, experiment, feature name validation
* default_experiment_name validation + experiment existence validation
* experiment param name conflict and emptiness

Other was added just to have the full coverage (forcing_flag,
google_web_experiment_id).
  • Loading branch information
goodov authored Aug 20, 2024
1 parent 6e47a28 commit 0f56482
Show file tree
Hide file tree
Showing 7 changed files with 585 additions and 7 deletions.
14 changes: 14 additions & 0 deletions src/seed_tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,17 @@ npm run seed_tools -- split_seed_json <seed_json_path> <output_dir>
- `<seed_json_path>`: The path to the `seed.json` file to be split.
- `<output_dir>`: The directory where the individual study files will be
outputted.

### `validate_seed`

Validates a seed protobuf.

##### Syntax

```bash
npm run seed_tools -- validate_seed <seed_file>
```

##### Arguments

- `<seed_file>`: The path to the binary-serialized `seed` protobuf.
55 changes: 55 additions & 0 deletions src/seed_tools/commands/validate_seed.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

import * as fs_sync from 'fs';
import * as path from 'path';
import { wsPath } from '../../base/path_utils';
import validate_seed from './validate_seed';

describe('validate_seed command', () => {
const testDataDir = wsPath('//src/test/data');

let errorMock: jest.SpyInstance;
let exitMock: jest.SpyInstance;

beforeEach(async () => {
errorMock = jest.spyOn(console, 'error').mockImplementation();
exitMock = jest.spyOn(process, 'exit').mockImplementation();
});

afterEach(async () => {
jest.restoreAllMocks();
});

describe('valid seeds', () => {
const validSeedsDir = path.join(testDataDir, 'valid_seeds');
it.each(fs_sync.readdirSync(validSeedsDir))(
'correctly validates %s',
async (testCase) => {
const testCaseDir = path.join(validSeedsDir, testCase);
const seedBin = path.join(testCaseDir, 'expected_seed.bin');

await validate_seed.parseAsync(['node', 'validate_seed', seedBin]);

expect(errorMock).toHaveBeenCalledTimes(0);
expect(exitMock).toHaveBeenCalledWith(0);
},
);
});

test('invalid seed', async () => {
const seedBin = path.join(testDataDir, 'invalid_seed.bin');
expect(fs_sync.existsSync(seedBin)).toBe(true);

await validate_seed.parseAsync(['node', 'validate_seed', seedBin]);

expect(errorMock).toHaveBeenCalledWith(
expect.stringContaining(
'Total probability is not 100 for study AllowCertainClientHintsStudy',
),
);
expect(exitMock).toHaveBeenCalledWith(1);
});
});
44 changes: 44 additions & 0 deletions src/seed_tools/commands/validate_seed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

import { Command } from '@commander-js/extra-typings';
import { promises as fs } from 'fs';
import { VariationsSeed } from '../../proto/generated/variations_seed';
import * as seed_validation from '../utils/seed_validation';
import * as study_validation from '../utils/study_validation';

export default new Command('validate_seed')
.description('Validates seed.bin')
.argument('<seed_file>', 'path to a seed protobuf')
.action(main);

async function main(seedFilePath: string) {
const variationsSeed = VariationsSeed.fromBinary(
await fs.readFile(seedFilePath, { encoding: null }),
);
const errors = [];
for (const study of variationsSeed.study) {
const filePath = `${study.name}.json`;
for (const error of study_validation.validateStudyReturnErrors(
study,
filePath,
)) {
errors.push(error);
}
}

for (const error of seed_validation.validateSeedReturnErrors(
variationsSeed,
)) {
errors.push(error);
}

console.log('Seed studies count:', variationsSeed.study.length);
if (errors.length > 0) {
console.error(`Seed validation errors:\n${errors.join('\n---\n')}`);
}

process.exit(errors.length > 0 ? 1 : 0);
}
2 changes: 2 additions & 0 deletions src/seed_tools/seed_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import check_study from './commands/check_study';
import compare_seeds from './commands/compare_seeds';
import create_seed from './commands/create_seed';
import split_seed_json from './commands/split_seed_json';
import validate_seed from './commands/validate_seed';

program
.name('seed_tools')
Expand All @@ -17,4 +18,5 @@ program
.addCommand(compare_seeds)
.addCommand(create_seed)
.addCommand(split_seed_json)
.addCommand(validate_seed)
.parse();
Loading

0 comments on commit 0f56482

Please sign in to comment.