summaryrefslogtreecommitdiffstats
path: root/test/ral/providers/package.rb
blob: 5264443bc8a7669f61c92f5e5ec5e3b6cf660cb6 (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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/env ruby

require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')

require 'puppettest'
require 'etc'

class TestPackageProvider < Test::Unit::TestCase
  include PuppetTest

  def setup
    super
    Puppet.info @method_name
  end

  # Load the testpackages hash.
  def self.load_test_packages
    require 'yaml'
    file = File.join(PuppetTest.datadir, "providers", "package", "testpackages.yaml")
    raise "Could not find file #{file}" unless FileTest.exists?(file)
    array = YAML::load(File.read(file)).collect { |hash|
      # Stupid ruby 1.8.1.  YAML is sometimes broken such that
      # symbols end up being strings with the : in them.
      hash.each do |name, value|
        if name.is_a?(String) and name =~ /^:/
          hash.delete(name)
          name = name.sub(/^:/, '').intern
          hash[name] = value
        end
        if value.is_a?(String) and value =~ /^:/
          hash[name] = value.sub(/^:/, '').intern
        end
      end
    }

    array
  end

  def self.suitable_test_packages
    list = load_test_packages
    providers = {}
    Puppet::Type.type(:package).suitableprovider.each do |provider|
      providers[provider.name] = provider
    end
    facts = {}
    Facter.to_hash.each do |fact, value|
      facts[fact.to_s.downcase.intern] = value.to_s.downcase.intern
    end
    list.find_all { |hash| # First find the matching providers
      hash.include?(:provider) and providers.include?(hash[:provider])
    }.reject { |hash| # Then find matching fact sets
      facts.detect do |fact, value|
        # We're detecting unmatched facts, but we also want to
        # delete the facts so they don't show up later.
        if fval = hash[fact]
          hash.delete(fact)
          fval = [fval] unless fval.is_a?(Array)
          fval = fval.collect { |v| v.downcase.intern }
          ! fval.include?(value)
        end
      end
    }
  end

  def assert_absent(provider, msg = "package not absent")
    result = nil
    assert_nothing_raised("Could not query provider") do
      result = provider.query
    end
    if result.nil?
      assert_nil(result)
    elsif result.is_a?(Hash)
      assert (result[:ensure] == :absent or result[:ensure] == :purged), msg
    else
      raise "dunno how to handle #{result.inspect}"
    end
  end

  def assert_not_absent(provider, msg = "package not installed")
    result = nil
    assert_nothing_raised("Could not query provider") do
      result = provider.query
    end
    assert((result == :listed or result.is_a?(Hash)), "query did not return hash or :listed")
    if result == :listed
      assert(provider.resource.is(:ensure) != :absent, msg)
    else
      assert(result[:ensure] != :absent, msg)
    end
  end

  # Run a package through all of its paces.  FIXME This should use the
  # provider, not the package, duh.
  def run_package_installation_test(hash)
    # Turn the hash into a package
    if files = hash[:files]
      hash.delete(:files)
      if files.is_a?(Array)
        hash[:source] = files.shift
      else
        hash[:source] = files
        files = []
      end
    else
      files = []
    end

    if versions = hash[:versions]
      hash.delete(:versions)
    else
      versions = []
    end

    # Start out by just making sure it's installed
    if versions.empty?
      hash[:ensure] = :present
    else
      hash[:ensure] = versions.shift
    end

    if hash[:source]
      unless FileTest.exists?(hash[:source])
        $stderr.puts "Create a package at #{hash[:source]} for testing"
        return
      end
    end

    if cleancmd = hash[:cleanup]
      hash.delete(:cleanup)
    end

    pkg = nil
    assert_nothing_raised(
      "Could not turn #{hash.inspect} into a package"
    ) do
      pkg = Puppet::Type.newpackage(hash)
    end

    # Make any necessary modifications.
    modpkg(pkg)

    provider = pkg.provider

    assert(provider, "Could not retrieve provider")

    return if result = provider.query and ! [:absent, :purged].include?(result[:ensure])

    assert_absent(provider)

    if Process.uid != 0
      Puppet.info "Run as root for full package tests"
      return
    end

    cleanup do
      if pkg.provider.respond_to?(:uninstall)
        pkg.provider.flush
        if pkg.provider.properties[:ensure] != :absent
          assert_nothing_raised("Could not clean up package") do
            pkg.provider.uninstall
          end
        end
      else
        system(cleancmd) if cleancmd
      end
    end

    # Now call 'latest' after the package is installed
    if provider.respond_to?(:latest)
      assert_nothing_raised("Could not call 'latest'") do
        provider.latest
      end
    end

    assert_nothing_raised("Could not install package") do
      provider.install
    end

    assert_not_absent(provider, "package did not install")

    # If there are any remaining files, then test upgrading from there
    unless files.empty?
      pkg[:source] = files.shift
      current = provider.properties
      assert_nothing_raised("Could not upgrade") do
        provider.update
      end
      provider.flush
      new = provider.properties
      assert(current != new, "package was not upgraded: #{current.inspect} did not change")
    end

    unless versions.empty?
      pkg[:ensure] = versions.shift
      current = provider.properties
      assert_nothing_raised("Could not upgrade") do
        provider.update
      end
      provider.flush
      new = provider.properties
      assert(current != new, "package was not upgraded: #{current.inspect} did not change")
    end

    # Now call 'latest' after the package is installed
    if provider.respond_to?(:latest)
      assert_nothing_raised("Could not call 'latest'") do
        provider.latest
      end
    end

    # Now remove the package
    if provider.respond_to?(:uninstall)
      assert_nothing_raised do
        provider.uninstall
      end

      assert_absent(provider)
    end
  end

  # Now create a separate test method for each package
  suitable_test_packages.each do |hash|
    mname = ["test", hash[:name].to_s, hash[:provider].to_s].join("_").intern

    if method_defined?(mname)
      warn "Already a test method defined for #{mname}"
    else
      define_method(mname) do
        run_package_installation_test(hash)
      end
    end
  end

  def test_dont_complain_if_theres_nothing_to_test
    assert("sometimes the above metaprogramming fails to find anything to test and the runner complains")
  end

  def modpkg(pkg)
    case pkg[:provider]
    when :sun
      pkg[:adminfile] = "/usr/local/pkg/admin_file"
    end
  end
end