1

I've written a very simple facter fact. It looks like this:

# Kubadmin facts
#
require 'json'

Facter.add(:has_kubectl) do
  confine :kernel => :linux
  setcode do
    Facter::Core::Execution.which('kubectl')
  end
end


Facter.add(:kubernetes_version) do
  confine :kernel => :linux
  kubernetes_json = Facter::Core::Execution.execute('/usr/bin/kubectl version -o json')
  kubernetes_parsed_json = JSON.parse(kubernetes_json)

  versions = {
    "client" => kubernetes_parsed_json['clientVersion']['gitVersion'],
    "server" => kubernetes_parsed_json['serverVersion']['gitVersion'],
  }

  setcode do
    versions
  end

end

I now want to test that fact, so I wrote a spec test for it

require 'spec_helper'

describe 'kubectl', :type => :fact do

  before :each do
    Facter.clear
    Facter.clear_messages
  end

  before(:each) do
    Facter.fact(:kernel).stubs(:value).returns('linux')
  end


  expected = File.read('spec/expected/kubectl_client_server.json')

  context 'kubectl installed' do
      it 'should return nil' do
        expect(Facter.fact(:has_kubectl).value).to eq nil
      end
  end


  context 'server and client returns' do
    it do
      Facter::Core::Execution.stubs(:execute).with('/usr/bin/kubectl version -o json').returns expected
        expect(Facter.fact(:kubernetes_version).value).to be_a(Hash)
        expect(Facter.fact(:kubernetes_version)).to include(
          'client' => "v1.8.4",
          'server' => "v1.8.4"
        )
    end
  end
end

When I run the tests, I get a very weird error:

1) kubectl kubectl installed should return nil
     Failure/Error: expect(Facter.fact(:has_kubectl).value).to eq nil

     Mocha::ExpectationError:
       unexpected invocation: Facter::Core::Execution.which("vmware")
       satisfied expectations:
       - allowed any number of times, not yet invoked: #<Puppet::Util::Feature:0x7f88fbc7cca8>.root?(any_parameters)
       - allowed any number of times, invoked 15 times: #<Facter::Util::Fact:0x7f88fbc96220>.value(any_parameters)
       - allowed any number of times, not yet invoked: Facter::Core::Execution.which("kubectl")

2) kubectl server and client returns
     Failure/Error:
       expect(Facter.fact(:kubernetes_version)).to include(
         'client' => "v1.8.4",
         'server' => "v1.8.4"
       )

     Mocha::ExpectationError:
       unexpected invocation: Facter::Core::Execution.execute("uname -r", {:on_fail => nil})
       satisfied expectations:
       - allowed any number of times, not yet invoked: #<Puppet::Util::Feature:0x7f88fbc7cca8>.root?(any_parameters)
       - allowed any number of times, invoked 13 times: #<Facter::Util::Fact:0x7f88fbf61748>.value(any_parameters)
       - allowed any number of times, invoked once: Facter::Core::Execution.execute("/usr/bin/kubectl version -o json")

What did I do wrong here?

The code for this, btw, is here: https://github.com/jaxxstorm/puppet-kubeadm/blob/version_facts/spec/unit/facter/kubectl_spec.rb

jaxxstorm
  • 12,422
  • 5
  • 57
  • 67
  • The code for the fact looks fine to me. The code for the spec test looks mostly fine as well, except I would think you do not need that `.value` attribute when checking the type for `Hash` since the implicit return on that method is the `versions` value assignment unless I am mistaken. – Matthew Schuchard Mar 28 '18 at 16:49
  • More to the point of the errors, it would seem that Mocha is disallowing other method invocations during the spec tests other than what you `expect` and `stub`. I would also venture a guess that Facter is making other method invocations implicitly during your method calls (such as 'is this on VMWare' and 'is this Linux' even though you stubbed that fact). That would explain the behavior you are seeing, but I cannot verify that in the source code for Facter at the moment. – Matthew Schuchard Mar 28 '18 at 16:51
  • The tests run fine for me. – Alex Harvey Mar 28 '18 at 22:03
  • @AlexHarvey With or without Mocha? – Matthew Schuchard Mar 29 '18 at 15:40

0 Answers0