Skip to content

Add marks parameter for subset test selection#1054

Open
dukelion wants to merge 3 commits into
goss-org:masterfrom
dukelion:feature/marks-parameter
Open

Add marks parameter for subset test selection#1054
dukelion wants to merge 3 commits into
goss-org:masterfrom
dukelion:feature/marks-parameter

Conversation

@dukelion
Copy link
Copy Markdown

@dukelion dukelion commented Apr 17, 2026

Add marks parameter for subset test selection

Summary

This PR introduces a marks feature that allows users to tag resources and run only specific subsets of tests, similar to pytest's -m flag. This enables more flexible test workflows in CI/CD and local development.

Changes

Core Feature:

  • Added Marks []string field to all 16 resource types (addr, command, dns, file, gossfile, group, http, interface, kernel_param, matching, mount, package, port, process, service, user)
  • Added --marks and --exclude-marks CLI flags for validate and serve commands
  • Added ?marks= and ?exclude_marks= query parameters to HTTP endpoints
  • Added --marks flag to goss add and goss autoadd commands for tagging new resources

Infrastructure:

  • Thread-safe skip-state handling for concurrent HTTP requests
  • Cache isolation by marks (resources filtered by marks don't pollute cache)
  • Debug logging for mark filter summary (visible with -L DEBUG)

Usage

# goss.yaml
file:
  /etc/nginx/nginx.conf:
    exists: true
    marks:
      - nginx
      - config

port:
  tcp:80:
    listening: true
    marks:
      - nginx

command:
  echo test:
    exit-status: 0
# Run only nginx-related tests
goss validate --marks nginx

# Run all tests EXCEPT config tests
goss validate --exclude-marks config

# HTTP endpoint with marks
curl "http://localhost:8080/healthz?marks=nginx"

Testing

  • Unit tests added for mark filtering, config parsing, and HTTP endpoint behavior
  • All existing tests pass: go test -race -count=3 ./...
  • Tested serve-mode with concurrent requests using different marks

Related

  • This PR includes the logger interface refactor (prerequisite for safe concurrent access)
  • Closes the gap for users wanting selective test execution without maintaining multiple goss files

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

This change introduces a minimal util.Logger interface (Printf, Fatalf) as
a first step toward decoupling goss from the standard library's global log
package. It addresses some friction reported in goss-org#544 around using goss as a
library, and provides a path toward resolving goss-org#991 where log level filtering
doesn't catch all messages.

What this improves:
- Tests can now run with t.Parallel() without racing on log.SetOutput;
  TestLogger captures output per-test with goroutine-safe buffer
- Library consumers can inject custom log sinks via util.WithLogger(),
  including filtered loggers that could address goss-org#991
- Data races are fixed in: color.NoColor (sync.Once), store.go globals
  (RWMutex), and format.UseStringerRepresentation (sync.Once)

The approach keeps most API signatures stable - core functions return
warnings as values and edge layers handle logging. WriteJSON now returns
(string, error) to surface its warning message, which is the one public
API change.

New files:
- util/logger.go: interface and DefaultLogger/TestLogger implementations
- util/logger_test.go: unit tests including concurrent write coverage
- util/color_init.go: shared InitNoColor for race-free color disable

This doesn't fully resolve goss-org#544 (os.Exit remains in some paths) or goss-org#991
(a filtered logger would need to be provided), but it removes blockers
and provides seams for both library embeddability and log control.
Adds a new top-level 'marks' field ([]string) on all resource types and
CLI/HTTP filtering options. Addresses goss-org#544 (library usage improvements)
and provides foundation for goss-org#991 (log level filtering).

Usage:
  goss validate --marks critical,fast
  goss validate --exclude-marks slow,flaky
  goss serve --marks critical  # overridable via ?marks= query param

Backward Compatibility:
- Resources without marks run by default (existing gossfiles unaffected)
- Empty marks omitted from JSON output to avoid schema churn
- When filters exclude all tests, goss exits 0 with "all skipped" output,
  consistent with DisabledResourceTypes behavior

Why this matters:
- Selective alerting: run only critical checks in production
- Incident response: filter by category (network, storage, etc.)
- Flaky test quarantine: exclude known-broken tests from CI gates
- Resource constraints: skip memory/CPU-heavy checks under pressure

Filter semantics:
- --marks: include only resources with at least one matching mark
- --exclude-marks: skip resources with any matching mark
- Inclusion evaluated before exclusion when both specified

Implementation highlights:
- Cache keys encode mark filter to prevent cross-contamination
- Query params override server-config without mutating shared state
- Skip-state snapshot/restore under gossMu for serve-mode safety
- Marks preserved across gossfile re-parses (with Title/Meta)

Tests: 382 lines across marks_test.go, validate_marks_test.go,
serve_marks_test.go, config_test.go covering round-trip serialization,
filter logic, HTTP endpoint, cache isolation, and concurrency safety.
- Add SetMarks() to ResourceRead interface (all 16 resource types)
- goss add/autoadd --marks flag for auto-tagging new resources
- Debug logging for mark filter summary when -L DEBUG set
- README section on marks usage with CLI and HTTP examples

The --marks flag on add commands only applies to newly created
resources; existing marks in the gossfile are preserved.
@dukelion dukelion requested a review from aelsabbahy as a code owner April 17, 2026 17:07
Comment thread cmd/goss/goss.go
Value: 50,
EnvVar: "GOSS_MAX_CONCURRENT",
},
cli.StringFlag{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just an FYI: if/when #1060 is merged, you'll have some merge conflicts. The fixes are easy, as it's mostly just a matter of turning the the flag object into references and updating the indentation.

I don't think I've potentially messed anything else up for you though.

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