summaryrefslogtreecommitdiffstats
path: root/spec/unit/util/resolution.rb
blob: e546713f2cad91786c8de93a67d1014fd847bf81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env ruby

require File.dirname(__FILE__) + '/../../spec_helper'

require 'facter/util/resolution'

describe Facter::Util::Resolution do
    it "should require a name" do
        lambda { Facter::Util::Resolution.new }.should raise_error(ArgumentError)
    end

    it "should have a name" do
        Facter::Util::Resolution.new("yay").name.should == "yay"
    end

    it "should have a method for setting the code" do
        Facter::Util::Resolution.new("yay").should respond_to(:setcode)
    end

    it "should support a timeout value" do
        Facter::Util::Resolution.new("yay").should respond_to(:timeout=)
    end

    it "should default to a timeout of 0.5 seconds" do
        Facter::Util::Resolution.new("yay").timeout.should == 0.5
    end

    describe "when setting the code" do
        before do
            @resolve = Facter::Util::Resolution.new("yay")
        end

        it "should default to /bin/sh as the interpreter if a string is provided" do
            @resolve.setcode "foo"
            @resolve.interpreter.should == "/bin/sh"
        end

        it "should set the code to any provided string" do
            @resolve.setcode "foo"
            @resolve.code.should == "foo"
        end

        it "should set the code to any provided block" do
            block = lambda { }
            @resolve.setcode(&block)
            @resolve.code.should equal(block)
        end

        it "should prefer the string over a block" do
            @resolve.setcode("foo") { }
            @resolve.code.should == "foo"
        end

        it "should fail if neither a string nor block has been provided" do
            lambda { @resolve.setcode }.should raise_error(ArgumentError)
        end
    end

    it "should be able to return a value" do
        Facter::Util::Resolution.new("yay").should respond_to(:value)
    end

    describe "when returning the value" do
        before do
            @resolve = Facter::Util::Resolution.new("yay")
        end

        describe "and the code is a string" do
            it "should return the result of executing the code with the interpreter" do
                @resolve.setcode "/bin/foo"
                Facter::Util::Resolution.expects(:exec).with("/bin/foo", "/bin/sh").returns "yup"

                @resolve.value.should == "yup"
            end

            it "should return nil if the value is an empty string" do
                @resolve.setcode "/bin/foo"
                Facter::Util::Resolution.stubs(:exec).returns ""
                @resolve.value.should be_nil
            end
        end

        describe "and the code is a block" do
            it "should return the value returned by the block" do
                @resolve.setcode { "yayness" }
                @resolve.value.should == "yayness"
            end

            it "should return nil if the value is an empty string" do
                @resolve.setcode { "" }
                @resolve.value.should be_nil
            end

            it "should timeout after the provided timeout" do
                @resolve.expects(:warn)
                @resolve.timeout = 0.1
                @resolve.setcode { sleep 2; raise "This is a test" }

                @resolve.value.should be_nil
            end
        end
    end

    it "should return its value when converted to a string" do
        @resolve = Facter::Util::Resolution.new("yay")
        @resolve.expects(:value).returns "myval"
        @resolve.to_s.should == "myval"
    end

    it "should allow the adding of confines" do
        Facter::Util::Resolution.new("yay").should respond_to(:confine)
    end

    it "should provide a method for returning the number of confines" do
        @resolve = Facter::Util::Resolution.new("yay")
        @resolve.confine "one" => "foo", "two" => "fee"
        @resolve.length.should == 2
    end

    it "should return 0 confines when no confines have been added" do
        Facter::Util::Resolution.new("yay").length.should == 0
    end

    it "should have a method for determining if it is suitable" do
        Facter::Util::Resolution.new("yay").should respond_to(:suitable?)
    end

    describe "when adding confines" do
        before do
            @resolve = Facter::Util::Resolution.new("yay")
        end

        it "should accept a hash of fact names and values" do
            lambda { @resolve.confine :one => "two" }.should_not raise_error
        end

        it "should create a Util::Confine instance for every argument in the provided hash" do
            Facter::Util::Confine.expects(:new).with("one", "foo")
            Facter::Util::Confine.expects(:new).with("two", "fee")

            @resolve.confine "one" => "foo", "two" => "fee"
        end

    end

    describe "when determining suitability" do
        before do
            @resolve = Facter::Util::Resolution.new("yay")
        end

        it "should always be suitable if no confines have been added" do
            @resolve.should be_suitable
        end

        it "should be unsuitable if any provided confines return false" do
            confine1 = mock 'confine1', :true? => true
            confine2 = mock 'confine2', :true? => false
            Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
            @resolve.confine :one => :two, :three => :four

            @resolve.should_not be_suitable
        end

        it "should be suitable if all provided confines return true" do
            confine1 = mock 'confine1', :true? => true
            confine2 = mock 'confine2', :true? => true
            Facter::Util::Confine.expects(:new).times(2).returns(confine1).then.returns(confine2)
            @resolve.confine :one => :two, :three => :four

            @resolve.should be_suitable
        end
    end

    it "should have a class method for executing code" do
        Facter::Util::Resolution.should respond_to(:exec)
    end

    # It's not possible, AFAICT, to mock %x{}, so I can't really test this bit.
    describe "when executing code" do
        it "should fail if any interpreter other than /bin/sh is requested" do
            lambda { Facter::Util::Resolution.exec("/something", "/bin/perl") }.should raise_error(ArgumentError)
        end
    end
end