puppet 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (117) hide show
  1. data/ext/osx/puppet.plist +32 -0
  2. data/ext/redhat/client.init +3 -6
  3. data/ext/redhat/client.sysconfig +1 -10
  4. data/ext/suse/client.init +3 -6
  5. data/ext/systemd/puppet.service +2 -1
  6. data/lib/puppet.rb +1 -1
  7. data/lib/puppet/agent.rb +4 -19
  8. data/lib/puppet/application/apply.rb +22 -6
  9. data/lib/puppet/configurer.rb +3 -2
  10. data/lib/puppet/configurer/plugin_handler.rb +6 -2
  11. data/lib/puppet/face/plugin.rb +7 -14
  12. data/lib/puppet/forge/repository.rb +1 -2
  13. data/lib/puppet/indirector/catalog/compiler.rb +4 -3
  14. data/lib/puppet/indirector/facts/facter.rb +8 -0
  15. data/lib/puppet/module.rb +17 -12
  16. data/lib/puppet/network/http/factory.rb +8 -4
  17. data/lib/puppet/node/environment.rb +11 -7
  18. data/lib/puppet/parser/ast/pops_bridge.rb +5 -0
  19. data/lib/puppet/parser/functions/fqdn_rand.rb +2 -2
  20. data/lib/puppet/parser/scope.rb +39 -13
  21. data/lib/puppet/pops.rb +1 -0
  22. data/lib/puppet/pops/evaluator/runtime3_converter.rb +1 -1
  23. data/lib/puppet/pops/evaluator/runtime3_support.rb +31 -0
  24. data/lib/puppet/pops/parser/epp_support.rb +4 -2
  25. data/lib/puppet/property/ensure.rb +1 -1
  26. data/lib/puppet/provider.rb +5 -0
  27. data/lib/puppet/provider/augeas/augeas.rb +5 -0
  28. data/lib/puppet/provider/group/pw.rb +1 -0
  29. data/lib/puppet/provider/group/windows_adsi.rb +9 -0
  30. data/lib/puppet/provider/mount/parsed.rb +15 -1
  31. data/lib/puppet/provider/package.rb +6 -2
  32. data/lib/puppet/provider/package/gem.rb +16 -0
  33. data/lib/puppet/provider/package/openbsd.rb +7 -7
  34. data/lib/puppet/provider/package/pacman.rb +9 -8
  35. data/lib/puppet/provider/package/pip.rb +1 -1
  36. data/lib/puppet/provider/package/pip3.rb +18 -0
  37. data/lib/puppet/provider/package/pkgdmg.rb +4 -2
  38. data/lib/puppet/provider/package/pkgin.rb +3 -3
  39. data/lib/puppet/provider/package/rpm.rb +8 -14
  40. data/lib/puppet/provider/package/yum.rb +5 -4
  41. data/lib/puppet/provider/service/base.rb +3 -2
  42. data/lib/puppet/provider/service/bsd.rb +7 -7
  43. data/lib/puppet/provider/service/debian.rb +2 -1
  44. data/lib/puppet/provider/service/freebsd.rb +1 -1
  45. data/lib/puppet/provider/service/systemd.rb +75 -6
  46. data/lib/puppet/provider/service/upstart.rb +1 -1
  47. data/lib/puppet/provider/user/pw.rb +1 -0
  48. data/lib/puppet/resource/catalog.rb +1 -1
  49. data/lib/puppet/resource/status.rb +9 -0
  50. data/lib/puppet/resource/type.rb +4 -2
  51. data/lib/puppet/settings.rb +43 -16
  52. data/lib/puppet/transaction.rb +27 -13
  53. data/lib/puppet/type/augeas.rb +1 -0
  54. data/lib/puppet/type/exec.rb +11 -2
  55. data/lib/puppet/type/group.rb +9 -1
  56. data/lib/puppet/type/mount.rb +2 -0
  57. data/lib/puppet/type/package.rb +13 -2
  58. data/lib/puppet/type/service.rb +9 -0
  59. data/lib/puppet/util.rb +8 -3
  60. data/lib/puppet/util/execution.rb +2 -2
  61. data/lib/puppet/util/http_proxy.rb +60 -0
  62. data/lib/puppet/util/log.rb +1 -1
  63. data/lib/puppet/util/splayer.rb +18 -0
  64. data/lib/puppet/version.rb +1 -1
  65. data/spec/fixtures/unit/provider/package/yum/yum-check-update-obsoletes.txt +195 -0
  66. data/spec/integration/application/apply_spec.rb +72 -30
  67. data/spec/integration/indirector/facts/facter_spec.rb +38 -0
  68. data/spec/integration/parser/scope_spec.rb +20 -2
  69. data/spec/integration/provider/mount_spec.rb +23 -36
  70. data/spec/integration/transaction_spec.rb +40 -1
  71. data/spec/integration/type/file_spec.rb +36 -0
  72. data/spec/integration/type/package_spec.rb +65 -0
  73. data/spec/lib/matchers/include_in_order.rb +0 -1
  74. data/spec/lib/puppet_spec/files.rb +14 -0
  75. data/spec/unit/agent_spec.rb +0 -38
  76. data/spec/unit/application/apply_spec.rb +13 -0
  77. data/spec/unit/configurer/plugin_handler_spec.rb +42 -13
  78. data/spec/unit/configurer_spec.rb +5 -0
  79. data/spec/unit/face/plugin_spec.rb +33 -4
  80. data/spec/unit/file_serving/configuration/parser_spec.rb +25 -30
  81. data/spec/unit/indirector/catalog/compiler_spec.rb +16 -0
  82. data/spec/unit/indirector/facts/facter_spec.rb +2 -1
  83. data/spec/unit/module_spec.rb +0 -23
  84. data/spec/unit/network/http/factory_spec.rb +14 -0
  85. data/spec/unit/parser/functions/fqdn_rand_spec.rb +6 -2
  86. data/spec/unit/parser/functions/generate_spec.rb +3 -12
  87. data/spec/unit/parser/scope_spec.rb +9 -0
  88. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +19 -0
  89. data/spec/unit/pops/evaluator/variables_spec.rb +1 -1
  90. data/spec/unit/pops/parser/lexer2_spec.rb +35 -3
  91. data/spec/unit/provider/augeas/augeas_spec.rb +9 -0
  92. data/spec/unit/provider/group/windows_adsi_spec.rb +5 -0
  93. data/spec/unit/provider/package/aptrpm_spec.rb +2 -2
  94. data/spec/unit/provider/package/base_spec.rb +18 -0
  95. data/spec/unit/provider/package/gem_spec.rb +70 -0
  96. data/spec/unit/provider/package/pacman_spec.rb +55 -0
  97. data/spec/unit/provider/package/pip3_spec.rb +257 -0
  98. data/spec/unit/provider/package/pip_spec.rb +1 -1
  99. data/spec/unit/provider/package/pkgdmg_spec.rb +18 -0
  100. data/spec/unit/provider/package/pkgin_spec.rb +23 -13
  101. data/spec/unit/provider/package/yum_spec.rb +11 -0
  102. data/spec/unit/provider/service/bsd_spec.rb +130 -0
  103. data/spec/unit/provider/service/debian_spec.rb +12 -1
  104. data/spec/unit/provider/service/freebsd_spec.rb +16 -0
  105. data/spec/unit/provider/service/systemd_spec.rb +84 -7
  106. data/spec/unit/provider/service/upstart_spec.rb +1 -0
  107. data/spec/unit/provider/zone/solaris_spec.rb +45 -12
  108. data/spec/unit/puppet_spec.rb +1 -1
  109. data/spec/unit/resource/catalog_spec.rb +5 -0
  110. data/spec/unit/type/mount_spec.rb +8 -0
  111. data/spec/unit/type/service_spec.rb +5 -0
  112. data/spec/unit/util/http_proxy_spec.rb +87 -0
  113. data/spec/unit/util/log_spec.rb +12 -1
  114. data/spec/unit/util/splayer_spec.rb +45 -0
  115. metadata +3057 -3035
  116. checksums.yaml +0 -7
  117. data/ext/systemd/puppetmaster.service +0 -11
@@ -33,6 +33,15 @@ describe Puppet::Parser::Scope do
33
33
  end
34
34
  end
35
35
 
36
+ it "should generate a simple string when inspecting a scope" do
37
+ expect(@scope.inspect).to eq("Scope()")
38
+ end
39
+
40
+ it "should generate a simple string when inspecting a scope with a resource" do
41
+ @scope.resource="foo::bar"
42
+ expect(@scope.inspect).to eq("Scope(foo::bar)")
43
+ end
44
+
36
45
  it "should return a scope for use in a test harness" do
37
46
  expect(create_test_scope_for_node("node_name_foo")).to be_a_kind_of(Puppet::Parser::Scope)
38
47
  end
@@ -0,0 +1,19 @@
1
+ #! /usr/bin/env ruby
2
+ require 'spec_helper'
3
+
4
+ require 'puppet/pops'
5
+ require 'puppet/pops/types/type_factory'
6
+
7
+ describe 'when converting to 3.x' do
8
+ it "converts a resource type starting with Class without confusing it with exact match on 'class'" do
9
+ t = Puppet::Pops::Types::TypeFactory.resource('classroom', 'kermit')
10
+ converted = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(t)
11
+ expect(converted).to eql(['classroom', 'kermit'])
12
+ end
13
+
14
+ it "converts a resource type of exactly 'Class'" do
15
+ t = Puppet::Pops::Types::TypeFactory.resource('class', 'kermit')
16
+ converted = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(t)
17
+ expect(converted).to eql(['class', 'kermit'])
18
+ end
19
+ end
@@ -41,7 +41,7 @@ describe 'Puppet::Pops::Impl::EvaluatorImpl' do
41
41
 
42
42
  it "access to global names works in local scope" do
43
43
  top_scope_block = block( var('a').set(literal(2)+literal(2)))
44
- local_scope_block = block( var('a').set(var('::a')+literal(2)), var('::a'))
44
+ local_scope_block = block( var('a').set(literal(100)), var('b').set(var('::a')+literal(2)), var('b'))
45
45
  expect(evaluate_l(top_scope_block, local_scope_block)).to eq(6)
46
46
  end
47
47
 
@@ -524,7 +524,7 @@ describe 'Lexer2' do
524
524
  [:VARIABLE, "x"],
525
525
  :EQUALS,
526
526
  [:NUMBER, "10"],
527
- [:RENDER_STRING, "just text\n"]
527
+ [:RENDER_STRING, " just text\n"]
528
528
  )
529
529
  end
530
530
 
@@ -540,7 +540,39 @@ describe 'Lexer2' do
540
540
  [:VARIABLE, "x"],
541
541
  :EQUALS,
542
542
  [:NUMBER, "10"],
543
- [:RENDER_STRING, "just text\n"]
543
+ [:RENDER_STRING, " just text\n"]
544
+ )
545
+ end
546
+
547
+ it 'epp comments strips left whitespace when preceding is right trim' do
548
+ code = <<-CODE
549
+ This is <% $x=10 -%>
550
+ space-before-me-but-not-after <%# This is an epp comment %>
551
+ just text
552
+ CODE
553
+ expect(epp_tokens_scanned_from(code)).to match_tokens2(
554
+ :EPP_START,
555
+ [:RENDER_STRING, " This is "],
556
+ [:VARIABLE, "x"],
557
+ :EQUALS,
558
+ [:NUMBER, "10"],
559
+ [:RENDER_STRING, " space-before-me-but-not-after\n just text\n"]
560
+ )
561
+ end
562
+
563
+ it 'epp comments strips left whitespace on same line when preceding is not right trim' do
564
+ code = <<-CODE
565
+ This is <% $x=10 %>
566
+ <%# This is an epp comment -%>
567
+ just text
568
+ CODE
569
+ expect(epp_tokens_scanned_from(code)).to match_tokens2(
570
+ :EPP_START,
571
+ [:RENDER_STRING, " This is "],
572
+ [:VARIABLE, "x"],
573
+ :EQUALS,
574
+ [:NUMBER, "10"],
575
+ [:RENDER_STRING, "\n just text\n"]
544
576
  )
545
577
  end
546
578
 
@@ -555,7 +587,7 @@ describe 'Lexer2' do
555
587
  [:VARIABLE, "x"],
556
588
  :EQUALS,
557
589
  [:NUMBER, "10"],
558
- [:RENDER_STRING, "<% this is escaped epp %>\n"]
590
+ [:RENDER_STRING, " <% this is escaped epp %>\n"]
559
591
  )
560
592
  end
561
593
 
@@ -692,6 +692,15 @@ describe provider_class do
692
692
  expect(@provider.execute_changes).to eq(:executed)
693
693
  end
694
694
 
695
+ it "should handle rename commands" do
696
+ @resource[:changes] = "rename Jar/Jar Binks"
697
+ @resource[:context] = "/foo/"
698
+ @augeas.expects(:rename).with("/foo/Jar/Jar", "Binks").returns(true)
699
+ @augeas.expects(:save).returns(true)
700
+ @augeas.expects(:close)
701
+ expect(@provider.execute_changes).to eq(:executed)
702
+ end
703
+
695
704
  it "should handle setm commands" do
696
705
  @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"]
697
706
  @resource[:context] = "/foo/"
@@ -35,11 +35,13 @@ describe Puppet::Type.type(:group).provider(:windows_adsi), :if => Puppet.featur
35
35
  let(:user1) { stub(:account => 'user1', :domain => '.', :to_s => 'user1sid') }
36
36
  let(:user2) { stub(:account => 'user2', :domain => '.', :to_s => 'user2sid') }
37
37
  let(:user3) { stub(:account => 'user3', :domain => '.', :to_s => 'user3sid') }
38
+ let(:invalid_user) { SecureRandom.uuid }
38
39
 
39
40
  before :each do
40
41
  Puppet::Util::Windows::SID.stubs(:name_to_sid_object).with('user1').returns(user1)
41
42
  Puppet::Util::Windows::SID.stubs(:name_to_sid_object).with('user2').returns(user2)
42
43
  Puppet::Util::Windows::SID.stubs(:name_to_sid_object).with('user3').returns(user3)
44
+ Puppet::Util::Windows::SID.stubs(:name_to_sid_object).with(invalid_user).returns(nil)
43
45
  end
44
46
 
45
47
  describe "#members_insync?" do
@@ -157,6 +159,9 @@ describe Puppet::Type.type(:group).provider(:windows_adsi), :if => Puppet.featur
157
159
  it "should return a user string like DOMAIN\\USER,DOMAIN2\\USER2" do
158
160
  expect(provider.members_to_s(['user1', 'user2'])).to eq('.\user1,.\user2')
159
161
  end
162
+ it "should return the username when it cannot be resolved to a SID (for the sake of resource_harness error messages)" do
163
+ expect(provider.members_to_s([invalid_user])).to eq("#{invalid_user}")
164
+ end
160
165
  end
161
166
  end
162
167
 
@@ -24,9 +24,9 @@ describe Puppet::Type.type(:package).provider(:aptrpm) do
24
24
  pkg.provider.expects(:rpm).with(*args)
25
25
  end
26
26
 
27
- it "should report absent packages" do
27
+ it "should report purged packages" do
28
28
  rpm.raises(Puppet::ExecutionFailure, "couldn't find rpm")
29
- expect(pkg.property(:ensure).retrieve).to eq(:absent)
29
+ expect(pkg.property(:ensure).retrieve).to eq(:purged)
30
30
  end
31
31
 
32
32
  it "should report present packages correctly" do
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'puppet/provider/package'
3
+
4
+ describe Puppet::Provider::Package do
5
+ it 'returns absent for uninstalled packages when not purgeable' do
6
+ provider = Puppet::Provider::Package.new
7
+ provider.expects(:query).returns nil
8
+ provider.class.expects(:feature?).with(:purgeable).returns false
9
+ expect(provider.properties[:ensure]).to eq(:absent)
10
+ end
11
+
12
+ it 'returns purged for uninstalled packages when purgeable' do
13
+ provider = Puppet::Provider::Package.new
14
+ provider.expects(:query).returns nil
15
+ provider.class.expects(:feature?).with(:purgeable).returns true
16
+ expect(provider.properties[:ensure]).to eq(:purged)
17
+ end
18
+ end
@@ -185,6 +185,76 @@ context 'installing myresource' do
185
185
  end
186
186
  end
187
187
  end
188
+
189
+ describe 'insync?' do
190
+ describe 'for array of versions' do
191
+ let(:is) { ['1.3.4', '3.6.1', '5.1.2'] }
192
+
193
+ it 'returns true for ~> 1.3' do
194
+ resource[:ensure] = '~> 1.3'
195
+ expect(provider).to be_insync(is)
196
+ end
197
+
198
+ it 'returns false for ~> 2' do
199
+ resource[:ensure] = '~> 2'
200
+ expect(provider).to_not be_insync(is)
201
+ end
202
+
203
+ it 'returns true for > 4' do
204
+ resource[:ensure] = '> 4'
205
+ expect(provider).to be_insync(is)
206
+ end
207
+
208
+ it 'returns true for 3.6.1' do
209
+ resource[:ensure] = '3.6.1'
210
+ expect(provider).to be_insync(is)
211
+ end
212
+
213
+ it 'returns false for 3.6.2' do
214
+ resource[:ensure] = '3.6.2'
215
+ expect(provider).to_not be_insync(is)
216
+ end
217
+ end
218
+
219
+ describe 'for string version' do
220
+ let(:is) { '1.3.4' }
221
+
222
+ it 'returns true for ~> 1.3' do
223
+ resource[:ensure] = '~> 1.3'
224
+ expect(provider).to be_insync(is)
225
+ end
226
+
227
+ it 'returns false for ~> 2' do
228
+ resource[:ensure] = '~> 2'
229
+ expect(provider).to_not be_insync(is)
230
+ end
231
+
232
+ it 'returns false for > 4' do
233
+ resource[:ensure] = '> 4'
234
+ expect(provider).to_not be_insync(is)
235
+ end
236
+
237
+ it 'returns true for 1.3.4' do
238
+ resource[:ensure] = '1.3.4'
239
+ expect(provider).to be_insync(is)
240
+ end
241
+
242
+ it 'returns false for 3.6.1' do
243
+ resource[:ensure] = '3.6.1'
244
+ expect(provider).to_not be_insync(is)
245
+ end
246
+ end
247
+
248
+ it 'should return false for bad version specifiers' do
249
+ resource[:ensure] = 'not a valid gem specifier'
250
+ expect(provider).to_not be_insync('1.0')
251
+ end
252
+
253
+ it 'should return false for :absent' do
254
+ resource[:ensure] = '~> 1.0'
255
+ expect(provider).to_not be_insync(:absent)
256
+ end
257
+ end
188
258
  end
189
259
  end
190
260
 
@@ -410,4 +410,59 @@ EOF
410
410
  expect(provider.latest).to eq('package1 1.0.0, package2 1.0.1')
411
411
  end
412
412
  end
413
+
414
+ describe 'when determining if a resource is a group' do
415
+ before do
416
+ described_class.unstub(:group?)
417
+ end
418
+
419
+ it 'should return false on non-zero pacman exit' do
420
+ executor.stubs(:execute).with(['/usr/bin/pacman', '-Sg', 'git'], {:failonfail => true, :combine => true, :custom_environment => {}}).raises(Puppet::ExecutionFailure, 'error')
421
+ expect(described_class.group?('git')).to eq(false)
422
+ end
423
+
424
+ it 'should return false on empty pacman output' do
425
+ executor.stubs(:execute).with(['/usr/bin/pacman', '-Sg', 'git'], {:failonfail => true, :combine => true, :custom_environment => {}}).returns ''
426
+ expect(described_class.group?('git')).to eq(false)
427
+ end
428
+
429
+ it 'should return true on non-empty pacman output' do
430
+ executor.stubs(:execute).with(['/usr/bin/pacman', '-Sg', 'vim-plugins'], {:failonfail => true, :combine => true, :custom_environment => {}}).returns 'vim-plugins vim-a'
431
+ expect(described_class.group?('vim-plugins')).to eq(true)
432
+ end
433
+ end
434
+
435
+ describe 'when querying installed groups' do
436
+ let(:installed_packages) { {'package1' => '1.0', 'package2' => '2.0', 'package3' => '3.0'} }
437
+ let(:groups) { [['foo package1'], ['foo package2'], ['bar package3'], ['bar package4'], ['baz package5']] }
438
+
439
+ it 'should raise an error on non-zero pacman exit without a filter' do
440
+ executor.expects(:open).with('| /usr/bin/pacman -Sgg 2>&1').returns 'error!'
441
+ $CHILD_STATUS.stubs(:exitstatus).returns 1
442
+ expect { described_class.get_installed_groups(installed_packages) }.to raise_error(Puppet::ExecutionFailure, 'error!')
443
+ end
444
+
445
+ it 'should return empty groups on non-zero pacman exit with a filter' do
446
+ executor.expects(:open).with('| /usr/bin/pacman -Sgg git 2>&1').returns ''
447
+ $CHILD_STATUS.stubs(:exitstatus).returns 1
448
+ expect(described_class.get_installed_groups(installed_packages, 'git')).to eq({})
449
+ end
450
+
451
+ it 'should return empty groups on empty pacman output' do
452
+ pipe = stub()
453
+ pipe.expects(:each_line)
454
+ executor.expects(:open).with('| /usr/bin/pacman -Sgg 2>&1').yields(pipe).returns ''
455
+ $CHILD_STATUS.stubs(:exitstatus).returns 0
456
+ expect(described_class.get_installed_groups(installed_packages)).to eq({})
457
+ end
458
+
459
+ it 'should return groups on non-empty pacman output' do
460
+ pipe = stub()
461
+ pipe.expects(:each_line).multiple_yields(*groups)
462
+ executor.expects(:open).with('| /usr/bin/pacman -Sgg 2>&1').yields(pipe).returns ''
463
+ $CHILD_STATUS.stubs(:exitstatus).returns 0
464
+ expect(described_class.get_installed_groups(installed_packages)).to eq({'foo' => 'package1 1.0, package2 2.0'})
465
+ end
466
+ end
467
+
413
468
  end
@@ -0,0 +1,257 @@
1
+ #! /usr/bin/env ruby
2
+ require 'spec_helper'
3
+
4
+ provider_class = Puppet::Type.type(:package).provider(:pip3)
5
+ osfamilies = { ['All', nil] => 'pip3' }
6
+
7
+ describe provider_class do
8
+
9
+ before do
10
+ @resource = Puppet::Resource.new(:package, "fake_package")
11
+ @provider = provider_class.new(@resource)
12
+ @client = stub_everything('client')
13
+ @client.stubs(:call).with('package_releases', 'real_package').returns(["1.3", "1.2.5", "1.2.4"])
14
+ @client.stubs(:call).with('package_releases', 'fake_package').returns([])
15
+ XMLRPC::Client.stubs(:new2).returns(@client)
16
+ end
17
+
18
+ describe "parse" do
19
+
20
+ it "should return a hash on valid input" do
21
+ expect(provider_class.parse("real_package==1.2.5")).to eq({
22
+ :ensure => "1.2.5",
23
+ :name => "real_package",
24
+ :provider => :pip3,
25
+ })
26
+ end
27
+
28
+ it "should return nil on invalid input" do
29
+ expect(provider_class.parse("foo")).to eq(nil)
30
+ end
31
+
32
+ end
33
+
34
+ describe "cmd" do
35
+
36
+ it "should return pip3 by default" do
37
+ Facter.stubs(:value).with(:osfamily).returns("Not RedHat")
38
+ expect(provider_class.cmd).to eq('pip3')
39
+ end
40
+
41
+ end
42
+
43
+ describe "instances" do
44
+
45
+ osfamilies.each do |osfamily, pip_cmd|
46
+ it "should return an array on #{osfamily} when #{pip_cmd} is present" do
47
+ Facter.stubs(:value).with(:osfamily).returns(osfamily.first)
48
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns(osfamily.last)
49
+ provider_class.expects(:which).with(pip_cmd).returns("/fake/bin/pip3")
50
+ p = stub("process")
51
+ p.expects(:collect).yields("real_package==1.2.5")
52
+ provider_class.expects(:execpipe).with("/fake/bin/pip3 freeze").yields(p)
53
+ provider_class.instances
54
+ end
55
+
56
+ it "should return an empty array on #{osfamily} when #{pip_cmd} is missing" do
57
+ Facter.stubs(:value).with(:osfamily).returns(osfamily.first)
58
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns(osfamily.last)
59
+ provider_class.expects(:which).with(pip_cmd).returns nil
60
+ expect(provider_class.instances).to eq([])
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ describe "query" do
67
+
68
+ before do
69
+ @resource[:name] = "real_package"
70
+ end
71
+
72
+ it "should return a hash when pip3 and the package are present" do
73
+ provider_class.expects(:instances).returns [provider_class.new({
74
+ :ensure => "1.2.5",
75
+ :name => "real_package",
76
+ :provider => :pip3,
77
+ })]
78
+
79
+ expect(@provider.query).to eq({
80
+ :ensure => "1.2.5",
81
+ :name => "real_package",
82
+ :provider => :pip3,
83
+ })
84
+ end
85
+
86
+ it "should return nil when the package is missing" do
87
+ provider_class.expects(:instances).returns []
88
+ expect(@provider.query).to eq(nil)
89
+ end
90
+
91
+ it "should be case insensitive" do
92
+ @resource[:name] = "Real_Package"
93
+
94
+ provider_class.expects(:instances).returns [provider_class.new({
95
+ :ensure => "1.2.5",
96
+ :name => "real_package",
97
+ :provider => :pip3,
98
+ })]
99
+
100
+ expect(@provider.query).to eq({
101
+ :ensure => "1.2.5",
102
+ :name => "real_package",
103
+ :provider => :pip3,
104
+ })
105
+ end
106
+
107
+ end
108
+
109
+ describe "latest" do
110
+
111
+ it "should find a version number for real_package" do
112
+ @resource[:name] = "real_package"
113
+ expect(@provider.latest).not_to eq(nil)
114
+ end
115
+
116
+ it "should not find a version number for fake_package" do
117
+ @resource[:name] = "fake_package"
118
+ expect(@provider.latest).to eq(nil)
119
+ end
120
+
121
+ it "should handle a timeout gracefully" do
122
+ @resource[:name] = "fake_package"
123
+ @client.stubs(:call).raises(Timeout::Error)
124
+ expect { @provider.latest }.to raise_error(Puppet::Error)
125
+ end
126
+
127
+ end
128
+
129
+ describe "install" do
130
+
131
+ before do
132
+ @resource[:name] = "fake_package"
133
+ @url = "git+https://example.com/fake_package.git"
134
+ end
135
+
136
+ it "should install" do
137
+ @resource[:ensure] = :installed
138
+ @resource[:source] = nil
139
+ @provider.expects(:lazy_pip).
140
+ with("install", '-q', "fake_package")
141
+ @provider.install
142
+ end
143
+
144
+ it "omits the -e flag (GH-1256)" do
145
+ # The -e flag makes the provider non-idempotent
146
+ @resource[:ensure] = :installed
147
+ @resource[:source] = @url
148
+ @provider.expects(:lazy_pip).with() do |*args|
149
+ not args.include?("-e")
150
+ end
151
+ @provider.install
152
+ end
153
+
154
+ it "should install from SCM" do
155
+ @resource[:ensure] = :installed
156
+ @resource[:source] = @url
157
+ @provider.expects(:lazy_pip).
158
+ with("install", '-q', "#{@url}#egg=fake_package")
159
+ @provider.install
160
+ end
161
+
162
+ it "should install a particular SCM revision" do
163
+ @resource[:ensure] = "0123456"
164
+ @resource[:source] = @url
165
+ @provider.expects(:lazy_pip).
166
+ with("install", "-q", "#{@url}@0123456#egg=fake_package")
167
+ @provider.install
168
+ end
169
+
170
+ it "should install a particular version" do
171
+ @resource[:ensure] = "0.0.0"
172
+ @resource[:source] = nil
173
+ @provider.expects(:lazy_pip).with("install", "-q", "fake_package==0.0.0")
174
+ @provider.install
175
+ end
176
+
177
+ it "should upgrade" do
178
+ @resource[:ensure] = :latest
179
+ @resource[:source] = nil
180
+ @provider.expects(:lazy_pip).
181
+ with("install", "-q", "--upgrade", "fake_package")
182
+ @provider.install
183
+ end
184
+
185
+ it "should handle install options" do
186
+ @resource[:ensure] = :installed
187
+ @resource[:source] = nil
188
+ @resource[:install_options] = [{"--timeout" => "10"}, "--no-index"]
189
+ @provider.expects(:lazy_pip).
190
+ with("install", "-q", "--timeout=10", "--no-index", "fake_package")
191
+ @provider.install
192
+ end
193
+
194
+ end
195
+
196
+ describe "uninstall" do
197
+
198
+ it "should uninstall" do
199
+ @resource[:name] = "fake_package"
200
+ @provider.expects(:lazy_pip).
201
+ with('uninstall', '-y', '-q', 'fake_package')
202
+ @provider.uninstall
203
+ end
204
+
205
+ end
206
+
207
+ describe "update" do
208
+
209
+ it "should just call install" do
210
+ @provider.expects(:install).returns(nil)
211
+ @provider.update
212
+ end
213
+
214
+ end
215
+
216
+ describe "lazy_pip" do
217
+
218
+ after(:each) do
219
+ Puppet::Type::Package::ProviderPip.instance_variable_set(:@confine_collection, nil)
220
+ end
221
+
222
+ it "should succeed if pip3 is present" do
223
+ @provider.stubs(:pip).returns(nil)
224
+ @provider.method(:lazy_pip).call "freeze"
225
+ end
226
+
227
+ osfamilies.each do |osfamily, pip_cmd|
228
+ it "should retry on #{osfamily} if #{pip_cmd} has not yet been found" do
229
+ Facter.stubs(:value).with(:osfamily).returns(osfamily.first)
230
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns(osfamily.last)
231
+ @provider.expects(:pip).twice.with('freeze').raises(NoMethodError).then.returns(nil)
232
+ @provider.expects(:which).with(pip_cmd).returns("/fake/bin/pip3")
233
+ @provider.method(:lazy_pip).call "freeze"
234
+ end
235
+
236
+ it "should fail on #{osfamily} if #{pip_cmd} is missing" do
237
+ Facter.stubs(:value).with(:osfamily).returns(osfamily.first)
238
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns(osfamily.last)
239
+ @provider.expects(:pip).with('freeze').raises(NoMethodError)
240
+ @provider.expects(:which).with(pip_cmd).returns(nil)
241
+ expect { @provider.method(:lazy_pip).call("freeze") }.to raise_error(NoMethodError)
242
+ end
243
+
244
+ it "should output a useful error message on #{osfamily} if #{pip_cmd} is missing" do
245
+ Facter.stubs(:value).with(:osfamily).returns(osfamily.first)
246
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns(osfamily.last)
247
+ @provider.expects(:pip).with('freeze').raises(NoMethodError)
248
+ @provider.expects(:which).with(pip_cmd).returns(nil)
249
+ expect { @provider.method(:lazy_pip).call("freeze") }.
250
+ to raise_error(NoMethodError, "Could not locate the #{pip_cmd} command.")
251
+ end
252
+
253
+ end
254
+
255
+ end
256
+
257
+ end