Skip to content

Commit e98c3aa

Browse files
authored
Add Support for Testing Golden Snapshots (#939)
* backup * backup * backup * support colorized diffs * support colorized diffs * golden snapshots * validate test-cases schema * validate test-cases schema * Update schema path * Update schema path * try to use script for tty * fix for workingn with pty on GHA * remove script hack * colorize unified diff * Fix more snapshots * add readme * update snaphots and test cases * disable snapshots on version check * update match patterns * change logs level * set github token * pass github token to step * fix windows tests * tweak git attributes and add empty dir testing * add empty dir testing, update docs * remove debug command * fix regex for windows * pass GITHUB_TOKEN on tests * add skip conditions * update docs, fix errors with workflows and tests * reword
1 parent 4ab1b75 commit e98c3aa

File tree

64 files changed

+1552
-104
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1552
-104
lines changed

.editorconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22
insert_final_newline = true
33
end_of_line = lf
44

5+
# Binary files (override to ensure no text-related rules are applied)
6+
[*.{png,jpg,gif,svg,pdf,ai,eps,mp4}]
7+
insert_final_newline = false
8+
end_of_line = unset
9+
indent_style = unset
10+
indent_size = unset
11+
12+
# Override for machine generated binary HTML files in Screengrabs directory
13+
[website/src/components/Screengrabs/**/*.html]
14+
insert_final_newline = false
15+
end_of_line = unset
16+
indent_style = unset
17+
indent_size = unset
18+
19+
# Override for machine generated binary files in tests/snapshots directory for golden snapshots
20+
[test/snapshots/**/*.golden]
21+
insert_final_newline = false
22+
end_of_line = unset
23+
indent_style = unset
24+
indent_size = unset
25+
526
# Override for Makefile
627
[{Makefile,makefile,GNUmakefile}]
728
indent_style = tab

.gitattributes

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ docs linguist-documentation=true
66
# Screengrabs are binary HTML files that are automatically generated
77
website/src/components/Screengrabs/**/*.html linguist-generated=true binary
88

9+
# Golden snapshots should be treated a raw output to prevent line-ending conversions
10+
tests/snapshots/**/*.golden linguist-generated=true -text
11+
912
# Mark binary files to prevent normalization
1013
*.png binary
1114
*.svg binary
@@ -16,3 +19,8 @@ website/src/components/Screengrabs/**/*.html linguist-generated=true binary
1619
*.eps binary
1720
*.ansi binary
1821
*.mp4 binary
22+
23+
# Reduce merge conflicts that can occur when go.mod and go.sum files are updated
24+
# Run `go mod tidy` to update the go.sum file
25+
go.sum linguist-generated=true merge=union
26+
go.mod linguist-generated=true merge=union

.github/workflows/test.yml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ jobs:
7272
path: |
7373
./build/
7474
75+
tidy:
76+
name: Tidy Go Modules
77+
runs-on: ubuntu-latest
78+
steps:
79+
- name: Check out code into the Go module directory
80+
uses: actions/checkout@v4
81+
82+
- name: Set up Go
83+
uses: actions/setup-go@v5
84+
with:
85+
go-version-file: "go.mod"
86+
id: go
87+
88+
- uses: j0hnsmith/go-mod-check@v1
89+
with:
90+
working-directory: ${{ github.workspace }}
91+
# optional, only if you're happy to have `replace ` lines in your go.mod file
92+
skip-replace-check: true
93+
7594
# run acceptance tests
7695
test:
7796
name: Acceptance Tests
@@ -140,8 +159,23 @@ jobs:
140159
run: |
141160
make deps
142161
162+
# Enable this after merging test-cases
163+
# Only seems to work with remote schema files
164+
#- name: Validate YAML Schema for Test Cases
165+
# uses: InoUno/[email protected]
166+
# with:
167+
# root: "tests/test-cases"
168+
# schemaMapping: |
169+
# {
170+
# "schema.json": [
171+
# "**/*.yaml"
172+
# ]
173+
# }
174+
143175
- name: Acceptance tests
144176
timeout-minutes: 10
177+
env:
178+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
145179
run: make testacc
146180

147181
docker:
@@ -352,6 +386,8 @@ jobs:
352386
- name: Run tests in ${{ matrix.demo-folder }} for ${{ matrix.flavor.target }}
353387
working-directory: ${{ matrix.demo-folder }}
354388
if: matrix.flavor.target == 'linux' || matrix.flavor.target == 'macos'
389+
env:
390+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
355391
run: |
356392
atmos test
357393
@@ -369,6 +405,8 @@ jobs:
369405
working-directory: ${{ matrix.demo-folder }}
370406
if: matrix.flavor.target == 'windows'
371407
shell: pwsh
408+
env:
409+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
372410
run: |
373411
atmos test
374412
@@ -446,7 +484,7 @@ jobs:
446484
- name: Check out code
447485
uses: actions/checkout@v4
448486

449-
- name: Validate YAML Schema
487+
- name: Validate YAML Schema for Stacks
450488
uses: InoUno/[email protected]
451489
with:
452490
root: "examples/${{ matrix.demo-folder }}/stacks"

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"yaml.customTags": [
3+
"!not scalar"
4+
],
5+
"[mdx]": { "editor.defaultFormatter": null, "editor.formatOnSave": false },
6+
}

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# This works because `go list ./...` excludes vendor directories by default in modern versions of Go (1.11+).
22
# No need for grep or additional filtering.
33
TEST ?= $$(go list ./...)
4+
TESTARGS ?=
45
SHELL := /bin/bash
56
#GOOS=darwin
67
#GOOS=linux

cmd/docs.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ var docsCmd = &cobra.Command{
116116

117117
// Opens atmos.tools docs if no component argument is provided
118118
var err error
119+
120+
if os.Getenv("GO_TEST") == "1" {
121+
u.LogDebug(atmosConfig, "Skipping browser launch in test environment")
122+
return // Skip launching the browser
123+
}
124+
119125
switch runtime.GOOS {
120126
case "linux":
121127
err = exec.Command("xdg-open", atmosDocsURL).Start()

cmd/version.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ var versionCmd = &cobra.Command{
2828
u.LogErrorAndExit(schema.AtmosConfiguration{}, err)
2929
}
3030

31-
u.PrintMessage(fmt.Sprintf("\U0001F47D Atmos %s on %s/%s", version.Version, runtime.GOOS, runtime.GOARCH))
31+
atmosIcon := "\U0001F47D"
32+
33+
u.PrintMessage(fmt.Sprintf("%s Atmos %s on %s/%s", atmosIcon, version.Version, runtime.GOOS, runtime.GOARCH))
3234
fmt.Println()
3335

3436
if checkFlag {
@@ -45,7 +47,10 @@ var versionCmd = &cobra.Command{
4547
}
4648
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
4749
currentRelease := strings.TrimPrefix(version.Version, "v")
48-
if latestRelease != currentRelease {
50+
51+
if latestRelease == currentRelease {
52+
u.PrintMessage(fmt.Sprintf("You are running the latest version of Atmos (%s)", latestRelease))
53+
} else {
4954
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
5055
}
5156
}

go.mod

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/exec/vendor_component_utils.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"github.com/cloudposse/atmos/pkg/schema"
1717
u "github.com/cloudposse/atmos/pkg/utils"
1818
"github.com/hairyhenderson/gomplate/v3"
19-
"github.com/mattn/go-isatty"
2019
cp "github.com/otiai10/copy"
20+
"golang.org/x/term"
2121
)
2222

2323
// findComponentConfigFile identifies the component vendoring config file (`component.yaml` or `component.yml`)
@@ -359,5 +359,7 @@ func ExecuteComponentVendorInternal(
359359

360360
// CheckTTYSupport checks if stdout supports TTY for displaying the progress UI.
361361
func CheckTTYSupport() bool {
362-
return isatty.IsTerminal(os.Stdout.Fd())
362+
fd := int(os.Stdout.Fd())
363+
isTerminal := term.IsTerminal(fd)
364+
return isTerminal
363365
}

tests/README.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Tests
2+
3+
We have automated tests in packages, as well as standalone tests in this directory.
4+
5+
Smoke tests are implemented to verify the basic functionality and expected behavior of the compiled `atmos` binary, simulating real-world usage scenarios.
6+
7+
```shell
8+
├── cli_test.go # Responsible for smoke testing
9+
├── fixtures/
10+
│ ├── components/
11+
│ │ └── terraform/ # Components that are conveniently reused for tests
12+
│ ├── scenarios/ # Test scenarios consisting of stack configurations (valid & invalid)
13+
│ │ ├── complete/ # Advanced stack configuration with both broken and valid stacks
14+
│ │ ├── metadata/ # Test configurations for `metadata.*`
15+
│ │ └── relative-paths/ # Test configurations for relative imports
16+
│ └── schemas/ # Schemas used for JSON validation
17+
├── snapshots/ # Golden snapshots (what we expect output to look like)
18+
│ ├── TestCLICommands.stderr.golden
19+
│ └── TestCLICommands_which_atmos.stdout.golden
20+
└── test-cases/
21+
├── complete.yaml
22+
├── core.yaml
23+
├── demo-custom-command.yaml
24+
├── demo-stacks.yaml
25+
├── demo-vendoring.yaml
26+
├── metadata.yaml
27+
├── relative-paths.yaml
28+
└── schema.json # JSON schema for validation
29+
30+
```
31+
32+
## Test Cases
33+
34+
Our convention is to implement a test-case configuration file per scenario. Then place all smoke tests related to that scenario in the file.
35+
36+
### Environment Variables
37+
38+
The tests will automatically set some environment variables:
39+
40+
- `GO_TEST=1` is always set, so commands in atmos can disable certain functionality during tests
41+
- `TERM` is set when `tty: true` to emulate a proper terminal
42+
43+
### Flags
44+
45+
To regenerate ALL snapshots pass the `-regenerate-snaphosts` flag.
46+
47+
> ![WARNING]
48+
>
49+
> #### This will regenerate all the snapshots
50+
>
51+
> After regenerating, make sure to review the differences:
52+
>
53+
> ```shell
54+
> git diff tests/snapshots
55+
> ```
56+
57+
To regenerate the snapshots for a specific test, just run:
58+
59+
(replace `TestCLICommands/check_atmos_--help_in_empty-dir` with your test name)
60+
61+
```shell
62+
go test ./tests -v -run 'TestCLICommands/check_atmos_--help_in_empty-dir' -timeout 2m -regenerate-snapshots
63+
```
64+
65+
After generating new golden snapshots, don't forget to add them.
66+
67+
```shell
68+
git add tests/snapshots/*
69+
```
70+
71+
### Example Configuration
72+
73+
We support an explicit type `!not` on the `expect.stdout` and `expect.stderr` sections (not on `expect.diff`)
74+
75+
Snapshots are enabled by setting the `snapshots` flag, and using the `expect.diff` to ignore line-level differences. If no differences are expected, use an empty list. Note, things like paths will change between local development and CI, so some differences are often expected.
76+
77+
We recommend testing incorrect usage with `expect.exit_code` of non-zero. For example, passing unsupported arguments.
78+
79+
```yaml
80+
# yaml-language-server: $schema=schema.json
81+
82+
tests:
83+
- name: atmos circuit-breaker
84+
description: > # Friendly description of what this test is verifying
85+
Ensure atmos breaks the infinite loop when shell depth exceeds maximum (10).
86+
87+
enabled: true # Whether or not to enable this check
88+
89+
skip: # Conditions when to skip
90+
os: !not windows # Do not run on Windows (e.g. PTY not supported)
91+
# Use "darwin" for macOS
92+
# Use "linux" for Linux ;)
93+
94+
snapshot: true # Enable golden snapshot. Use together with `expect.diff`
95+
96+
workdir: "fixtures/scenarios/complete/" # Location to execute command
97+
env:
98+
SOME_ENV: true # Set an environment variable called "SOME_ENV"
99+
command: "atmos" # Command to run
100+
args: # Arguments or flags passed to command
101+
- "help"
102+
103+
expect: # Assertions
104+
diff: [] # List of expected differences
105+
stdout: # Expected output to stdout or TTY. All TTY output is directed to stdout
106+
stderr: # Expected output to stderr;
107+
- "^$" # Expect no output
108+
exit_code: 0 # Expected exit code
109+
```

0 commit comments

Comments
 (0)