Skip to content

feat: warn when a matcher property is an empty list - #1097

Merged
kgaughan merged 3 commits into
goss-org:masterfrom
vsolano9:feat/1095-warn-empty-matcher-list
Aug 6, 2026
Merged

feat: warn when a matcher property is an empty list#1097
kgaughan merged 3 commits into
goss-org:masterfrom
vsolano9:feat/1095-warn-empty-matcher-list

Conversation

@vsolano9

@vsolano9 vsolano9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Refs #1095. Follow-up to #1096, implementing what you asked for there:

I do think empty lists should produce a warning, even if they don't produce an error. It does smell like the kind of thing that somebody would only do by accident, but I don't think it's worth changing the existing behaviour.

So: warning, behaviour untouched.

What changed

isSetWarnEmpty sits next to isSet and wraps it. It warns when the property holds a list written out as empty, then returns exactly what isSet returned, so no matcher changes outcome.

All six properties that route through isSet are covered — command.stdout, command.stderr, file.contains, file.contents, http.headers, http.body:

$ goss -g vacuous.yaml validate
WARNING: vacuous_stderr_test: command.stderr is an empty list, which asserts nothing and always passes. Use "" to assert empty content, or remove it.
.

Total Duration: 0.018s
Count: 1, Failed: 0, Skipped: 0

Count: 1, Failed: 0 is unchanged from master — the check is still skipped and still passes.

The message follows the <id>: <type>.<property> shape deprecateAtoI already uses, and goes to stderr like the existing deprecation warnings, so stdout stays clean. Verified: -f json still parses as JSON, -f tap is unchanged, and integration-tests/test.sh captures stdout only, so nothing there sees the warning.

stderr: "" — the form the warning points at — produces no warning and correctly reports Count: 2, Failed: 1.

The thing you should decide

A gossfile generated by goss add file produces one warning per file. Measured, not guessed:

$ goss -g gen.yaml add file /etc/hosts
$ goss -g gen.yaml add file /etc/passwd
$ goss -g gen.yaml validate 2>&1 >/dev/null
WARNING: /etc/hosts: file.contents is an empty list, ...
WARNING: /etc/passwd: file.contents is an empty list, ...

That is the generator writing contents: [] (resource/file.go:125) and the warning correctly reporting that it asserts nothing. It is accurate, but it means the warning fires on goss's own output.

This repository's own fixtures hit it too — 8 empty-list matcher properties across testdata/passing.goss.yaml, testdata/failing.goss.yaml, goss-shared.yaml, goss-serve.yaml and goss-dummy.yaml would each print one line on stderr during an integration run. No test breaks, because they all read stdout. I left those files alone rather than editing fixtures to silence a warning about the thing they exercise.

If that noise is not acceptable, the fix is to stop goss add file writing contents: []. That is a generator behaviour change and it would need integration-tests/goss/*/goss-expected-q.yaml regenerating, so I did not fold it into this PR. Say the word and I'll do it as a separate one.

One more thing worth flagging: goss serve re-validates on cache miss, so a long-running server repeats the warning each time. That is exactly how the existing file.contains deprecation warning already behaves, so I kept it consistent rather than inventing a dedupe mechanism. Happy to add once-per-process dedupe if you'd rather.

Testing

resource/resource_test.go is new. It pins both halves of the contract: the warning fires only for an empty list, and the set/unset answer is byte-identical to isSet's for every input — nil, empty list, non-empty list, "", a string, and an empty map.

Both warning assertions were checked by disabling the warning and confirming they go red; TestIsSet* is otherwise vacuous. TestIsSetWarnEmptyNamesTheProperty also asserts exactly one line is written, so a future change that warns per element rather than per property fails.

gofmt -l, go vet ./..., go build ./..., go test ./... -count=1 all clean. npx markdownlint-cli2 "docs/**/*.md" reports 0 issues in 14 files, matching the docs workflow.

Docs: the two admonitions added in #1096 now say the warning exists and that generated gossfiles will trigger it, so the documentation still matches the behaviour.

AI assistance

This contribution was prepared with AI assistance. Every console block above is real output from the built binary on this branch, GOSS_USE_ALPHA=1, Go 1.26.5.


📚 Documentation preview 📚: https://goss--1097.org.readthedocs.build/en/1097/

A list of patterns is a list of conditions that must all hold, so an
empty list is zero conditions: isSet reports the property as absent, no
check is created, and the resource passes without asserting anything.
That is easy to write by accident and silent when you do.

Warn about it on stderr instead of failing. The behaviour is unchanged
on purpose. goss add file emits contents: [] to record that it captured
no content expectation, and empty lists appear in this repository's own
testdata and integration gossfiles, so rejecting them would invalidate
every gossfile goss has ever generated.

The warning covers all six properties that route through isSet:
command.stdout, command.stderr, file.contains, file.contents,
http.headers and http.body. It names the resource and property in the
same "<id>: <type>.<property>" shape as the existing deprecation
warnings, and goes to stderr like they do, so the text, JSON, TAP,
JUnit and nagios output on stdout is untouched.

Refs goss-org#1095

Signed-off-by: Victor Solano <victor.solanonunez@gmail.com>
@vsolano9

vsolano9 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

The red coverage check here is not this PR. It's a pre-existing flaky race, and I've split the fix out into #1098.

I assumed it was mine first and went looking. race detected during execution of test in the root package, and the stacks point at two serve tests sharing the log buffer, nothing near isSetWarnEmpty. So I ran the same command the coverage job runs against clean master fbc8318:

Branch DATA RACE
master, 8 runs 4
master, 12 more runs 7
#1098, 12 runs 0

master fails it more often than this branch does. Details and the full trace are in #1098.

Everything else here is green: build, lint, Lint Documentation, and the Read the Docs build.

If you merge #1098 first I'll rebase this one and the check should go green.

Picks up goss-org#1098 (serve-test log-buffer race fix), which is the cause of the
stale red `coverage` check on this PR's previous head 6a9d2dd.

Signed-off-by: Victor Solano <victor.solanonunez@gmail.com>
kgaughan
kgaughan previously approved these changes Aug 6, 2026

@kgaughan kgaughan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. There's a small change I'm hoping to add as part of some modernisation.

Comment thread resource/resource.go Outdated
@kgaughan
kgaughan merged commit 4a91642 into goss-org:master Aug 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants