I am writing a custom resource for Chef. The resource is used for setting sysctl values. I am basically using the Chef sysctl code and putting some limitations around it. We don't trust all the users at the company :P
I am trying to put most of the code inside a library helper module so I can test the code easier. I am not sure if this is best practice. Let me know if this is bad practice.
Anyway, the issue I am running into is trying to test my library code. Whenever I try to mock the shell_out command I always get the following error.
1) Sysctl::Helpers.set_sysctl_param
Failure/Error: subject.set_sysctl_param("key1", "value1")
NoMethodError:
undefined method `shell_out!' for Sysctl::Helpers:Module
Library Code
module Sysctl
module Helpers
include Chef::Mixin::ShellOut
def self.set_sysctl_param(key, value)
shell_out!("sysctl -w \"#{key}=#{value}\"")
end
end
end
Test
require 'spec_helper'
describe Sysctl::Helpers do
describe '.set_sysctl_param' do
let(:shellout) { double(run_command: nil, error!: nil, stdout: '', stderr: double(empty?: true)) }
before do
allow(Chef::Mixin::ShellOut).to receive(:new).and_return(shellout)
end
it do
subject.set_sysctl_param("key1", "value1")
expect(:shellout).to receive(:run_command).with("sysctl -w \"key1=value1\"")
end
end
end
I appreciate any help or advise you can give me.
Thanks!
When you include a module, you add module methods as instance methods. But you try to access shell_out
in a class method. You actually need to extend your module with Chef::Mixin::ShellOut. This way ShellOut methods will be added as class methods.
module Sysctl
module Helpers
extend Chef::Mixin::ShellOut # replace include with extend
def self.set_sysctl_param(key, value)
shell_out!("sysctl -w \"#{key}=#{value}\"")
end
end
end
More on this What is the difference between include and extend in Ruby?