goss-org / goss

Quick and Easy server testing/validation
https://goss.rocks
Apache License 2.0
5.5k stars 470 forks source link

command stdout matcher with AND and NOT #872

Closed smerle33 closed 4 months ago

smerle33 commented 5 months ago

I cannot have, in the command part, a 2 steps test with contain AND not contain string

command:
  nodejs:
    exec: node --version
    exit-status: 0
    stdout:
      - 18.18.2
      - not: 'Please install a version by running one of the following'

I got :

Command: nodejs: stdout:
Error
    HavePatterns matcher expects patterns to be a string. got: 
        <map[string]interface {} | len:1>: {
            "not": <string>"Please install a version by running one of the following",
        }

or

command:
  nodejs:
    exec: node --version
    exit-status: 0
    stdout:
      and:
        - 18.18.2
        - not: 'Please install a version by running one of the following'

this one check the exact "18.18.2" and not the contain :

Command: nodejs: stdout:
Expected
    "v18.18.2\n"
to equal
    "18.18.2"
diff
    --- test
    +++ actual
    @@ -1 +1,2 @@
    -18.18.2
    +v18.18.2
    +

while if I drop the AND it correctly check the content .... but I would miss the NOT part

Expected Behavior I would like the AND to keep the check as without it meaning if the stdout contain the string (i would expect an exact match with quotes for example) I would like the NOT to work like here : https://github.com/goss-org/goss/blob/9ae6acfa7a895b5b89ef8088afe55accbf08fc12/examples/goss_awesome_gomega.yaml#L41

Actual Behavior doesn't work at all.

Environment:

aelsabbahy commented 5 months ago

Does the documentation here help?

https://github.com/goss-org/goss/blob/master/docs/manual.md#ioreaders

As I understand your request, you would like "18.18.2" to be a partial match

Do you want the not to be a partial match or exact match?

smerle33 commented 5 months ago

Does the documentation here help?

master/docs/manual.md#ioreaders

not really, I did try :

---
command:
  bundle:
    exec: bundle -v
    exit-status: 0
  nodejs:
    exec: node --version
    exit-status: 0
    stdout:
      and:
        - contain-element: "18.18.2"
        - not: {contain-element: "Please install a version by running one of the following"}
  npm:
    exec: npm version
    exit-status: 0

but got :

Failures/Skipped:

Command: nodejs: stdout:
Expected
    ["v18.18.2",""]
to contain element matching
    "18.18.2"
the transform chain was
    [{"to-array":{}}]
the raw value was
    "v18.18.2\n"

As I understand your request, you would like "18.18.2" to be a partial match

Do you want the not to be a partial match or exact match?

both should be partial.

my main problem here is that if the nodejs is not installed, the asdf dump an informationnal text that contain the version, so if I just look for it, goss give a false positif. I need to search the version (partial as I don't want to deal with v and \n and that the text Please install a version by running one of the following is NOT present :

Please install a version by running one of the following:

asdf install nodejs 18.15.0

or add one of the following versions in your config file at /Users/smerle/code/infra-reports/.tool-versions
nodejs 18.18.2
aelsabbahy commented 5 months ago

If I'm understanding your request correctly, the test can simply be:

command:
    nodejs:
        exec: node --version
        exit-status: 0
        stdout:
            - '18.18.2'
            - '!Please install a version by running one of the following'

Here's an example I tested with locally (just used cat and stubbed data to reproduce your requirements):

Stubs:

$ tail 872_*
==> 872_bad1.txt <==
Please install a version by running one of the following:

asdf install nodejs 18.15.0

or add one of the following versions in your config file at /Users/smerle/code/infra-reports/.tool-versions
nodejs 18.18.2

==> 872_bad2.txt <==
v18.18.9999

==> 872_good.txt <==
v18.18.2

goss.yaml:

$ cat goss.yaml
command:
    cat 872_bad1.txt:
        exit-status: 0
        stdout:
            - '18.18.2'
            - '!Please install a version by running one of the following'
    cat 872_bad2.txt:
        exit-status: 0
        stdout:
            - '18.18.2'
            - '!Please install a version by running one of the following'
    cat 872_good.txt:
        exit-status: 0
        stdout:
            - '18.18.2'
            - '!Please install a version by running one of the following'

results:

$ goss v
...F.F

Failures/Skipped:

Command: cat 872_bad1.txt: stdout:
Expected
    "object: *bytes.Reader"
to have patterns
    ["18.18.2","!Please install a version by running one of the following"]
the missing elements were
    ["!Please install a version by running one of the following"]

Command: cat 872_bad2.txt: stdout:
Expected
    "object: *bytes.Reader"
to have patterns
    ["18.18.2","!Please install a version by running one of the following"]
the missing elements were
    ["18.18.2"]

Total Duration: 0.005s
Count: 6, Failed: 2, Skipped: 0

The documentation has a mistake for the expanded version, you're correct it will match the whole string. To get the same result as above using and + contain-element you need to add a contain-substring:

        stdout:
            and:
            - contain-element:
                contain-substring: '18.18.2'
            - not:
                contain-element:
                    contain-substring: 'Please install a version by running one of the following'

Hope this helps, sorry for the delay, wanted to respond from a computer to provide a thorough answer.

smerle33 commented 4 months ago

this :

stdout:
     - '18.18.2'
     - '!Please install a version by running one of the following'

worked perfectly ! Thanks for your help

(this not :

        stdout:
            and:
            - contain-element:
                contain-substring: '18.18.2'
            - not:
                contain-element:
                    contain-substring: 'Please install a version by running one of the following'

)