@cloudbeat/atlas-cli 0.2.0 → 0.4.0
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 +52 -19
- package/dist/api.js +70 -18
- package/dist/cli.js +34 -6
- package/dist/commands/analyze.js +118 -0
- package/dist/commands/capacity.js +99 -0
- package/dist/commands/docs.js +57 -0
- package/dist/commands/files.js +18 -4
- package/dist/commands/plan.js +100 -0
- package/dist/commands/record.js +11 -1
- package/dist/commands/results.js +13 -7
- package/dist/commands/schema.js +86 -0
- package/dist/commands/skills.js +111 -0
- package/dist/commands/tests.js +73 -0
- package/dist/docs/agent-setup.md +109 -0
- package/dist/docs/agent-tasks.md +169 -0
- package/dist/docs/ai-agents.md +90 -0
- package/dist/docs/auth.md +74 -0
- package/dist/docs/automation.md +150 -0
- package/dist/docs/ci.md +105 -0
- package/dist/docs/clusters.md +48 -0
- package/dist/docs/commands.md +155 -0
- package/dist/docs/files.md +86 -0
- package/dist/docs/generators.md +52 -0
- package/dist/docs/getting-started.md +85 -0
- package/dist/docs/index.json +110 -0
- package/dist/docs/projects.md +50 -0
- package/dist/docs/recorder.md +143 -0
- package/dist/docs/results.md +79 -0
- package/dist/docs/running.md +80 -0
- package/dist/docs/skills.md +88 -0
- package/dist/docs/test-plans.md +92 -0
- package/dist/docs/troubleshooting.md +79 -0
- package/dist/plan.js +250 -0
- package/dist/skills/AGENTS.md +70 -0
- package/dist/skills/atlas-analyze/SKILL.md +104 -0
- package/dist/skills/atlas-correlate/SKILL.md +89 -0
- package/dist/skills/atlas-load-test/SKILL.md +154 -0
- package/dist/skills/atlas-record/SKILL.md +167 -0
- package/dist/skills/atlas-run/SKILL.md +109 -0
- package/dist/skills/atlas-test-plan/SKILL.md +281 -0
- package/package.json +5 -3
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# What an Agent Can Do
|
|
2
|
+
|
|
3
|
+
The whole lifecycle, from an empty project to a report you can send someone.
|
|
4
|
+
Each section below is a real thing to ask for, what the agent does about it, and
|
|
5
|
+
what it should ask you along the way.
|
|
6
|
+
|
|
7
|
+
## Find its bearings
|
|
8
|
+
|
|
9
|
+
> What can I load test here, and how much capacity do I have?
|
|
10
|
+
|
|
11
|
+
Before anything else, a well-behaved assistant establishes what it is looking
|
|
12
|
+
at: who it is signed in as, which account is active, which projects it can
|
|
13
|
+
reach, which test plans and data files those hold, what ran recently, and how
|
|
14
|
+
much capacity and usage allowance you have left.
|
|
15
|
+
|
|
16
|
+
That last part matters more than it sounds. Sizing a test without knowing the
|
|
17
|
+
fleet is how people ask for 50 machines on a 20-machine account, or blow a
|
|
18
|
+
monthly allowance on a warm-up run.
|
|
19
|
+
|
|
20
|
+
## Record a scenario
|
|
21
|
+
|
|
22
|
+
> Open our staging site, sign in as the demo user, add two items to the basket
|
|
23
|
+
> and check out. Turn that into a test plan.
|
|
24
|
+
|
|
25
|
+
The agent opens a **real, visible browser**. It reads each page as an
|
|
26
|
+
accessibility tree — the same structure a screen reader sees — so it clicks
|
|
27
|
+
"Add to basket" because that button exists, not because a selector was guessed.
|
|
28
|
+
It names each step *before* performing it, because those names become the rows
|
|
29
|
+
in your results report, and `Rome` is a useless row title.
|
|
30
|
+
|
|
31
|
+
You can watch the whole thing and take over whenever you like. For a password,
|
|
32
|
+
an MFA prompt, or a decision only you can make, the agent hands the window back,
|
|
33
|
+
you do that step, and it carries on recording.
|
|
34
|
+
|
|
35
|
+
Prefer to drive yourself? Say so, and it opens a plain recording session for you
|
|
36
|
+
to click through while it waits.
|
|
37
|
+
|
|
38
|
+
Export your cookies, or reuse a saved browser profile, and the recording starts
|
|
39
|
+
already signed in — see [Recording a Scenario](/recorder/). Never give an agent
|
|
40
|
+
a password to type.
|
|
41
|
+
|
|
42
|
+
## Turn the recording into a real test
|
|
43
|
+
|
|
44
|
+
This is the step people skip, and it is the difference between a load test and
|
|
45
|
+
an expensive replay.
|
|
46
|
+
|
|
47
|
+
A recording is a draft: it contains exactly what *you* did. The agent reads the
|
|
48
|
+
capture and works through it with you, stage by stage, asking rather than
|
|
49
|
+
deciding:
|
|
50
|
+
|
|
51
|
+
1. **Is the flow right?** The steps, their names, anything missing.
|
|
52
|
+
2. **Which recorded values should become test data?** The username and password
|
|
53
|
+
you typed. The search term. The product id that appears in three different
|
|
54
|
+
requests. If every simulated user sends the same ones, they collide on the
|
|
55
|
+
same session and hit the same cache — the application looks fast because it
|
|
56
|
+
is barely working. The agent proposes a CSV, the columns, and how many rows;
|
|
57
|
+
you say whether to generate them or supply real data. Atlas then divides
|
|
58
|
+
those rows between machines at run time, so no two users get the same row.
|
|
59
|
+
3. **What changes per session?** Session ids, CSRF tokens, cart ids — values the
|
|
60
|
+
*server* issued, which must be captured from an earlier response instead of
|
|
61
|
+
replayed. The recorder detects these with evidence, and the agent pins
|
|
62
|
+
anything it missed. See [Dynamic values](/recorder/#dynamic-values-are-handled).
|
|
63
|
+
4. **Do you need checks?** A `200` that returns a login page is a pass as far as
|
|
64
|
+
JMeter is concerned. Assertions on the responses that matter turn that into a
|
|
65
|
+
visible failure.
|
|
66
|
+
5. **Upload and smoke-run it.**
|
|
67
|
+
|
|
68
|
+
## Edit an existing plan
|
|
69
|
+
|
|
70
|
+
> Add a "search by postcode" step to our existing plan, and point it at staging.
|
|
71
|
+
|
|
72
|
+
The agent downloads the stored plan first — uploading replaces a file and there
|
|
73
|
+
is no version history — then makes the narrowest change that does the job:
|
|
74
|
+
recording a new scenario straight into the plan as an additional thread group,
|
|
75
|
+
or editing specific values in place.
|
|
76
|
+
|
|
77
|
+
For structural surgery it will tell you plainly that the JMeter GUI is the right
|
|
78
|
+
tool, rather than rewriting a plan nobody has the source for.
|
|
79
|
+
|
|
80
|
+
## Debug it locally, in seconds
|
|
81
|
+
|
|
82
|
+
If JMeter is installed on your machine, the agent can run a single user through
|
|
83
|
+
the plan locally before spending any Atlas capacity — the fastest way to confirm
|
|
84
|
+
a new step, an assertion or a data file actually works.
|
|
85
|
+
|
|
86
|
+
It knows the trick that makes this practical: recorded plans contain **think
|
|
87
|
+
time**, typically ten to thirty seconds between steps, which is correct for a
|
|
88
|
+
real load test and absurd for a debug run. The agent switches it off in a
|
|
89
|
+
throwaway copy, so a check that would have taken two minutes takes five seconds,
|
|
90
|
+
then restores it — your plan keeps its pauses, and nothing gets uploaded with
|
|
91
|
+
the think time missing.
|
|
92
|
+
|
|
93
|
+
It can also prove an assertion *fails* when it should, which is the only way to
|
|
94
|
+
know a check is doing anything at all.
|
|
95
|
+
|
|
96
|
+
## Check before you spend
|
|
97
|
+
|
|
98
|
+
> Will this plan actually run?
|
|
99
|
+
|
|
100
|
+
`atlas plan check` catches what otherwise surfaces as an empty dashboard an hour
|
|
101
|
+
later:
|
|
102
|
+
|
|
103
|
+
- **A data file the plan reads that the project does not have.** Every user in
|
|
104
|
+
that thread group dies before sending a request, so the group disappears from
|
|
105
|
+
your results with *no errors at all* while the rest look healthy.
|
|
106
|
+
- **A plan Atlas cannot attach its reporting to** — it runs, and reports nothing.
|
|
107
|
+
- **A broken structure, or no enabled thread group.**
|
|
108
|
+
- **Fixed user counts**, meaning more machines is the only way to scale it.
|
|
109
|
+
|
|
110
|
+
## Size and run it
|
|
111
|
+
|
|
112
|
+
> Run it with 500 users for ten minutes, ramped up over five.
|
|
113
|
+
|
|
114
|
+
Sizing is where load tests are most often wrong, in both directions. Each
|
|
115
|
+
machine runs the **whole** plan, so 100 users in the plan across 5 machines is
|
|
116
|
+
500 users, not 100. The agent does that arithmetic against your real fleet,
|
|
117
|
+
explains it, and confirms with you before starting anything larger than a smoke
|
|
118
|
+
test.
|
|
119
|
+
|
|
120
|
+
It smoke-runs first — one machine, a couple of users — and checks the result
|
|
121
|
+
contains actual data. A smoke run that finishes in seconds with nothing in it is
|
|
122
|
+
a broken plan, not a fast application, and catching that costs one minute
|
|
123
|
+
instead of twenty machine-minutes.
|
|
124
|
+
|
|
125
|
+
While the run is live it can report progress, and stop the test if you ask.
|
|
126
|
+
|
|
127
|
+
## Read the results
|
|
128
|
+
|
|
129
|
+
> How did it go? Where did it start to break?
|
|
130
|
+
|
|
131
|
+
Numbers are the easy part. The agent reports which steps degraded and at what
|
|
132
|
+
user count, what the errors actually say — with the real request and response,
|
|
133
|
+
not just a code — and how the run behaved over time rather than as one average.
|
|
134
|
+
|
|
135
|
+
It is also taught to distrust a clean-looking result. A test that measured
|
|
136
|
+
nothing looks *better* than one that worked: a missing thread group with zero
|
|
137
|
+
errors, a run that ended in seconds, or fast `200`s returning login pages. Those
|
|
138
|
+
are reported as failures of the test, not as performance.
|
|
139
|
+
|
|
140
|
+
## Wire it into CI
|
|
141
|
+
|
|
142
|
+
> Add a nightly load test to our pipeline and fail the build if p95 goes over
|
|
143
|
+
> 800ms.
|
|
144
|
+
|
|
145
|
+
The agent writes the pipeline step, using thresholds and exit codes rather than
|
|
146
|
+
a human reading a dashboard:
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
atlas run -p SHOP --jmx checkout.jmx --servers 4 \
|
|
150
|
+
--gate "error_rate<1,p95<800" --junit results.xml
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`0` passed · `1` a threshold was breached · `2` a usage or sign-in problem ·
|
|
154
|
+
`3` the run failed or Atlas was unreachable. JUnit output drops into whatever
|
|
155
|
+
already reports your test results. See [Running in CI](/cli/ci).
|
|
156
|
+
|
|
157
|
+
## What it should always ask
|
|
158
|
+
|
|
159
|
+
- Which project, and which plan when there is more than one
|
|
160
|
+
- How many users, for how long, over what ramp-up
|
|
161
|
+
- Fixed machines or a cluster
|
|
162
|
+
- Confirmation before the full run
|
|
163
|
+
- Whether to generate test data or use yours
|
|
164
|
+
|
|
165
|
+
And what it should never do without you: start a large run, stop someone else's
|
|
166
|
+
test, delete a file it did not just upload, or upload a plan it has not checked.
|
|
167
|
+
|
|
168
|
+
[The skills behind this →](/agents/skills) ·
|
|
169
|
+
[Build your own integration →](/agents/automation)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Atlas for AI Agents
|
|
2
|
+
|
|
3
|
+
**Describe the test. Let the agent build it.**
|
|
4
|
+
|
|
5
|
+
Load testing has always had a gap between wanting a test and having one. Someone
|
|
6
|
+
has to click through the flow, capture the requests, work out which values are
|
|
7
|
+
per-session tokens, wire up the data files, size the run, and then interpret a
|
|
8
|
+
report full of percentiles. It is a day of work for a thirty-second question:
|
|
9
|
+
*will this hold up on launch day?*
|
|
10
|
+
|
|
11
|
+
Atlas closes that gap. Every part of it — recording, test plans, data files,
|
|
12
|
+
machines, runs, results — is reachable through one command-line tool that speaks
|
|
13
|
+
JSON, and it ships with the guidance an AI coding assistant needs to use it
|
|
14
|
+
properly. Point your assistant at Atlas and ask in plain language:
|
|
15
|
+
|
|
16
|
+
> Record a checkout on our staging site, then run it with 500 users for ten
|
|
17
|
+
> minutes and tell me where it breaks.
|
|
18
|
+
|
|
19
|
+
It records the flow in a real browser, turns the recording into a genuine load
|
|
20
|
+
test, checks the plan will actually report, smoke-runs it, asks you to confirm
|
|
21
|
+
the real run, and comes back with what broke and at what point.
|
|
22
|
+
|
|
23
|
+
<div class="tip custom-block" style="padding-top: 8px">
|
|
24
|
+
|
|
25
|
+
New here? [Set it up](/agents/setup) in two commands, then see
|
|
26
|
+
[what it can do](/agents/capabilities).
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## Why this works with Atlas
|
|
31
|
+
|
|
32
|
+
**One tool, every surface.** The agent does not need infrastructure credentials,
|
|
33
|
+
a database, or your cloud account. Everything goes through the same CLI you use,
|
|
34
|
+
so your permissions, your account's quota and your machine limits apply exactly
|
|
35
|
+
as they do in the browser.
|
|
36
|
+
|
|
37
|
+
**Machine-readable by design.** Every command takes `--json`. Failures print
|
|
38
|
+
JSON on standard error, so clean output stays clean. `atlas schema --json`
|
|
39
|
+
describes the entire command tree, so an agent can discover the surface instead
|
|
40
|
+
of guessing at flags.
|
|
41
|
+
|
|
42
|
+
**It knows the traps.** Load testing fails quietly. A data file that was never
|
|
43
|
+
uploaded silently removes an entire thread group — with *zero* errors to explain
|
|
44
|
+
it. A plan whose structure defeats reporting runs perfectly and tells you
|
|
45
|
+
nothing. Fast responses that are really login pages look like excellent
|
|
46
|
+
performance. The bundled guidance teaches an assistant to recognise all of these
|
|
47
|
+
before you act on a number that means nothing.
|
|
48
|
+
|
|
49
|
+
**The documentation travels with it.** `atlas docs` prints this documentation
|
|
50
|
+
offline, so an agent in a sandbox or a CI container still has the manual.
|
|
51
|
+
|
|
52
|
+
## What you get
|
|
53
|
+
|
|
54
|
+
| | |
|
|
55
|
+
|---|---|
|
|
56
|
+
| **Recording without clicking** | The agent opens a real browser, reads the page as an accessibility tree, clicks through your flow and names each step — or hands the window to you for the parts only you can do, like a password or an MFA prompt. |
|
|
57
|
+
| **A real test, not a replay** | It spots the values every simulated user would otherwise repeat — credentials, search terms, product ids — and moves them into a data file, so you are testing your application rather than your cache. |
|
|
58
|
+
| **Plans that actually report** | Before anything runs, `atlas plan check` catches the three failures that produce an empty dashboard an hour later. |
|
|
59
|
+
| **Sizing you can defend** | It reads your real capacity and explains what 500 users means in machines, because each machine runs the whole plan. |
|
|
60
|
+
| **Results in sentences** | Not just p95 numbers: which step degraded, at what user count, and what the errors actually say. |
|
|
61
|
+
| **CI that fails honestly** | Pass/fail thresholds, JUnit output and exit codes, written into your pipeline by the same assistant. |
|
|
62
|
+
|
|
63
|
+
## Guardrails
|
|
64
|
+
|
|
65
|
+
An agent that can start a load test can spend money and put load on production.
|
|
66
|
+
The bundled guidance is explicit about this, and a good assistant will:
|
|
67
|
+
|
|
68
|
+
- **Confirm before any real run.** Machines are powered on for a test and billed
|
|
69
|
+
to your account. Smoke tests are cheap and encouraged; a 20-machine run is not
|
|
70
|
+
something to start on an assumption.
|
|
71
|
+
- **Never stop a run it did not start.** Someone else's test is someone else's.
|
|
72
|
+
- **Ask rather than guess** about the things that change the result: which
|
|
73
|
+
project, how many users, how long, ramp-up, fixed machines or a cluster.
|
|
74
|
+
- **Report what happened, not what should have.** Including failed thresholds, a
|
|
75
|
+
thread group that vanished, and its own uncertainty.
|
|
76
|
+
- **Leave your files as it found them.** It downloads before it edits, and it
|
|
77
|
+
restores anything it changed for debugging — think time included.
|
|
78
|
+
|
|
79
|
+
Everything an agent can do, you can do by hand with the same commands. Nothing
|
|
80
|
+
here is required, and nothing here is hidden from you.
|
|
81
|
+
|
|
82
|
+
## Which assistants
|
|
83
|
+
|
|
84
|
+
| Assistant | How it reads the guidance |
|
|
85
|
+
|---|---|
|
|
86
|
+
| **Claude Code** | Skills — loaded automatically when your request is about load testing |
|
|
87
|
+
| **GitHub Copilot, Cursor, Codex, Gemini CLI, Windsurf** | `AGENTS.md` in your project root |
|
|
88
|
+
| **Anything else** | `atlas schema --json`, `atlas docs`, and `--json` on every command |
|
|
89
|
+
|
|
90
|
+
[Set it up →](/agents/setup)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Signing In
|
|
2
|
+
|
|
3
|
+
## For everyday use
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
atlas login --url https://atlas.cloudbeat.io -u you@company.com
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
You'll be prompted for your password. The session lasts **8 hours**.
|
|
10
|
+
|
|
11
|
+
Credentials are stored in `~/.atlas/config.json`, readable only by you.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
atlas whoami # who am I, and in which account
|
|
15
|
+
atlas logout # forget the credential
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## For CI: API tokens
|
|
19
|
+
|
|
20
|
+
A password prompt is no use in a pipeline, and storing a human's password is
|
|
21
|
+
worse. Create an **API token** instead.
|
|
22
|
+
|
|
23
|
+
On your Atlas instance, go to **Profile → API tokens** and create one. The token
|
|
24
|
+
is shown **once** — copy it then.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
atlas login --token atlas_pat_...
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or, better in CI, pass it as an environment variable and don't store it at all:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
export ATLAS_TOKEN=atlas_pat_...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### What a token can and can't do
|
|
37
|
+
|
|
38
|
+
A token acts as **the person who created it**, with the same permissions and in
|
|
39
|
+
one fixed account. If that person's access is reduced or removed, the token
|
|
40
|
+
follows immediately.
|
|
41
|
+
|
|
42
|
+
Two things it deliberately **cannot** do:
|
|
43
|
+
|
|
44
|
+
- create more tokens
|
|
45
|
+
- change a password
|
|
46
|
+
|
|
47
|
+
So a leaked pipeline token can't mint replacements for itself or lock you out.
|
|
48
|
+
Revoking it on the Profile page stops it working at once.
|
|
49
|
+
|
|
50
|
+
If you belong to several accounts, switch to the one the pipeline should use
|
|
51
|
+
*before* creating the token. The token is fixed to whichever account was active
|
|
52
|
+
when it was made.
|
|
53
|
+
|
|
54
|
+
A token is a credential. Put it in your CI system's secret store, not in the
|
|
55
|
+
repository, and not in a build log.
|
|
56
|
+
|
|
57
|
+
## Settings and precedence
|
|
58
|
+
|
|
59
|
+
Command-line options win over environment variables, which win over the saved
|
|
60
|
+
configuration file.
|
|
61
|
+
|
|
62
|
+
| Variable | Meaning |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `ATLAS_URL` | your Atlas instance |
|
|
65
|
+
| `ATLAS_TOKEN` | API token |
|
|
66
|
+
| `ATLAS_PROJECT` | project to use when `--project` is omitted |
|
|
67
|
+
| `ATLAS_DEBUG` | set to any value to print full error details |
|
|
68
|
+
|
|
69
|
+
To avoid repeating yourself:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
atlas config set url https://atlas.cloudbeat.io
|
|
73
|
+
atlas config set project SHOP
|
|
74
|
+
```
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Building Your Own Integration
|
|
2
|
+
|
|
3
|
+
The same surfaces the bundled skills use are there for your own scripts, bots
|
|
4
|
+
and agents. No SDK, no separate API client: the CLI is the integration point,
|
|
5
|
+
and everything it does is scriptable.
|
|
6
|
+
|
|
7
|
+
## JSON everywhere
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
atlas projects --json
|
|
11
|
+
atlas capacity --json
|
|
12
|
+
atlas results SHOP-20260917-101500 --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Every command takes `--json`. On failure it prints the error as JSON on
|
|
16
|
+
**standard error**, so standard out stays parseable:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{"error":{"message":"Project 'SHOPP' not found","code":"not_found"}}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Exit codes are the contract, and they do not change with `--json`:
|
|
23
|
+
|
|
24
|
+
| Code | Meaning |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `0` | Success, and any thresholds passed |
|
|
27
|
+
| `1` | A `--gate` threshold was breached — the test ran, the numbers failed |
|
|
28
|
+
| `2` | A usage or authentication problem: bad flags, unknown project, not signed in |
|
|
29
|
+
| `3` | The run failed or timed out, or Atlas could not be reached |
|
|
30
|
+
|
|
31
|
+
`1` and `3` are deliberately distinct: a breached threshold is a result, an
|
|
32
|
+
unreachable server is not.
|
|
33
|
+
|
|
34
|
+
## Discovering the surface
|
|
35
|
+
|
|
36
|
+
Rather than hard-coding flags, read them:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
atlas schema --json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This returns every command, argument and option, with its description. Two
|
|
43
|
+
fields worth knowing: `takesValue` says whether the flag expects a value, and
|
|
44
|
+
`valueOptional` whether that value may be omitted. Neither means the flag itself
|
|
45
|
+
is mandatory.
|
|
46
|
+
|
|
47
|
+
## Documentation, offline
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
atlas docs # list the topics
|
|
51
|
+
atlas docs troubleshooting # print one
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The documentation is bundled inside the package, so it works with no network —
|
|
55
|
+
in CI, in a container, in a sandboxed agent.
|
|
56
|
+
|
|
57
|
+
## Checking a plan without running it
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
atlas plan check ./checkout.jmx -p SHOP --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Read-only and advisory: it never rewrites your plan. Useful as a pre-commit
|
|
64
|
+
hook or a pipeline step, because it exits non-zero when the plan would produce
|
|
65
|
+
no usable results.
|
|
66
|
+
|
|
67
|
+
## Driving the recorder from code
|
|
68
|
+
|
|
69
|
+
The recorder can be controlled step by step, which is what lets an agent click
|
|
70
|
+
through a flow. It is also a perfectly good scripting interface:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
atlas-rec start https://shop.example.com -o flow.jmx -n "Checkout"
|
|
74
|
+
atlas-rec snapshot # the page, as an accessibility tree
|
|
75
|
+
atlas-rec tx new "Search" # name the step that follows
|
|
76
|
+
atlas-rec click --role button --name "Search"
|
|
77
|
+
atlas-rec fill "laptop" --selector "#q"
|
|
78
|
+
atlas-rec wait --selector ".results"
|
|
79
|
+
atlas-rec state --full # everything captured so far
|
|
80
|
+
atlas-rec stop # writes the plan and the capture
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The window stays visible and a person can click in the same session — the two
|
|
84
|
+
mix freely, so a script can pause for a human to sign in and then carry on.
|
|
85
|
+
|
|
86
|
+
The control channel is **local to your machine**: it listens on the loopback
|
|
87
|
+
interface, on an ephemeral port, and requires a per-session token that is kept
|
|
88
|
+
out of the process list. It only accepts commands while a recording you started
|
|
89
|
+
is open.
|
|
90
|
+
|
|
91
|
+
Afterwards, a capture can be re-read and rebuilt without recording again:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
atlas-rec inspect flow.capture.json # transactions, hosts, response codes
|
|
95
|
+
atlas-rec suggest flow.capture.json # per-session values, with evidence
|
|
96
|
+
atlas-rec generate flow.capture.json -o flow.jmx --correlations rules.json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The same capture always produces the same plan, so regenerating is safe to
|
|
100
|
+
repeat and easy to review.
|
|
101
|
+
|
|
102
|
+
## Authentication for automation
|
|
103
|
+
|
|
104
|
+
Use an API token, never a password:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
export ATLAS_TOKEN=atlas_pat_...
|
|
108
|
+
export ATLAS_URL=https://atlas.cloudbeat.io
|
|
109
|
+
export ATLAS_PROJECT=SHOP
|
|
110
|
+
atlas run --servers 4 --gate "error_rate<1,p95<800" --junit results.xml
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A token acts as its creating user, in one account. Revoking it takes effect
|
|
114
|
+
immediately, and a token cannot mint further tokens or change a password — so a
|
|
115
|
+
leaked CI credential cannot entrench itself. See
|
|
116
|
+
[Signing In](/cli/authentication).
|
|
117
|
+
|
|
118
|
+
## A worked example
|
|
119
|
+
|
|
120
|
+
Everything together — gate a deployment on a load test:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
#!/usr/bin/env bash
|
|
124
|
+
set -euo pipefail
|
|
125
|
+
|
|
126
|
+
# Refuse to run a plan that could not report
|
|
127
|
+
atlas plan check -p SHOP --jmx checkout.jmx --json >/dev/null
|
|
128
|
+
|
|
129
|
+
# `|| rc=$?` keeps `set -e` from aborting on a breached threshold, which is a
|
|
130
|
+
# result we want to act on rather than a crash
|
|
131
|
+
rc=0
|
|
132
|
+
atlas run -p SHOP --jmx checkout.jmx --servers 4 \
|
|
133
|
+
--args "-Jthreads=125 -Jrampup=300" \
|
|
134
|
+
--gate "error_rate<1,p95<800" \
|
|
135
|
+
--junit results.xml --json > run.json || rc=$?
|
|
136
|
+
|
|
137
|
+
case $rc in
|
|
138
|
+
0) echo "passed: $(jq -r .testId run.json)" ;;
|
|
139
|
+
1) echo "thresholds breached"; jq '.gates[] | select(.passed | not)' run.json; exit 1 ;;
|
|
140
|
+
*) echo "the test did not run (exit $rc)"; exit "$rc" ;;
|
|
141
|
+
esac
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
With `--wait` — which `--gate` and `--junit` imply — the JSON on standard out
|
|
145
|
+
carries `testId`, `state`, `durationSec`, the overall figures and every gate
|
|
146
|
+
result. It is written **before** a breached threshold sets the exit code, so
|
|
147
|
+
`run.json` is complete either way.
|
|
148
|
+
|
|
149
|
+
[Running in CI](/cli/ci) has the pipeline-ready version, including GitHub
|
|
150
|
+
Actions.
|
package/dist/docs/ci.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Running in CI
|
|
2
|
+
|
|
3
|
+
The point of running Atlas from CI is to catch a performance regression the same
|
|
4
|
+
way you catch a failing unit test — automatically, on the build that caused it.
|
|
5
|
+
|
|
6
|
+
## A complete example
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
export ATLAS_URL=https://atlas.cloudbeat.io
|
|
10
|
+
export ATLAS_TOKEN=atlas_pat_...
|
|
11
|
+
|
|
12
|
+
# Only if the plan or its data live in this repository and may have changed.
|
|
13
|
+
atlas files upload -p SHOP ./checkout.jmx ./data/users.csv
|
|
14
|
+
|
|
15
|
+
atlas run -p SHOP --jmx checkout.jmx --servers 5 \
|
|
16
|
+
--gate "error_rate<1,p95<2000" \
|
|
17
|
+
--junit results.xml
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
If your test plan is maintained in Atlas rather than in the repository, drop the
|
|
21
|
+
upload step — the run command works on its own.
|
|
22
|
+
|
|
23
|
+
## Pass/fail thresholds
|
|
24
|
+
|
|
25
|
+
`--gate` fails the command when a threshold is breached, checked against the
|
|
26
|
+
run's overall totals.
|
|
27
|
+
|
|
28
|
+
| Metric | Meaning |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `error_rate` | percentage of failed requests |
|
|
31
|
+
| `avg` | average response time, ms |
|
|
32
|
+
| `p90`, `p95`, `p99` | percentile response times, ms |
|
|
33
|
+
| `max` | slowest response, ms |
|
|
34
|
+
| `throughput` | requests per second |
|
|
35
|
+
| `requests` | total requests |
|
|
36
|
+
|
|
37
|
+
Use `<`, `<=`, `>` or `>=`. Separate several with commas, or repeat `--gate`.
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
--gate "error_rate<1,p95<2000,throughput>50"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Setting a gate implies `--wait` — there is nothing to check until the test has
|
|
44
|
+
finished.
|
|
45
|
+
|
|
46
|
+
`error_rate` and a percentile. Averages hide the tail: a p95 catches the slow
|
|
47
|
+
requests a handful of users actually felt, which an average smooths away.
|
|
48
|
+
|
|
49
|
+
## Exit codes
|
|
50
|
+
|
|
51
|
+
| Code | Meaning |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `0` | the test ran and every threshold passed |
|
|
54
|
+
| `1` | the test ran but a `--gate` threshold was breached |
|
|
55
|
+
| `2` | something was wrong with the request — bad option, unknown project, not signed in |
|
|
56
|
+
| `3` | the test failed or timed out, or the server could not be reached |
|
|
57
|
+
|
|
58
|
+
The distinction that matters: **`1` means your system was too slow, `2` and `3`
|
|
59
|
+
mean the test never produced a verdict.** Treating them the same makes a broken
|
|
60
|
+
pipeline look like a performance regression.
|
|
61
|
+
|
|
62
|
+
## JUnit report
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
atlas run -p SHOP --servers 5 --junit results.xml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Writes a standard JUnit file with one test case per threshold, so CI shows each
|
|
69
|
+
one as a separate pass or fail. The run's headline numbers are included as
|
|
70
|
+
properties. Point your CI's test reporter at it and gates appear alongside your
|
|
71
|
+
other tests.
|
|
72
|
+
|
|
73
|
+
## Example: GitHub Actions
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
- name: Load test
|
|
77
|
+
env:
|
|
78
|
+
ATLAS_URL: https://atlas.cloudbeat.io
|
|
79
|
+
ATLAS_TOKEN: ${{ secrets.ATLAS_TOKEN }}
|
|
80
|
+
run: |
|
|
81
|
+
npm install -g @cloudbeat/atlas-cli
|
|
82
|
+
atlas run -p SHOP --servers 5 \
|
|
83
|
+
--gate "error_rate<1,p95<2000" \
|
|
84
|
+
--junit results.xml
|
|
85
|
+
|
|
86
|
+
- name: Publish results
|
|
87
|
+
if: always()
|
|
88
|
+
uses: actions/upload-artifact@v4
|
|
89
|
+
with:
|
|
90
|
+
name: load-test
|
|
91
|
+
path: results.xml
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Things worth knowing
|
|
95
|
+
|
|
96
|
+
**Load tests take minutes, not seconds.** Give the job a generous timeout, and
|
|
97
|
+
consider running it on a schedule or on merges to main rather than on every
|
|
98
|
+
push.
|
|
99
|
+
|
|
100
|
+
**Machines may be busy.** If another test holds the generators you asked for,
|
|
101
|
+
your run is queued and starts when they free up. Set `--timeout` to bound how
|
|
102
|
+
long you're willing to wait.
|
|
103
|
+
|
|
104
|
+
**A queued or failed run is not a regression.** That's the exit-code distinction
|
|
105
|
+
above — don't let a `3` open a performance bug.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Clusters
|
|
2
|
+
|
|
3
|
+
A **cluster** is elastic capacity: instead of fixed machines that sit there
|
|
4
|
+
between tests, units are created when a test starts and destroyed when it ends.
|
|
5
|
+
|
|
6
|
+
You pay for what a test uses, and you're not limited by how many machines you
|
|
7
|
+
happened to set up in advance.
|
|
8
|
+
|
|
9
|
+
## When to use one
|
|
10
|
+
|
|
11
|
+
Use a cluster when your load varies a lot between tests, or when you want a
|
|
12
|
+
large run occasionally without keeping that capacity around. Use fixed
|
|
13
|
+
[servers](/generators/adding) when you want predictable, always-available
|
|
14
|
+
machines — or when your test needs to come from a specific network location.
|
|
15
|
+
|
|
16
|
+
## Setting one up
|
|
17
|
+
|
|
18
|
+
A cluster runs on a Docker host you provide. Atlas talks to it through a small
|
|
19
|
+
**controller** you install on that host, which connects outbound — so the host
|
|
20
|
+
needs no inbound access, exactly like a load generator.
|
|
21
|
+
|
|
22
|
+
Go to **Fleet → Clusters**, create a cluster, and run the install command it
|
|
23
|
+
gives you on your Docker host. When the controller connects, the cluster shows
|
|
24
|
+
as ready.
|
|
25
|
+
|
|
26
|
+
## Running on a cluster
|
|
27
|
+
|
|
28
|
+
On the **Run Test** tab choose **Cluster** instead of Servers, and say how many
|
|
29
|
+
units you want:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
atlas run -p SHOP --cluster my-cluster --units 10
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Each unit is one JMeter instance, equivalent to one load generator. Ten units
|
|
36
|
+
running a 100-thread plan is 1,000 concurrent users.
|
|
37
|
+
|
|
38
|
+
## While it runs
|
|
39
|
+
|
|
40
|
+
Units register themselves as they come up, then the test deploys and starts as
|
|
41
|
+
usual. When the test finishes, every unit is destroyed.
|
|
42
|
+
|
|
43
|
+
If a run ends unexpectedly, check the Clusters tab to confirm nothing was left
|
|
44
|
+
behind.
|
|
45
|
+
|
|
46
|
+
Clusters are newer than fixed servers. If a run needs to be reliable — a
|
|
47
|
+
scheduled regression test, a customer demo — fixed machines are the safer
|
|
48
|
+
choice today.
|