Skip to content

Commit

Permalink
feat: support tags/match filtering in push
Browse files Browse the repository at this point in the history
  • Loading branch information
vigneshshanmugam committed Apr 3, 2024
1 parent 7c75279 commit a724735
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 101 deletions.
43 changes: 37 additions & 6 deletions __tests__/core/runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ describe('runner', () => {
expect(
await runner.run({
...defaultRunOptions,
match: 'j2',
filter: { match: 'j2' },
})
).toMatchObject({
j2: { status: 'succeeded' },
Expand All @@ -351,7 +351,7 @@ describe('runner', () => {
expect(
await runner.run({
...defaultRunOptions,
match: 'j*',
filter: { match: 'j*' },
})
).toMatchObject({
j1: { status: 'succeeded' },
Expand All @@ -368,8 +368,7 @@ describe('runner', () => {
expect(
await runner.run({
...defaultRunOptions,
tags: ['foo*'],
match: 'j*',
filter: { tags: ['foo*'], match: 'j*' },
})
).toMatchObject({
j1: { status: 'succeeded' },
Expand All @@ -385,7 +384,7 @@ describe('runner', () => {
expect(
await runner.run({
...defaultRunOptions,
tags: ['hello:b*'],
filter: { tags: ['hello:b*'] },
})
).toMatchObject({
j2: { status: 'succeeded' },
Expand All @@ -400,7 +399,7 @@ describe('runner', () => {
expect(
await runner.run({
...defaultRunOptions,
tags: ['!hello:b*'],
filter: { tags: ['!hello:b*'] },
})
).toMatchObject({
j1: { status: 'succeeded' },
Expand Down Expand Up @@ -810,6 +809,38 @@ describe('runner', () => {
alert: { tls: { enabled: true } },
});
});

it('runner - build monitors filtered through "match"', async () => {
const j1 = new Journey({ name: 'j1' }, noop);
const j2 = new Journey({ name: 'j2' }, noop);
runner.addJourney(j1);
runner.addJourney(j2);

const monitors = runner.buildMonitors({
...options,
filter: { match: 'j1' },
schedule: 1,
});
expect(monitors.length).toBe(1);
expect(monitors[0].config.name).toBe('j1');
});

it('runner - build monitors filtered through "tags"', async () => {
const j1 = new Journey({ name: 'j1', tags: ['first'] }, noop);
const j2 = new Journey({ name: 'j2', tags: ['second'] }, noop);
const j3 = new Journey({ name: 'j3' }, noop);
runner.addJourney(j1);
runner.addJourney(j2);
runner.addJourney(j3);

const monitors = runner.buildMonitors({
...options,
filter: { tags: ['first'] },
schedule: 1,
});
expect(monitors.length).toBe(1);
expect(monitors[0].config.name).toBe('j1');
});
});

describe('journey and step annotations', () => {
Expand Down
7 changes: 0 additions & 7 deletions __tests__/push/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Push abort on tags and match 1`] = `
"Aborted. Invalid CLI flags.
Tags and Match are not supported in push command.
"
`;

exports[`Push error on empty project id 1`] = `
"Aborted. Invalid synthetics project settings.
Expand Down
6 changes: 0 additions & 6 deletions __tests__/push/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,6 @@ describe('Push', () => {
expect(output).toContain('Push command Aborted');
});

it('abort on tags and match', async () => {
await fakeProjectSetup({}, {});
const output = await runPush([...DEFAULT_ARGS, '--tags', 'foo:*']);
expect(output).toMatchSnapshot();
});

it('error on invalid schedule in monitor DSL', async () => {
await fakeProjectSetup(
{ id: 'test-project', space: 'dummy', url: 'http://localhost:8080' },
Expand Down
46 changes: 45 additions & 1 deletion __tests__/push/monitor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ heartbeat.monitors:
`);
const monitors = await createLightweightMonitors(PROJECT_DIR, {
...opts,
pattern: '.yaml$',
filter: { pattern: '.yaml$' },
});
expect(monitors.length).toBe(0);
});
Expand Down Expand Up @@ -236,6 +236,50 @@ heartbeat.monitors:
expect(monitors.length).toBe(1);
});

it('push - match filering', async () => {
await writeHBFile(`
heartbeat.monitors:
- type: http
name: "m1"
id: "mon1"
tags: "tag1"
- type: http
name: "m2"
id: "mon2"
tags: "tag2"
`);
const monitors = await createLightweightMonitors(PROJECT_DIR, {
...opts,
filter: { match: 'm1' },
});
expect(monitors.length).toBe(1);
expect(monitors[0].config.name).toEqual('m1');
});

it('push - tags filering', async () => {
await writeHBFile(`
heartbeat.monitors:
- type: http
name: "m1"
id: "mon1"
tags: ["foo", "bar"]
- type: http
name: "m2"
id: "mon2"
tags: ["bar", "baz"]
- type: http
name: "m3"
id: "mon3"
tags: ["baz", "boom"]
`);
const monitors = await createLightweightMonitors(PROJECT_DIR, {
...opts,
filter: { tags: ['bar'] },
});
expect(monitors.length).toBe(2);
expect(monitors.map(m => m.config.name)).toEqual(['m1', 'm2']);
});

it('prefer local monitor config', async () => {
await writeHBFile(`
heartbeat.monitors:
Expand Down
26 changes: 17 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,25 @@ import { installTransform } from './core/transform';
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
const { name, version } = require('../package.json');

const { params, pattern, playwrightOpts, auth, authMandatory, configOpt } =
getCommonCommandOpts();
const {
params,
pattern,
playwrightOpts,
auth,
authMandatory,
configOpt,
tags,
match,
} = getCommonCommandOpts();

program
.name(`npx ${name}`)
.usage('[options] [dir] [files] file')
.addOption(configOpt)
.addOption(pattern)
.addOption(tags)
.addOption(match)
.addOption(params)
.option('--tags <name...>', 'run tests with a tag that matches the glob')
.option(
'--match <name>',
'run tests with a name or tags that matches the glob'
)
.addOption(
new Option('--reporter <value>', `output reporter format`).choices(
Object.keys(reporters)
Expand Down Expand Up @@ -157,6 +162,7 @@ program
.description(
'Push all journeys in the current directory to create monitors within the Kibana monitor management UI'
)
.addOption(authMandatory)
.option(
'--schedule <time-in-minutes>',
"schedule in minutes for the pushed monitors. Setting `10`, for example, configures monitors which don't have an interval defined to run every 10 minutes.",
Expand All @@ -172,7 +178,7 @@ program
'--private-locations <locations...>',
'default list of private locations from which your monitors will run.'
)
.option('--url <url>', 'Kibana URL to upload the monitors')
.option('--url <url>', 'Kibana URL to upload the project monitors')
.option(
'--id <id>',
'project id that will be used for logically grouping monitors'
Expand All @@ -182,8 +188,10 @@ program
'the target Kibana spaces for the pushed monitors — spaces help you organise pushed monitors.'
)
.option('-y, --yes', 'skip all questions and run non-interactively')
.addOption(authMandatory)

.addOption(pattern)
.addOption(tags)
.addOption(match)
.addOption(params)
.addOption(playwrightOpts)
.addOption(configOpt)
Expand Down
15 changes: 12 additions & 3 deletions src/common_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,18 @@ export type ThrottlingOptions = {
latency?: number;
};

type CmdFilter = {
pattern?: string;
tags?: Array<string>;
match?: string;
};

type BaseArgs = {
params?: Params;
screenshots?: ScreenshotOptions;
dryRun?: boolean;
config?: string;
pattern?: string;
match?: string;
tags?: Array<string>;
auth?: string;
outfd?: number;
wsEndpoint?: string;
pauseOnError?: boolean;
Expand All @@ -217,9 +221,13 @@ type BaseArgs = {
schedule?: MonitorConfig['schedule'];
locations?: MonitorConfig['locations'];
privateLocations?: MonitorConfig['privateLocations'];
filter?: CmdFilter;
};

export type CliArgs = BaseArgs & {
pattern?: string;
match?: string;
tags?: Array<string>;
reporter?: BuiltInReporterName;
inline?: boolean;
require?: Array<string>;
Expand All @@ -246,6 +254,7 @@ export type PushOptions = Partial<ProjectSettings> &
auth: string;
kibanaVersion?: string;
yes?: boolean;
tags?: Array<string>;
alert?: AlertConfig;
retestOnFailure?: MonitorConfig['retestOnFailure'];
enabled?: boolean;
Expand Down
20 changes: 14 additions & 6 deletions src/core/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,7 @@ export default class Runner {

buildMonitors(options: PushOptions) {
/**
* Update the global monitor configuration required for
* setting defaults
* Update the global monitor configuration required for setting defaults
*/
this.updateMonitor({
throttling: options.throttling,
Expand All @@ -430,11 +429,20 @@ export default class Runner {
);
}
/**
* Execute dummy callback to get all monitor specific
* configurations for the current journey
* Before pushing a browser monitor, three things need to be done:
*
* - execute callback `monitor.use` in particular to get monitor configurations
* - update the monitor config with global configuration
* - filter out monitors based on matched tags and name after applying both
* global and local monitor configurations
*/
journey.callback({ params: options.params } as any);
journey.monitor.update(this.monitor?.config);
if (
!journey.monitor.isMatch(options.filter?.match, options.filter?.tags)
) {
continue;
}
journey.monitor.validate();
monitors.push(journey.monitor);
}
Expand All @@ -454,7 +462,7 @@ export default class Runner {
params: options.params,
}).catch(e => (this.hookError = e));

const { dryRun, match, tags } = options;
const { dryRun, filter } = options;
/**
* Skip other journeys when using `.only`
*/
Expand All @@ -471,7 +479,7 @@ export default class Runner {
this.#reporter.onJourneyRegister?.(journey);
continue;
}
if (!journey.isMatch(match, tags) || journey.skip) {
if (!journey.isMatch(filter?.match, filter?.tags) || journey.skip) {
continue;
}
const journeyResult: JourneyResult = this.hookError
Expand Down
14 changes: 13 additions & 1 deletion src/dsl/monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
Params,
PlaywrightOptions,
} from '../common_types';
import { indent } from '../helpers';
import { indent, isMatch } from '../helpers';
import { LocationsMap } from '../locations/public-locations';

export type SyntheticsLocationsType = keyof typeof LocationsMap;
Expand Down Expand Up @@ -129,6 +129,18 @@ export class Monitor {
this.filter = filter;
}

/**
* Matches monitors based on the provided args. Proitize tags over match
*/
isMatch(matchPattern: string, tagsPattern: Array<string>) {
return isMatch(
this.config.tags,
this.config.name,
tagsPattern,
matchPattern
);
}

/**
* Hash is used to identify if the monitor has changed since the last time
* it was pushed to Kibana. Change is based on three factors:
Expand Down

0 comments on commit a724735

Please sign in to comment.