Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V4 new #814

Merged
merged 43 commits into from
Jul 19, 2023
Merged

V4 new #814

merged 43 commits into from
Jul 19, 2023

Conversation

aelsabbahy
Copy link
Member

@aelsabbahy aelsabbahy commented Jun 25, 2023

Checklist
  • make test-all (UNIX) passes. CI will also test this
  • unit and/or integration tests are included (if applicable)
  • documentation is changed or added (if applicable)

Description of change

Overview

This PR is a combination of v4 changes + a bunch of misc fixes/additions. My hope is to get this released sooner rather than later so future PRs/changes can be smaller and incremental.

The major changes with v4 is the ability to compare different types and more advanced string matching

note: Manual has been updated to document most (if not all) new matchers, also testdata/ folder has ~80% coverage of the matcher language.

For example:

command:
  echo_test:
    # command that outputs JSON, but this could be anything, http response, command output, etc
    exec: |
      echo '{"string_value": "15"}'
    exit-status: 0
    stdout:
      # advanced string parsing
      gjson:
        # extract "string_value"
        string_value:
          and:
            # The value is numerically <= 20 (auto type conversion)
            - le: 20
            # The value is numerically 15
            - 15
            # Equal does a strict check, the types have to match, hence string_value is "15" but not 15
            - equal: "15"
            - not: {equal: 15}

This conversion also allows treating an io.Reader (memory efficient line-by-line parsing) as a whole string (when compared with a string). This has the benefit of showing the full command output, which was a long-requested feature. For example:

$ cat goss.yaml
command:
  echo_test:
    exec: |
      echo 'hello world'
    exit-status: 0
    stdout: |
      goodbye world

$ goss v
.F

Failures/Skipped:

Command: echo_test: stdout:
Expected
    "hello world\n"
to equal
    "goodbye world\n"

Total Duration: 0.001s
Count: 2, Failed: 1, Skipped: 0

Changes

Decisions

Should -o include_raw be enabled by default, and the option becomes -o exclude_raw

$  cat goss.yaml
command:
  echo_test:
    exec: |
      echo '{"string_value": "15"}'
    exit-status: 0
    stdout:
      gjson:
        string_value:
          le: 5

Without include_raw:

$ goss v
.F

Failures/Skipped:

Command: echo_test: stdout:
Expected
    15
to be numerically le
    5
the transform chain was
    [{"gjson":{"Path":"string_value"}},{"to-numeric":{}}]

Total Duration: 0.001s
Count: 2, Failed: 1, Skipped: 0

With -o include_raw:

$ goss v -o include_raw
.F

Failures/Skipped:

Command: echo_test: stdout:
Expected
    15
to be numerically le
    5
the transform chain was
    [{"gjson":{"Path":"string_value"}},{"to-numeric":{}}]
the raw value was
    "{\"string_value\": \"15\"}\n"

Total Duration: 0.001s
Count: 2, Failed: 1, Skipped: 0

reverted (defer to later)

These were changes living on the v4 branch. However, they are either bad fixes, or need more polish before release

  • Changed: http.headers from io.reader -> array
    • This is a good discussion point on whether headers should be treated like an io.Reader or array. There are pros/cons to this.. however, I'm avoiding the breaking change for now.
  • Changed: Convert headers to lowercase. HTTP Header X-XSS-Protection does not match  #760
  • Changed: Migrate from go-ps to gopsutil for better process detection (Migrate from go-ps to gopsutil for better process detection #597)
    • I was hoping this woulud fix some of the issues with go-ps.. and it does. However, it reduces the ability to discover the process name for the user. The logic for gopsutil is here. Deferring decision for now.

aelsabbahy and others added 30 commits September 7, 2020 10:10
* Migrate from go-ps to gopsutil for better process detection

* Remove debugging code
* Add stale.yml config

* Change stale.yml label

* Add VfsOpts to mount

* Use mountinfo filter
* Rename binaries to strip '-alpha'

As discussed in #663 (comment); strip the -alpha naming, keep the messaging, keep the --use-alpha flag and env-var.

This allows people to remove edge-cases from their installation, yet retains the clearly-set expectations of support being community-driven.

Fixes #651.

* set expectations for future-us re: macOS+Windows vs linux

* fix doc
* service: Add support for OpenRC runlevels

* Omit empty runlevel

* Update documentation

* Update integration tests

* Use consistent pattern for configu default values

- Remove struct tag `default` value reflection

* Make runLevels a testable attribute

* empty commit to try to trigger travis

* Update trusty to reflect precise changes

Co-authored-by: Berney <[email protected]>
* Add transforms

* wip add transforms work

* Add some examples to make sense of this

* Handle floats/ints better

* Convert validatecontails to gomega

* wip

* Add gjson and contain-substring

* wip

* Subclass all matchers adding String()

* I don't evne know what this is.. should have checked it in back when I wrote it

* Migrate GomegaMatcher -> GossMatcher

* lots of changes + drop json-iterator

* Move output related logic to outputs

* Add include_raw flag

* Add bench output format

* Update have_patterns to check input. Add stubs to make Not matcher act as omegaMatcher

* SetEscapeHTML(false) for semver constraint

* Ensure have-Key_with_value works

* remove have-key-with-value

* Fix error compact output. Add oMegaMatcher stubs. Ensure matcher vs m consistent

* Cleanup matchers

* Cleanup TestResult struct and remove need for dyno

* Update all deps

* Update tranformer tests and add summary line to bench output format

* Update readme

* Conditionally print missing and empty values. Sanitize found and expected values for consistency

* Check value is valid before checking IsNil()

* Initial docs change

* WIP fix for pretty print

* Swap order on video vs blog for dgoss docs

* Updated all tests except for semver

* Fix all unit tests

* Fix detection of when matcher is set

* Update documentation

* Update docs/manual.md

Co-authored-by: Peter Mounce <[email protected]>

* Update docs/manual.md

Co-authored-by: Peter Mounce <[email protected]>

* gjson: Validate json before doing gets

* Make errors more clear

* Remove unused field

* Bump go version

* Update doc

* Fix regression with gomega errors

* Fix #262 no need to add file size by default

* Fix output formats

* Use proper quoting for windows test

* Add error checking for gjson path not found

Co-authored-by: Peter Mounce <[email protected]>
This also changes the way total time is calculated
in the output summary.

total time = endTime of last test - start time of first test
ripienaar
ripienaar previously approved these changes Jun 26, 2023
Copy link
Collaborator

@ripienaar ripienaar left a comment

Choose a reason for hiding this comment

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

Too big to realistically give a thorough review but overall this looks really great

Skip bool `json:"skip,omitempty" yaml:"skip,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Meta meta `json:"meta,omitempty" yaml:"meta,omitempty"`
id string `json:"-" yaml:"-"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

no harm, so just a comment - the json and yaml tags here not needed as the marshallers wont include private struct members

@aelsabbahy aelsabbahy mentioned this pull request Jun 26, 2023
Copy link
Collaborator

@petemounce petemounce left a comment

Choose a reason for hiding this comment

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

I've reviewed all the parts that are not the matchers; 58/135. I'll review the rest in a follow-up today.

Comment on lines +44 to +45
- release/goss-darwin-amd64
- release/goss-darwin-amd64.sha256
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same for windows...?

@@ -3,7 +3,7 @@ set -euo pipefail

command -v go

go test -coverprofile="c.out" "${1}"
go test -coverpkg=./... ./... -skip '^TestPrometheus' -coverprofile="c.out"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mind commenting the reason for the skip?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ooh, this one is easy.. it fails 😄

To be fair, I did run it on the main branch and it fails there too. Basically, the way that shell script was written it wasn't actually running those tests.. so they may have never worked.. not sure.. didn't try to check out the original commit to see.

I can take a look as a follow-up PR, or since you're familiar with the code, maybe give it a second look? Maybe I broke something a while back and not noticed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hahaha, ok. Reasonably sure it ran and passed when introduced, but I also haven't gone back and checked.

Once this is merged, I propose to spend some time enhancing our build & test pipeline.

@@ -416,14 +415,14 @@ func addAlphaFlagIfNeeded(app *cli.App) {
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
app.Flags = append(app.Flags, cli.StringFlag{
Name: "use-alpha",
Usage: fmt.Sprintf("goss is alpha-quality. Set to 1 to use anyway."),
Usage: fmt.Sprintf("goss on macOS/Windows is alpha-quality. Set to 1 to use anyway."),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess at this point I can remove the alpha flag altogether and just document that it's not as featureful/stable as Linux..

Copy link
Member Author

Choose a reason for hiding this comment

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

Looking back at the history of this, I'll put it back on your plate.. What are your thoughts on alpha vs non-alpha.

Your PR renamed the files.. seems they're fairly stable from your comment 2-3 years back.

#671

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd be fine with renaming each binary to remove the alpha segment. We still have the flag/env-var & message, and we have integration tests that run and pass for a lot of the functionality; missing or broken things can be iterated incrementally at need.

)

var (
update = flag.Bool("update", false, "update the golden files of this test")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mind adding a comment for how and when to use this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added comment

matcher_test.go Outdated
for _, outFile := range files {
outFile := outFile
parts := strings.Split(outFile, ".")
tfName := fmt.Sprintf("%s.yaml", strings.TrimPrefix(parts[0], "testdata/out_"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's tf in this context? Please expand or comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

"test file" renamed to specFile

@@ -268,14 +268,14 @@ func TestServeCacheNegotiatingContent(t *testing.T) {
logOutput.Reset()
})

t.Run("immediately re-request but different accept header, cache should be cold", func(t *testing.T) {
t.Run("immediately re-request but different accept header, cache should be warm", func(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

🤕 on my part!

Copy link
Member Author

Choose a reason for hiding this comment

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

Nah, those tests were great for implementing this feature. Made my life so much easier.

petemounce
petemounce previously approved these changes Jul 6, 2023
Copy link
Collaborator

@petemounce petemounce left a comment

Choose a reason for hiding this comment

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

LGTM

matchers/be_numerically_matcher.go Outdated Show resolved Hide resolved
Comment on lines +81 to +83
if startTime.IsZero() || tr.StartTime.Before(startTime) {
startTime = tr.StartTime
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Under what circumstances is this needed...?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a loop finding the earliest start time. Before, startTime was calculated at program start, and endTime was when the output was printing. Now, it's calculated from the start time of the first test and endtime of the last test.

The reason for this is when caching testResults and rendering them in different formats, the start/end time needs to be stable. Without this, different output formats would show different times depending on when they were run.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If that's not present as a comment someplace, please could it become present? I don't think I would have inferred that without the explanation.

}

func prettyPrint(i interface{}, indent bool) string {
// JSON doesn't like non-string keys
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's sooo nitpicky.

outputs/bench.go Outdated
"github.com/goss-org/goss/util"
)

type Bench struct{}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like a new output; mention in docs?

Copy link
Member Author

Choose a reason for hiding this comment

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

Mentioned in docs, also mentioned it may not be stable in future releases.. Was using it for debugging and got tired of it not being part of goss =)

Logging may replace it, and it may get deleted in the future.

Thinking through it, part of me wonders if maybe I should remove it from this PR. Leaning towards that, but will sleep on it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

🤷 . I'd say leave it in if it was useful.

Copy link
Member Author

Choose a reason for hiding this comment

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

Slept on it, removing it for now. Initial logging support was added as part of PR a few months back. I have some thoughts on expanding logging to be a lot more useful. Once that story concludes, perhaps the bench output will not be useful.

I'll open up some issues after this PR is merged.

if len(f.Contains) > 0 {
results = append(results, ValidateContains(f, "contains", f.Contains, sysFile.Contains, skip))
if isSet(f.Contains) {
fmt.Fprintf(os.Stderr, "DEPRECATION WARNING: file.contains has been renamed to file.contents\n")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mention these within the manual somewhere/how? Or maybe make an upgrade-notes for v4?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll add it to the upgrade notes

@petemounce
Copy link
Collaborator

Should -o include_raw be enabled by default, and the option becomes -o exclude_raw

I would prefer -o include_raw to be the default, because I think that's a higher UX. I would be frustrated if I got a failure, had to re-run with -o include_raw and the 2nd run passed; indicating the test is flaky somehow. I think that it's best to give the data up-front, because in the context of machine-assertions (and especially when some can be remote-assertions like http, addr) the chance of flakes is higher than in "normal" test frameworks.

@petemounce
Copy link
Collaborator

(Also - this is great work; thank you!)

@aelsabbahy
Copy link
Member Author

aelsabbahy commented Jul 6, 2023

Awesome, thanks for the thorough feedback. I'll address it over the coming week and hopefully this gets merged/released after that.

I would prefer -o include_raw to be the default

This was my leaning as well, for all the reasons you mentioned.

Copy link
Member Author

@aelsabbahy aelsabbahy left a comment

Choose a reason for hiding this comment

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

Added some comments, will address more over the week.

matcher_test.go Outdated
for _, outFile := range files {
outFile := outFile
parts := strings.Split(outFile, ".")
tfName := fmt.Sprintf("%s.yaml", strings.TrimPrefix(parts[0], "testdata/out_"))
Copy link
Member Author

Choose a reason for hiding this comment

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

"test file" renamed to specFile

matchers/be_numerically_matcher.go Outdated Show resolved Hide resolved
outputs/bench.go Outdated
"github.com/goss-org/goss/util"
)

type Bench struct{}
Copy link
Member Author

Choose a reason for hiding this comment

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

Mentioned in docs, also mentioned it may not be stable in future releases.. Was using it for debugging and got tired of it not being part of goss =)

Logging may replace it, and it may get deleted in the future.

Thinking through it, part of me wonders if maybe I should remove it from this PR. Leaning towards that, but will sleep on it.

Comment on lines +81 to +83
if startTime.IsZero() || tr.StartTime.Before(startTime) {
startTime = tr.StartTime
}
Copy link
Member Author

Choose a reason for hiding this comment

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

It's a loop finding the earliest start time. Before, startTime was calculated at program start, and endTime was when the output was printing. Now, it's calculated from the start time of the first test and endtime of the last test.

The reason for this is when caching testResults and rendering them in different formats, the start/end time needs to be stable. Without this, different output formats would show different times depending on when they were run.

@@ -268,14 +268,14 @@ func TestServeCacheNegotiatingContent(t *testing.T) {
logOutput.Reset()
})

t.Run("immediately re-request but different accept header, cache should be cold", func(t *testing.T) {
t.Run("immediately re-request but different accept header, cache should be warm", func(t *testing.T) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Nah, those tests were great for implementing this feature. Made my life so much easier.

@aelsabbahy aelsabbahy dismissed stale reviews from petemounce and ripienaar via d178d97 July 17, 2023 17:29
@aelsabbahy
Copy link
Member Author

  • Removed bench output
  • Temp solution to try to improve test flakiness

Addressed some (most/all?) of the feedback here.

@petemounce let me know if all looks good, if I don't hear back in a week, I'll merge it.

petemounce
petemounce previously approved these changes Jul 17, 2023
@aelsabbahy
Copy link
Member Author

Modified install.sh (locked down version) to avoid breaking anyone. Merging, will create a release candidate release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment