@elastic/synthetics 1.0.0-beta.26 → 1.0.0-beta.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +24 -14
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +0 -1
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/gatherer.js +2 -2
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +5 -1
- package/dist/core/runner.js.map +1 -1
- package/dist/dsl/locations.d.ts +37 -0
- package/dist/dsl/locations.d.ts.map +1 -0
- package/dist/dsl/locations.js +41 -0
- package/dist/dsl/locations.js.map +1 -0
- package/dist/dsl/monitor.d.ts +3 -2
- package/dist/dsl/monitor.d.ts.map +1 -1
- package/dist/dsl/monitor.js +2 -1
- package/dist/dsl/monitor.js.map +1 -1
- package/dist/generator/index.d.ts +9 -1
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +57 -11
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/utils.d.ts +1 -0
- package/dist/generator/utils.d.ts.map +1 -1
- package/dist/generator/utils.js +14 -1
- package/dist/generator/utils.js.map +1 -1
- package/dist/options.d.ts +0 -5
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +20 -28
- package/dist/options.js.map +1 -1
- package/dist/push/bundler.d.ts.map +1 -1
- package/dist/push/bundler.js +4 -9
- package/dist/push/bundler.js.map +1 -1
- package/dist/push/index.d.ts.map +1 -1
- package/dist/push/index.js +1 -4
- package/dist/push/index.js.map +1 -1
- package/dist/push/monitor.d.ts.map +1 -1
- package/dist/push/monitor.js +2 -7
- package/dist/push/monitor.js.map +1 -1
- package/dist/push/plugin.d.ts.map +1 -1
- package/dist/push/plugin.js +1 -0
- package/dist/push/plugin.js.map +1 -1
- package/dist/push/request.d.ts +0 -1
- package/dist/push/request.d.ts.map +1 -1
- package/dist/push/request.js +6 -17
- package/dist/push/request.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -4
- package/src/cli.ts +37 -17
- package/src/common_types.ts +0 -1
- package/src/core/gatherer.ts +2 -2
- package/src/core/runner.ts +8 -1
- package/src/dsl/locations.ts +38 -0
- package/src/dsl/monitor.ts +6 -2
- package/src/generator/index.ts +70 -17
- package/src/generator/utils.ts +13 -0
- package/src/options.ts +23 -29
- package/src/push/bundler.ts +4 -8
- package/src/push/index.ts +2 -6
- package/src/push/monitor.ts +2 -11
- package/src/push/plugin.ts +1 -0
- package/src/push/request.ts +6 -18
- package/templates/.github/workflows/run-synthetics.yml +26 -0
- package/templates/README.md +21 -0
- package/templates/journeys/advanced-example-helpers.ts +54 -0
- package/templates/journeys/advanced-example.journey.ts +43 -0
- package/templates/synthetics.config.ts +7 -0
package/src/cli.ts
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { program, Option } from 'commander';
|
|
29
|
+
import { cwd } from 'process';
|
|
29
30
|
import { CliArgs, PushOptions } from './common_types';
|
|
30
31
|
import { reporters } from './reporters';
|
|
31
32
|
import { normalizeOptions, parseThrottling } from './options';
|
|
@@ -65,7 +66,7 @@ program
|
|
|
65
66
|
.option('--inline', 'Run inline journeys from heartbeat')
|
|
66
67
|
.option('-r, --require <modules...>', 'module(s) to preload')
|
|
67
68
|
.option('--no-headless', 'run browser in headful mode')
|
|
68
|
-
.option('--sandbox', 'enable chromium sandboxing'
|
|
69
|
+
.option('--sandbox', 'enable chromium sandboxing')
|
|
69
70
|
.option('--rich-events', 'Mimics a heartbeat run')
|
|
70
71
|
.option(
|
|
71
72
|
'--capability <features...>',
|
|
@@ -81,12 +82,12 @@ program
|
|
|
81
82
|
"don't actually execute anything, report only registered journeys"
|
|
82
83
|
)
|
|
83
84
|
.option(
|
|
84
|
-
'--
|
|
85
|
-
'run only journeys with a
|
|
85
|
+
'--tags <name...>',
|
|
86
|
+
'run only journeys with a tag that matches the glob'
|
|
86
87
|
)
|
|
87
88
|
.option(
|
|
88
|
-
'--
|
|
89
|
-
'run only journeys with
|
|
89
|
+
'--match <name>',
|
|
90
|
+
'run only journeys with a name or tag that matches the glob'
|
|
90
91
|
)
|
|
91
92
|
.option(
|
|
92
93
|
'--outfd <fd>',
|
|
@@ -146,9 +147,21 @@ program
|
|
|
146
147
|
|
|
147
148
|
// Push command
|
|
148
149
|
program
|
|
149
|
-
.command('push
|
|
150
|
+
.command('push')
|
|
150
151
|
.description(
|
|
151
|
-
'Push
|
|
152
|
+
'Push journeys in the current directory to create monitors within the Kibana monitor management UI'
|
|
153
|
+
)
|
|
154
|
+
.option(
|
|
155
|
+
'--pattern <pattern>',
|
|
156
|
+
'RegExp file patterns to push inside current directory'
|
|
157
|
+
)
|
|
158
|
+
.option(
|
|
159
|
+
'--tags <name...>',
|
|
160
|
+
'push only journeys with a tag that matches the glob'
|
|
161
|
+
)
|
|
162
|
+
.option(
|
|
163
|
+
'--match <name>',
|
|
164
|
+
'push only journeys with a name or tag that matches the glob'
|
|
152
165
|
)
|
|
153
166
|
.option(
|
|
154
167
|
'--schedule <time-in-minutes>',
|
|
@@ -158,33 +171,40 @@ program
|
|
|
158
171
|
.addOption(
|
|
159
172
|
new Option(
|
|
160
173
|
'--locations <locations...>',
|
|
161
|
-
'
|
|
174
|
+
'default list of locations from which your monitors will run.'
|
|
162
175
|
).choices(SyntheticsLocations)
|
|
163
176
|
)
|
|
164
177
|
.requiredOption(
|
|
165
|
-
'--project <id
|
|
166
|
-
'
|
|
178
|
+
'--project <project-id>',
|
|
179
|
+
'id that will be used for logically grouping monitors'
|
|
167
180
|
)
|
|
168
181
|
.requiredOption('--url <url>', 'kibana URL to upload the monitors')
|
|
169
182
|
.requiredOption(
|
|
170
183
|
'--auth <auth>',
|
|
171
|
-
'
|
|
184
|
+
'API key used for Kibana authentication(https://www.elastic.co/guide/en/kibana/master/api-keys.html).'
|
|
172
185
|
)
|
|
173
186
|
.option(
|
|
174
187
|
'--space <space>',
|
|
175
188
|
'the target Kibana spaces for the pushed monitors — spaces help you organise pushed monitors.',
|
|
176
189
|
'default'
|
|
177
190
|
)
|
|
178
|
-
.
|
|
179
|
-
.action(async (files, cmdOpts: PushOptions) => {
|
|
191
|
+
.action(async (cmdOpts: PushOptions) => {
|
|
180
192
|
try {
|
|
181
|
-
|
|
182
|
-
await loadTestFiles(cliArgs, files);
|
|
193
|
+
await loadTestFiles({ inline: false }, [cwd()]);
|
|
183
194
|
const options = normalizeOptions({ ...program.opts(), ...cmdOpts });
|
|
195
|
+
if (!options.schedule) {
|
|
196
|
+
throw error(`Set default schedule in minutes for all monitors via '--schedule <time-in-minutes>' OR
|
|
197
|
+
configure via Synthetics config file under 'monitors.schedule' field.`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!options.locations) {
|
|
201
|
+
throw error(`Set default location for all monitors via CLI as '--locations <locations...>' OR
|
|
202
|
+
configure via Synthetics config file under 'monitors.locations' field.`);
|
|
203
|
+
}
|
|
184
204
|
const monitors = runner.buildMonitors(options);
|
|
185
205
|
await push(monitors, cmdOpts);
|
|
186
206
|
} catch (e) {
|
|
187
|
-
console.error(e);
|
|
207
|
+
e && console.error(e);
|
|
188
208
|
process.exit(1);
|
|
189
209
|
}
|
|
190
210
|
});
|
|
@@ -198,7 +218,7 @@ program
|
|
|
198
218
|
const generator = await new Generator(resolve(process.cwd(), dir));
|
|
199
219
|
await generator.setup();
|
|
200
220
|
} catch (e) {
|
|
201
|
-
error(e);
|
|
221
|
+
e && error(e);
|
|
202
222
|
process.exit(1);
|
|
203
223
|
}
|
|
204
224
|
});
|
package/src/common_types.ts
CHANGED
package/src/core/gatherer.ts
CHANGED
|
@@ -65,12 +65,12 @@ export class Gatherer {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
static async getUserAgent(userAgent?: string) {
|
|
68
|
-
const syntheticsIdentifier = ' Elastic/Synthetics';
|
|
69
68
|
if (!userAgent) {
|
|
70
69
|
const session = await Gatherer.browser.newBrowserCDPSession();
|
|
71
70
|
({ userAgent } = await session.send('Browser.getVersion'));
|
|
71
|
+
return userAgent + ' Elastic/Synthetics';
|
|
72
72
|
}
|
|
73
|
-
return userAgent
|
|
73
|
+
return userAgent;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
static setNetworkConditions(
|
package/src/core/runner.ts
CHANGED
|
@@ -97,11 +97,11 @@ export default class Runner {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
async captureScreenshot(page: Driver['page'], step: Step) {
|
|
100
|
-
await page.waitForLoadState('load');
|
|
101
100
|
const buffer = await page
|
|
102
101
|
.screenshot({
|
|
103
102
|
type: 'jpeg',
|
|
104
103
|
quality: 80,
|
|
104
|
+
timeout: 5000,
|
|
105
105
|
})
|
|
106
106
|
.catch(() => {});
|
|
107
107
|
/**
|
|
@@ -397,9 +397,16 @@ export default class Runner {
|
|
|
397
397
|
playwrightOptions: options.playwrightOptions,
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
+
const { match, tags } = options;
|
|
401
|
+
|
|
400
402
|
const monitors: Monitor[] = [];
|
|
401
403
|
for (const journey of this.journeys) {
|
|
404
|
+
if (!journey.isMatch(match, tags)) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
|
|
402
408
|
this.#currentJourney = journey;
|
|
409
|
+
|
|
403
410
|
/**
|
|
404
411
|
* Execute dummy callback to get all monitor specific
|
|
405
412
|
* configurations for the current journey
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present, Elastic NV
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// DO NOT EDIT - UPDATE WITH `npm run build:locations`
|
|
27
|
+
export const LocationsMap = {
|
|
28
|
+
japan: 'asia-northeast1-a',
|
|
29
|
+
india: 'asia-south1-a',
|
|
30
|
+
singapore: 'asia-southeast1-a',
|
|
31
|
+
australia_east: 'australia-southeast1-a',
|
|
32
|
+
united_kingdom: 'europe-west2-a',
|
|
33
|
+
germany: 'europe-west3-a',
|
|
34
|
+
canada_east: 'northamerica-northeast1-a',
|
|
35
|
+
brazil: 'southamerica-east1-a',
|
|
36
|
+
us_east: 'us-east4-a',
|
|
37
|
+
us_west: 'us-west1-a',
|
|
38
|
+
};
|
package/src/dsl/monitor.ts
CHANGED
|
@@ -31,9 +31,13 @@ import {
|
|
|
31
31
|
Params,
|
|
32
32
|
PlaywrightOptions,
|
|
33
33
|
} from '../common_types';
|
|
34
|
+
import { LocationsMap } from './locations';
|
|
35
|
+
|
|
36
|
+
export type SyntheticsLocationsType = keyof typeof LocationsMap;
|
|
37
|
+
export const SyntheticsLocations = Object.keys(
|
|
38
|
+
LocationsMap
|
|
39
|
+
) as SyntheticsLocationsType[];
|
|
34
40
|
|
|
35
|
-
export const SyntheticsLocations = ['US East', 'EU West'] as const;
|
|
36
|
-
export type SyntheticsLocationsType = typeof SyntheticsLocations[number];
|
|
37
41
|
export type MonitorConfig = {
|
|
38
42
|
id?: string;
|
|
39
43
|
name?: string;
|
package/src/generator/index.ts
CHANGED
|
@@ -27,13 +27,29 @@ import { existsSync } from 'fs';
|
|
|
27
27
|
import { mkdir, readFile, writeFile } from 'fs/promises';
|
|
28
28
|
import { bold, cyan, yellow } from 'kleur/colors';
|
|
29
29
|
import { join, relative, dirname, basename } from 'path';
|
|
30
|
+
import { prompt } from 'enquirer';
|
|
31
|
+
import { SyntheticsLocations } from '../dsl/monitor';
|
|
30
32
|
import { progress, write as stdWrite } from '../helpers';
|
|
31
|
-
import { getPackageManager, runCommand } from './utils';
|
|
33
|
+
import { getPackageManager, replaceTemplates, runCommand } from './utils';
|
|
32
34
|
|
|
33
35
|
// Templates that are required for setting up new
|
|
34
36
|
// synthetics project
|
|
35
37
|
const templateDir = join(__dirname, '..', '..', 'templates');
|
|
36
38
|
|
|
39
|
+
type PromptOptions = {
|
|
40
|
+
locations: string;
|
|
41
|
+
schedule: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// exported for testing
|
|
45
|
+
export const regularFiles = [
|
|
46
|
+
'.github/workflows/run-synthetics.yml',
|
|
47
|
+
'README.md',
|
|
48
|
+
'journeys/example.journey.ts',
|
|
49
|
+
'journeys/advanced-example.journey.ts',
|
|
50
|
+
'journeys/advanced-example-helpers.ts',
|
|
51
|
+
];
|
|
52
|
+
|
|
37
53
|
export class Generator {
|
|
38
54
|
pkgManager = 'npm';
|
|
39
55
|
constructor(public projectDir: string) {}
|
|
@@ -44,26 +60,47 @@ export class Generator {
|
|
|
44
60
|
}
|
|
45
61
|
}
|
|
46
62
|
|
|
47
|
-
async
|
|
63
|
+
async questions() {
|
|
64
|
+
if (process.env.TEST_QUESTIONS) {
|
|
65
|
+
return JSON.parse(process.env.TEST_QUESTIONS);
|
|
66
|
+
}
|
|
67
|
+
const question = [
|
|
68
|
+
{
|
|
69
|
+
type: 'select',
|
|
70
|
+
name: 'locations',
|
|
71
|
+
message: 'Select the default location where you want to run monitors.',
|
|
72
|
+
choices: SyntheticsLocations,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: 'numeral',
|
|
76
|
+
name: 'schedule',
|
|
77
|
+
message: 'Set default schedule in minutes for all monitors',
|
|
78
|
+
initial: 10,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
return await prompt<PromptOptions>(question);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async files(answers: PromptOptions) {
|
|
48
85
|
const fileMap = new Map<string, string>();
|
|
49
86
|
// Setup Synthetics config file
|
|
50
87
|
const configFile = 'synthetics.config.ts';
|
|
51
88
|
fileMap.set(
|
|
52
89
|
configFile,
|
|
53
|
-
|
|
90
|
+
replaceTemplates(
|
|
91
|
+
await readFile(join(templateDir, configFile), 'utf-8'),
|
|
92
|
+
answers
|
|
93
|
+
)
|
|
54
94
|
);
|
|
55
95
|
|
|
56
|
-
// Setup
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
'.gitignore',
|
|
65
|
-
await readFile(join(templateDir, '.gitignore'), 'utf-8')
|
|
66
|
-
);
|
|
96
|
+
// Setup non-templated files
|
|
97
|
+
Promise.all(
|
|
98
|
+
regularFiles.map(async fn => {
|
|
99
|
+
fileMap.set(fn, await readFile(join(templateDir, fn), 'utf-8'));
|
|
100
|
+
})
|
|
101
|
+
).catch(e => {
|
|
102
|
+
throw e;
|
|
103
|
+
});
|
|
67
104
|
|
|
68
105
|
// Create files
|
|
69
106
|
for (const [relativePath, content] of fileMap) {
|
|
@@ -122,7 +159,7 @@ export class Generator {
|
|
|
122
159
|
|
|
123
160
|
// Add push command
|
|
124
161
|
const project = basename(this.projectDir);
|
|
125
|
-
pkgJSON.scripts.push = `npx @elastic/synthetics push journeys --project ${project} --url http://localhost:5601 --auth
|
|
162
|
+
pkgJSON.scripts.push = `npx @elastic/synthetics push journeys --project ${project} --url http://localhost:5601 --auth apiKey`;
|
|
126
163
|
|
|
127
164
|
await this.createFile(
|
|
128
165
|
filename,
|
|
@@ -131,6 +168,20 @@ export class Generator {
|
|
|
131
168
|
);
|
|
132
169
|
}
|
|
133
170
|
|
|
171
|
+
async patchGitIgnore() {
|
|
172
|
+
const gitIgnorePath = join(this.projectDir, '.gitignore');
|
|
173
|
+
let gitIgnore = '';
|
|
174
|
+
if (existsSync(gitIgnorePath)) {
|
|
175
|
+
const contents = await readFile(gitIgnorePath, 'utf-8');
|
|
176
|
+
gitIgnore += contents.trimEnd() + '\n';
|
|
177
|
+
}
|
|
178
|
+
if (!gitIgnore.includes('node_modules')) {
|
|
179
|
+
gitIgnore += 'node_modules/\n';
|
|
180
|
+
}
|
|
181
|
+
gitIgnore += '.synthetics/\n';
|
|
182
|
+
await writeFile(gitIgnorePath, gitIgnore, 'utf-8');
|
|
183
|
+
}
|
|
184
|
+
|
|
134
185
|
banner() {
|
|
135
186
|
stdWrite(
|
|
136
187
|
bold(`
|
|
@@ -141,7 +192,7 @@ All set, you can run below commands inside: ${this.projectDir}:
|
|
|
141
192
|
Push monitors to Kibana: ${cyan(runCommand(this.pkgManager, 'push'))}
|
|
142
193
|
|
|
143
194
|
${yellow(
|
|
144
|
-
'Make sure to update the Kibana url and
|
|
195
|
+
'Make sure to update the Kibana url and api keys before pushing monitors to Kibana.'
|
|
145
196
|
)}
|
|
146
197
|
|
|
147
198
|
Visit https://www.elastic.co/guide/en/observability/master/synthetics-journeys.html to learn more.
|
|
@@ -151,9 +202,11 @@ Visit https://www.elastic.co/guide/en/observability/master/synthetics-journeys.h
|
|
|
151
202
|
|
|
152
203
|
async setup() {
|
|
153
204
|
await this.directory();
|
|
205
|
+
const answers = await this.questions();
|
|
154
206
|
await this.package();
|
|
155
|
-
await this.files();
|
|
207
|
+
await this.files(answers);
|
|
156
208
|
await this.patchPkgJSON();
|
|
209
|
+
await this.patchGitIgnore();
|
|
157
210
|
this.banner();
|
|
158
211
|
}
|
|
159
212
|
}
|
package/src/generator/utils.ts
CHANGED
|
@@ -39,3 +39,16 @@ export function runCommand(pkgManager: string, command: string) {
|
|
|
39
39
|
}
|
|
40
40
|
return `npm run ${command}`;
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
export function replaceTemplates(input: string, literals: Record<string, any>) {
|
|
44
|
+
for (const key in literals) {
|
|
45
|
+
const finalValue = literals[key];
|
|
46
|
+
input = input.replace(new RegExp(`'{{` + key + `}}'`, 'g'), () => {
|
|
47
|
+
if (typeof finalValue == 'number') {
|
|
48
|
+
return Number(finalValue);
|
|
49
|
+
}
|
|
50
|
+
return finalValue;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return input;
|
|
54
|
+
}
|
package/src/options.ts
CHANGED
|
@@ -27,7 +27,6 @@ import merge from 'deepmerge';
|
|
|
27
27
|
import { readConfig } from './config';
|
|
28
28
|
import { getNetworkConditions, DEFAULT_THROTTLING_OPTIONS } from './helpers';
|
|
29
29
|
import type { CliArgs, RunOptions, ThrottlingOptions } from './common_types';
|
|
30
|
-
import { MonitorConfig } from './dsl/monitor';
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
32
|
* Set debug based on DEBUG ENV and -d flags
|
|
@@ -100,21 +99,30 @@ export function normalizeOptions(cliArgs: CliArgs): RunOptions {
|
|
|
100
99
|
*/
|
|
101
100
|
options.params = Object.freeze(merge(config.params, cliArgs.params || {}));
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Merge playwright options from CLI and Synthetics config
|
|
104
|
+
* and prefer individual options over other option
|
|
105
|
+
*/
|
|
106
|
+
const playwrightOpts = merge(
|
|
107
|
+
config.playwrightOptions,
|
|
108
|
+
cliArgs.playwrightOptions || {}
|
|
109
|
+
);
|
|
110
|
+
options.playwrightOptions = {
|
|
111
|
+
...playwrightOpts,
|
|
112
|
+
headless: cliArgs.headless,
|
|
113
|
+
chromiumSandbox: cliArgs.sandbox ?? playwrightOpts?.chromiumSandbox,
|
|
114
|
+
ignoreHTTPSErrors:
|
|
115
|
+
cliArgs.ignoreHttpsErrors ?? playwrightOpts?.ignoreHTTPSErrors,
|
|
116
|
+
};
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Get the default monitor config from synthetics.config.ts file
|
|
120
|
+
*/
|
|
121
|
+
const monitor = config.monitor;
|
|
114
122
|
if (cliArgs.throttling) {
|
|
115
123
|
const throttleConfig = merge.all([
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
DEFAULT_THROTTLING_OPTIONS,
|
|
125
|
+
monitor?.throttling || {},
|
|
118
126
|
cliArgs.throttling as ThrottlingOptions,
|
|
119
127
|
]);
|
|
120
128
|
options.throttling = throttleConfig;
|
|
@@ -126,26 +134,12 @@ export function normalizeOptions(cliArgs: CliArgs): RunOptions {
|
|
|
126
134
|
options.throttling = {};
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
options.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
options.schedule =
|
|
133
|
-
cliArgs.schedule ?? config.monitor?.schedule ?? defaults.schedule;
|
|
137
|
+
options.schedule = cliArgs.schedule ?? monitor?.schedule;
|
|
138
|
+
options.locations = cliArgs.locations ?? monitor?.locations;
|
|
134
139
|
|
|
135
140
|
return options;
|
|
136
141
|
}
|
|
137
142
|
|
|
138
|
-
/**
|
|
139
|
-
* Get the default monitor configuration for all journeys
|
|
140
|
-
*/
|
|
141
|
-
export function getDefaultMonitorConfig(): MonitorConfig {
|
|
142
|
-
return {
|
|
143
|
-
throttling: DEFAULT_THROTTLING_OPTIONS,
|
|
144
|
-
locations: ['US East'],
|
|
145
|
-
schedule: 10,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
143
|
/**
|
|
150
144
|
* Parses the throttling CLI settings and also
|
|
151
145
|
* adapts to the format to keep the backwards compatability
|
package/src/push/bundler.ts
CHANGED
|
@@ -52,15 +52,11 @@ export class Bundler {
|
|
|
52
52
|
plugins: [MultiAssetPlugin(addToMap)],
|
|
53
53
|
},
|
|
54
54
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
throw result.errors;
|
|
59
|
-
}
|
|
60
|
-
this.moduleMap.set(absPath, result.outputFiles[0].text);
|
|
61
|
-
} catch (e) {
|
|
62
|
-
console.error(e);
|
|
55
|
+
const result = await esbuild.build(options);
|
|
56
|
+
if (result.errors.length > 0) {
|
|
57
|
+
throw result.errors;
|
|
63
58
|
}
|
|
59
|
+
this.moduleMap.set(absPath, result.outputFiles[0].text);
|
|
64
60
|
}
|
|
65
61
|
|
|
66
62
|
async zip(outputPath: string) {
|
package/src/push/index.ts
CHANGED
|
@@ -28,13 +28,12 @@ import {
|
|
|
28
28
|
ok,
|
|
29
29
|
formatAPIError,
|
|
30
30
|
formatFailedMonitors,
|
|
31
|
-
formatStaleMonitors,
|
|
32
31
|
formatNotFoundError,
|
|
33
32
|
} from './request';
|
|
34
33
|
import { Monitor } from '../dsl/monitor';
|
|
35
34
|
import { PushOptions } from '../common_types';
|
|
36
35
|
import { buildMonitorSchema } from './monitor';
|
|
37
|
-
import { progress, error, done
|
|
36
|
+
import { progress, error, done } from '../helpers';
|
|
38
37
|
|
|
39
38
|
export async function push(monitors: Monitor[], options: PushOptions) {
|
|
40
39
|
progress(`preparing all monitors`);
|
|
@@ -49,13 +48,10 @@ export async function push(monitors: Monitor[], options: PushOptions) {
|
|
|
49
48
|
const { error, message } = await body.json();
|
|
50
49
|
throw formatAPIError(statusCode, error, message);
|
|
51
50
|
}
|
|
52
|
-
const {
|
|
51
|
+
const { failedMonitors } = await body.json();
|
|
53
52
|
if (failedMonitors.length > 0) {
|
|
54
53
|
throw formatFailedMonitors(failedMonitors);
|
|
55
54
|
}
|
|
56
|
-
if (staleMonitors.length > 0) {
|
|
57
|
-
write(formatStaleMonitors());
|
|
58
|
-
}
|
|
59
55
|
done('Pushed');
|
|
60
56
|
} catch (e) {
|
|
61
57
|
error(e);
|
package/src/push/monitor.ts
CHANGED
|
@@ -27,11 +27,8 @@ import { mkdir } from 'fs/promises';
|
|
|
27
27
|
import { join } from 'path';
|
|
28
28
|
import { Bundler } from './bundler';
|
|
29
29
|
import { CACHE_PATH } from '../helpers';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
MonitorConfig,
|
|
33
|
-
SyntheticsLocationsType,
|
|
34
|
-
} from '../dsl/monitor';
|
|
30
|
+
import { LocationsMap } from '../dsl/locations';
|
|
31
|
+
import { Monitor, MonitorConfig } from '../dsl/monitor';
|
|
35
32
|
|
|
36
33
|
export type MonitorSchema = Omit<MonitorConfig, 'locations'> & {
|
|
37
34
|
content: string;
|
|
@@ -39,12 +36,6 @@ export type MonitorSchema = Omit<MonitorConfig, 'locations'> & {
|
|
|
39
36
|
filter: Monitor['filter'];
|
|
40
37
|
};
|
|
41
38
|
|
|
42
|
-
// Internal representation of Locations that would be used when
|
|
43
|
-
// talking to the Kibana API
|
|
44
|
-
const LocationsMap: Record<SyntheticsLocationsType, string> = {
|
|
45
|
-
'US East': 'us-east4-a',
|
|
46
|
-
'EU West': 'europe-west2-a',
|
|
47
|
-
};
|
|
48
39
|
function translateLocation(locations: MonitorConfig['locations']) {
|
|
49
40
|
return locations.map(loc => LocationsMap[loc]).filter(Boolean);
|
|
50
41
|
}
|
package/src/push/plugin.ts
CHANGED
package/src/push/request.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { bold
|
|
26
|
+
import { bold } from 'kleur/colors';
|
|
27
27
|
import { request } from 'undici';
|
|
28
28
|
import { PushOptions } from '../common_types';
|
|
29
29
|
import { indent, symbols } from '../helpers';
|
|
@@ -38,16 +38,11 @@ export type APISchema = {
|
|
|
38
38
|
monitors: MonitorSchema[];
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
function encodeAuth(auth: string) {
|
|
42
|
-
if (auth.includes(':')) {
|
|
43
|
-
return Buffer.from(auth).toString('base64');
|
|
44
|
-
}
|
|
45
|
-
return auth;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
41
|
function getAPIUrl(options: PushOptions) {
|
|
42
|
+
// remove trialing / as well
|
|
49
43
|
return (
|
|
50
|
-
options.url +
|
|
44
|
+
options.url.replace(/\/+$/, '') +
|
|
45
|
+
`/s/${options.space}/api/synthetics/service/project/monitors`
|
|
51
46
|
);
|
|
52
47
|
}
|
|
53
48
|
|
|
@@ -61,7 +56,7 @@ export async function createMonitors(
|
|
|
61
56
|
) {
|
|
62
57
|
const schema: APISchema = {
|
|
63
58
|
project: options.project,
|
|
64
|
-
keep_stale:
|
|
59
|
+
keep_stale: false,
|
|
65
60
|
monitors,
|
|
66
61
|
};
|
|
67
62
|
|
|
@@ -69,7 +64,7 @@ export async function createMonitors(
|
|
|
69
64
|
method: 'PUT',
|
|
70
65
|
body: JSON.stringify(schema),
|
|
71
66
|
headers: {
|
|
72
|
-
authorization: `
|
|
67
|
+
authorization: `ApiKey ${options.auth}`,
|
|
73
68
|
'content-type': 'application/json',
|
|
74
69
|
'user-agent': `Elastic/Synthetics ${version}`,
|
|
75
70
|
'kbn-xsrf': 'true',
|
|
@@ -114,10 +109,3 @@ export function formatFailedMonitors(errors: APIMonitorError[]) {
|
|
|
114
109
|
}
|
|
115
110
|
return outer;
|
|
116
111
|
}
|
|
117
|
-
|
|
118
|
-
export function formatStaleMonitors() {
|
|
119
|
-
let outer = bold(yellow(`${symbols['warning']} Found stale monitors\n`));
|
|
120
|
-
const inner = gray(`Pass --delete to remove all the stale monitors.`);
|
|
121
|
-
outer += indent(inner, ' ');
|
|
122
|
-
return outer;
|
|
123
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Elastic Synthetics Tests
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main, master]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [main, master]
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: '* 0 * * *'
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v2
|
|
14
|
+
- uses: actions/setup-node@v2
|
|
15
|
+
with:
|
|
16
|
+
node-version: 16
|
|
17
|
+
- run: npm install
|
|
18
|
+
- run: "SYNTHETICS_JUNIT_FILE='junit-synthetics.xml' npx @elastic/synthetics . --reporter=junit"
|
|
19
|
+
continue-on-error: true
|
|
20
|
+
- name: Publish Unit Test Results
|
|
21
|
+
uses: EnricoMi/publish-unit-test-result-action@v1.19
|
|
22
|
+
if: always()
|
|
23
|
+
with:
|
|
24
|
+
files: '**/junit-*.xml'
|
|
25
|
+
fail_on: 'test failures'
|
|
26
|
+
check_name: Elastic Synthetics Tests
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Get started with Elastic Synthetics!
|
|
2
|
+
|
|
3
|
+
Browse the directory structure here to see an example skeleton of an [Elastic Synthetics](https://www.elastic.co/observability/synthetic-monitoring) project.
|
|
4
|
+
Make sure to [read the docs](https://www.elastic.co/guide/en/observability/current/monitor-uptime-synthetics.html) as well if you're unfamiliar with Elastic Synthetics.
|
|
5
|
+
|
|
6
|
+
This directory was created with the command `npx @elastic/synthetics <target-directory>`, with `<target-directory>` being the name of the directory you'd like it to make.
|
|
7
|
+
You can always use this command to scafold new Synthetics projects.
|
|
8
|
+
|
|
9
|
+
Key places to look:
|
|
10
|
+
|
|
11
|
+
- The `synthetics.config.ts` file contains configuration for your project.
|
|
12
|
+
- The `journeys` directory contains both basic and more advanced examples of using synthetics. It tests a publicly hosted [Todos List](https://elastic.github.io/synthetics-demo/).
|
|
13
|
+
- The `.github` directory contains an example github action, demonstrating the use of a CI service for automatically running tests on merges and PR creation.
|
|
14
|
+
|
|
15
|
+
To run the tests locally, use the following command:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run test
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Curious to learn more? [Read the docs](https://www.elastic.co/guide/en/observability/current/monitor-uptime-synthetics.html) to learn about pushing configurations to an Elastic cloud stack and more.
|