rubychef-infratest-kitcheninspec

Coerce command('stdout') to integer for math comparison


Given a checker script deployed to my server at path /tmp/foo with the following content...

#!/bin/bash
a=`cat /tmp/a`
b=`cat /tmp/b`
echo -n $( expr $a - $b )

...I have an InSpec test to evaluate if the difference between a and b are within an acceptable range.

describe command('/tmp/foo') do 
  its('stdout') { should be >= 0 }
  its('stdout') { should be < 120 }
end

Sadly, the be matcher won't coerce the input to a type that can be used with the math operators.

How can I coerce this value to an integer?


So far I've tried

undefined method `to_i' for #<Class:0x00007f8a86b91f00> (NoMethodError) Did you mean?  to_s
   Command: `/tmp/foo`
     ↺  
     ↺  

Test Summary: 0 successful, 0 failures, 2 skipped
undefined method `0' for Command: `/tmp/foo`:#<Class:0x00007f9a52b912e0>

For background, /tmp/a and /tmp/b are a pair of epoch outputs from a previous InSpec test.

I could check client side if the values are within the acceptable range, but if possible I would like to have this variance checked & reported by the InSpec evaluation without regex wizardry in place of human-readable math expression.


Solution

  • Credit to @bodumin in the chef community slack #InSpec channel

    Fuzzy typing with cmp matching

    The simplest solution is to use the cmp matcher instead of the be matcher. While there are no explicit math operators given by example on [the official docs for cmp], math operations within a cmp match will evaluate properly

    describe command('/tmp/foo') do 
      its('stdout') { should cmp >= 0 }
      its('stdout') { should cmp < 120 }
    end
    

    Per @aaronlippold

    cmp is a logical compare that we do in the backend … aka 1 is true is TRUE is True. So in SSHD config as an example … you can set a prop using 1 or true or TRUE or True etc. Its a more forgiving matcher that we have built as much as a convince function etc.