puppet 6.15.0 → 6.16.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -7
  3. data/Gemfile.lock +17 -14
  4. data/lib/puppet.rb +32 -8
  5. data/lib/puppet/agent.rb +18 -4
  6. data/lib/puppet/application/agent.rb +1 -2
  7. data/lib/puppet/application/device.rb +1 -1
  8. data/lib/puppet/application/plugin.rb +1 -0
  9. data/lib/puppet/application/ssl.rb +1 -1
  10. data/lib/puppet/configurer.rb +2 -2
  11. data/lib/puppet/context/trusted_information.rb +14 -8
  12. data/lib/puppet/daemon.rb +13 -27
  13. data/lib/puppet/defaults.rb +19 -0
  14. data/lib/puppet/face/facts.rb +1 -1
  15. data/lib/puppet/face/help.rb +29 -3
  16. data/lib/puppet/face/module/search.rb +5 -0
  17. data/lib/puppet/face/plugin.rb +1 -1
  18. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  19. data/lib/puppet/file_system/uniquefile.rb +4 -0
  20. data/lib/puppet/forge/repository.rb +7 -6
  21. data/lib/puppet/functions/filter.rb +1 -0
  22. data/lib/puppet/http/client.rb +22 -11
  23. data/lib/puppet/http/external_client.rb +0 -6
  24. data/lib/puppet/indirector/file_content/http.rb +5 -0
  25. data/lib/puppet/indirector/file_metadata/http.rb +4 -4
  26. data/lib/puppet/indirector/rest.rb +7 -1
  27. data/lib/puppet/network/http/compression.rb +7 -0
  28. data/lib/puppet/network/http/connection.rb +2 -0
  29. data/lib/puppet/network/http/connection_adapter.rb +182 -0
  30. data/lib/puppet/network/http/nocache_pool.rb +1 -0
  31. data/lib/puppet/network/http_pool.rb +2 -2
  32. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  33. data/lib/puppet/pal/pal_impl.rb +4 -1
  34. data/lib/puppet/parser/compiler.rb +28 -25
  35. data/lib/puppet/parser/functions/filter.rb +1 -0
  36. data/lib/puppet/provider/package/aix.rb +17 -2
  37. data/lib/puppet/provider/package/apt.rb +4 -1
  38. data/lib/puppet/provider/package/dnfmodule.rb +24 -4
  39. data/lib/puppet/provider/package/pip.rb +60 -37
  40. data/lib/puppet/provider/package/portage.rb +2 -2
  41. data/lib/puppet/provider/package/yum.rb +7 -0
  42. data/lib/puppet/provider/package/zypper.rb +59 -1
  43. data/lib/puppet/provider/service/systemd.rb +21 -4
  44. data/lib/puppet/provider/user/useradd.rb +5 -1
  45. data/lib/puppet/reports/http.rb +5 -3
  46. data/lib/puppet/runtime.rb +25 -2
  47. data/lib/puppet/ssl/state_machine.rb +33 -8
  48. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  49. data/lib/puppet/test/test_helper.rb +1 -1
  50. data/lib/puppet/type/file/source.rb +1 -1
  51. data/lib/puppet/type/package.rb +16 -1
  52. data/lib/puppet/type/service.rb +6 -8
  53. data/lib/puppet/type/user.rb +1 -7
  54. data/lib/puppet/util/autoload.rb +1 -18
  55. data/lib/puppet/util/log/destinations.rb +1 -10
  56. data/lib/puppet/util/package/version/range.rb +4 -1
  57. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  58. data/lib/puppet/version.rb +1 -1
  59. data/locales/puppet.pot +191 -111
  60. data/man/man5/puppet.conf.5 +21 -2
  61. data/man/man8/puppet-agent.8 +1 -1
  62. data/man/man8/puppet-apply.8 +1 -1
  63. data/man/man8/puppet-catalog.8 +1 -1
  64. data/man/man8/puppet-config.8 +1 -1
  65. data/man/man8/puppet-describe.8 +1 -1
  66. data/man/man8/puppet-device.8 +1 -1
  67. data/man/man8/puppet-doc.8 +1 -1
  68. data/man/man8/puppet-epp.8 +1 -1
  69. data/man/man8/puppet-facts.8 +1 -1
  70. data/man/man8/puppet-filebucket.8 +1 -1
  71. data/man/man8/puppet-generate.8 +1 -1
  72. data/man/man8/puppet-help.8 +6 -3
  73. data/man/man8/puppet-key.8 +1 -1
  74. data/man/man8/puppet-lookup.8 +1 -1
  75. data/man/man8/puppet-man.8 +1 -1
  76. data/man/man8/puppet-module.8 +4 -1
  77. data/man/man8/puppet-node.8 +1 -1
  78. data/man/man8/puppet-parser.8 +1 -1
  79. data/man/man8/puppet-plugin.8 +1 -1
  80. data/man/man8/puppet-report.8 +1 -1
  81. data/man/man8/puppet-resource.8 +1 -1
  82. data/man/man8/puppet-script.8 +1 -1
  83. data/man/man8/puppet-ssl.8 +1 -1
  84. data/man/man8/puppet-status.8 +1 -1
  85. data/man/man8/puppet.8 +2 -2
  86. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-enabled.txt → dnf-module-list.txt} +6 -0
  87. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  88. data/spec/integration/application/agent_spec.rb +66 -1
  89. data/spec/integration/application/plugin_spec.rb +23 -0
  90. data/spec/integration/http/client_spec.rb +6 -1
  91. data/spec/integration/network/http_pool_spec.rb +56 -0
  92. data/spec/integration/util/windows/adsi_spec.rb +5 -0
  93. data/spec/lib/puppet_spec/https.rb +6 -0
  94. data/spec/unit/agent_spec.rb +47 -1
  95. data/spec/unit/application/agent_spec.rb +4 -4
  96. data/spec/unit/context/trusted_information_spec.rb +17 -0
  97. data/spec/unit/daemon_spec.rb +5 -64
  98. data/spec/unit/face/module/search_spec.rb +17 -0
  99. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  100. data/spec/unit/http/client_spec.rb +10 -10
  101. data/spec/unit/http/external_client_spec.rb +9 -9
  102. data/spec/unit/indirector/catalog/compiler_spec.rb +1 -0
  103. data/spec/unit/indirector/file_metadata/http_spec.rb +167 -0
  104. data/spec/unit/indirector/file_metadata/rest_spec.rb +15 -14
  105. data/spec/unit/indirector/rest_spec.rb +13 -0
  106. data/spec/unit/network/http/connection_spec.rb +542 -190
  107. data/spec/unit/network/http/nocache_pool_spec.rb +22 -0
  108. data/spec/unit/network/http_pool_spec.rb +63 -57
  109. data/spec/unit/network/http_spec.rb +1 -1
  110. data/spec/unit/provider/package/aix_spec.rb +29 -0
  111. data/spec/unit/provider/package/dnfmodule_spec.rb +25 -5
  112. data/spec/unit/provider/package/pip_spec.rb +42 -16
  113. data/spec/unit/provider/package/portage_spec.rb +5 -0
  114. data/spec/unit/provider/package/yum_spec.rb +16 -8
  115. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  116. data/spec/unit/provider/service/init_spec.rb +1 -0
  117. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  118. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  119. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  120. data/spec/unit/provider/service/systemd_spec.rb +84 -13
  121. data/spec/unit/provider/user/useradd_spec.rb +8 -0
  122. data/spec/unit/puppet_pal_catalog_spec.rb +43 -0
  123. data/spec/unit/puppet_spec.rb +33 -0
  124. data/spec/unit/reports/http_spec.rb +1 -1
  125. data/spec/unit/ssl/state_machine_spec.rb +52 -8
  126. data/spec/unit/type/service_spec.rb +9 -8
  127. data/spec/unit/type/user_spec.rb +1 -1
  128. data/spec/unit/util/autoload_spec.rb +2 -1
  129. data/spec/unit/util/log/destinations_spec.rb +1 -29
  130. data/spec/unit/util/package/version/range_spec.rb +22 -1
  131. data/tasks/manpages.rake +5 -35
  132. metadata +10 -4
@@ -39,4 +39,26 @@ describe Puppet::Network::HTTP::NoCachePool do
39
39
  it 'has a close method' do
40
40
  Puppet::Network::HTTP::NoCachePool.new.close
41
41
  end
42
+
43
+ it 'logs a deprecation warning' do
44
+ http = double('http', start: nil, finish: nil, started?: true)
45
+
46
+ factory = Puppet::Network::HTTP::Factory.new
47
+ allow(factory).to receive(:create_connection).and_return(http)
48
+ Puppet::Network::HTTP::NoCachePool.new(factory)
49
+
50
+ expect(@logs).to include(an_object_having_attributes(level: :warning, message: /Puppet::Network::HTTP::NoCachePool is deprecated/))
51
+ end
52
+
53
+ it 'omits the warning when deprecations are disabled' do
54
+ Puppet[:disable_warnings] = 'deprecations'
55
+
56
+ http = double('http', start: nil, finish: nil, started?: true)
57
+
58
+ factory = Puppet::Network::HTTP::Factory.new
59
+ allow(factory).to receive(:create_connection).and_return(http)
60
+ Puppet::Network::HTTP::NoCachePool.new(factory)
61
+
62
+ expect(@logs).to eq([])
63
+ end
42
64
  end
@@ -1,41 +1,65 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet/network/http_pool'
3
3
 
4
+ class Puppet::Network::HttpPool::FooClient
5
+ def initialize(host, port, options = {})
6
+ @host = host
7
+ @port = port
8
+ end
9
+ attr_reader :host, :port
10
+ end
11
+
4
12
  describe Puppet::Network::HttpPool do
5
- before :each do
6
- Puppet::SSL::Key.indirection.terminus_class = :memory
7
- Puppet::SSL::CertificateRequest.indirection.terminus_class = :memory
13
+ include PuppetSpec::Files
14
+
15
+ describe "when registering an http client class" do
16
+ let(:http_impl) { Puppet::Network::HttpPool::FooClient }
17
+
18
+ around :each do |example|
19
+ orig_class = Puppet::Network::HttpPool.http_client_class
20
+ begin
21
+ example.run
22
+ ensure
23
+ Puppet::Network::HttpPool.http_client_class = orig_class
24
+ end
25
+ end
26
+
27
+ it "returns instances of the http client class" do
28
+ Puppet::Network::HttpPool.http_client_class = http_impl
29
+ http = Puppet::Network::HttpPool.http_instance("me", 54321)
30
+ expect(http).to be_an_instance_of(http_impl)
31
+ expect(http.host).to eq('me')
32
+ expect(http.port).to eq(54321)
33
+ end
34
+
35
+ it "uses the default http client" do
36
+ expect(Puppet.runtime[:http]).to be_an_instance_of(Puppet::HTTP::Client)
37
+ end
38
+
39
+ it "switches to the external client implementation" do
40
+ Puppet::Network::HttpPool.http_client_class = http_impl
41
+
42
+ expect(Puppet.runtime[:http]).to be_an_instance_of(Puppet::HTTP::ExternalClient)
43
+ end
44
+
45
+ it "always uses an explicitly registered http implementation" do
46
+ Puppet::Network::HttpPool.http_client_class = http_impl
47
+
48
+ new_impl = double('new_http_impl')
49
+ Puppet.initialize_settings([], true, true, http: new_impl)
50
+
51
+ expect(Puppet.runtime[:http]).to eq(new_impl)
52
+ end
8
53
  end
9
54
 
10
55
  describe "when managing http instances" do
11
56
  it "should return an http instance created with the passed host and port" do
12
57
  http = Puppet::Network::HttpPool.http_instance("me", 54321)
13
- expect(http).to be_an_instance_of Puppet::Network::HTTP::Connection
58
+ expect(http).to be_a_kind_of Puppet::Network::HTTP::Connection
14
59
  expect(http.address).to eq('me')
15
60
  expect(http.port).to eq(54321)
16
61
  end
17
62
 
18
- it "should support using an alternate http client implementation" do
19
- begin
20
- class FooClient
21
- def initialize(host, port, options = {})
22
- @host = host
23
- @port = port
24
- end
25
- attr_reader :host, :port
26
- end
27
-
28
- orig_class = Puppet::Network::HttpPool.http_client_class
29
- Puppet::Network::HttpPool.http_client_class = FooClient
30
- http = Puppet::Network::HttpPool.http_instance("me", 54321)
31
- expect(http).to be_an_instance_of FooClient
32
- expect(http.host).to eq('me')
33
- expect(http.port).to eq(54321)
34
- ensure
35
- Puppet::Network::HttpPool.http_client_class = orig_class
36
- end
37
- end
38
-
39
63
  it "should enable ssl on the http instance by default" do
40
64
  expect(Puppet::Network::HttpPool.http_instance("me", 54321)).to be_use_ssl
41
65
  end
@@ -82,53 +106,35 @@ describe Puppet::Network::HttpPool do
82
106
  end
83
107
 
84
108
  describe 'peer verification' do
85
- def setup_standard_ssl_configuration
86
- ca_cert_file = File.expand_path('/path/to/ssl/certs/ca_cert.pem')
87
-
88
- Puppet[:ssl_client_ca_auth] = ca_cert_file
89
- allow(Puppet::FileSystem).to receive(:exist?).with(ca_cert_file).and_return(true)
90
- end
91
-
92
- def setup_standard_hostcert
93
- host_cert_file = File.expand_path('/path/to/ssl/certs/host_cert.pem')
94
- allow(Puppet::FileSystem).to receive(:exist?).with(host_cert_file).and_return(true)
95
-
96
- Puppet[:hostcert] = host_cert_file
97
- end
98
-
99
- def setup_standard_ssl_host
100
- cert = double('cert', :content => 'real_cert')
101
- key = double('key', :content => 'real_key')
102
- host = double('host', :certificate => cert, :key => key, :ssl_store => double('store'))
103
109
 
104
- allow(Puppet::SSL::Host).to receive(:localhost).and_return(host)
105
- end
110
+ before(:each) do
111
+ Puppet[:ssldir] = tmpdir('ssl')
112
+ Puppet.settings.use(:main)
106
113
 
107
- before do
108
- setup_standard_ssl_configuration
109
- setup_standard_hostcert
110
- setup_standard_ssl_host
114
+ Puppet[:certname] = 'signed'
115
+ File.write(Puppet[:localcacert], cert_fixture('ca.pem'))
116
+ File.write(Puppet[:hostcrl], crl_fixture('crl.pem'))
117
+ File.write(Puppet[:hostcert], cert_fixture('signed.pem'))
118
+ File.write(Puppet[:hostprivkey], key_fixture('signed-key.pem'))
111
119
  end
112
120
 
113
121
  it 'enables peer verification by default' do
114
- response = Net::HTTPOK.new('1.1', 200, 'body')
122
+ stub_request(:get, "https://me:54321")
123
+
115
124
  conn = Puppet::Network::HttpPool.http_instance("me", 54321, true)
116
- expect(conn).to receive(:execute_request) do |http, _|
125
+ expect_any_instance_of(Net::HTTP).to receive(:start) do |http|
117
126
  expect(http.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
118
-
119
- response
120
127
  end
121
128
 
122
129
  conn.get('/')
123
130
  end
124
131
 
125
132
  it 'can disable peer verification' do
126
- response = Net::HTTPOK.new('1.1', 200, 'body')
133
+ stub_request(:get, "https://me:54321")
134
+
127
135
  conn = Puppet::Network::HttpPool.http_instance("me", 54321, true, false)
128
- expect(conn).to receive(:execute_request) do |http, _|
136
+ expect_any_instance_of(Net::HTTP).to receive(:start) do |http|
129
137
  expect(http.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
130
-
131
- response
132
138
  end
133
139
 
134
140
  conn.get('/')
@@ -4,6 +4,6 @@ require 'puppet/network/http'
4
4
  describe Puppet::Network::HTTP do
5
5
  it 'defines an http_pool context' do
6
6
  pool = Puppet.lookup(:http_pool)
7
- expect(pool).to be_a(Puppet::Network::HTTP::NoCachePool)
7
+ expect(pool).to be_a(Puppet::Network::HTTP::Pool)
8
8
  end
9
9
  end
@@ -22,16 +22,26 @@ describe Puppet::Type.type(:package).provider(:aix) do
22
22
 
23
23
  context "when installing" do
24
24
  it "should install a package" do
25
+ allow(@provider).to receive(:query).and_return({:name => 'mypackage', :ensure => 'present', :status => :committed})
25
26
  expect(@provider).to receive(:installp).with('-acgwXY', '-d', 'mysource', 'mypackage')
26
27
  @provider.install
27
28
  end
28
29
 
29
30
  it "should install a specific package version" do
30
31
  allow(@resource).to receive(:should).with(:ensure).and_return("1.2.3.4")
32
+ allow(@provider).to receive(:query).and_return({:name => 'mypackage', :ensure => '1.2.3.4', :status => :committed})
31
33
  expect(@provider).to receive(:installp).with('-acgwXY', '-d', 'mysource', 'mypackage 1.2.3.4')
32
34
  @provider.install
33
35
  end
34
36
 
37
+ [:broken, :inconsistent].each do |state|
38
+ it "should fail if the installation resulted in a '#{state}' state" do
39
+ allow(@provider).to receive(:query).and_return({:name => 'mypackage', :ensure => 'present', :status => state})
40
+ expect(@provider).to receive(:installp).with('-acgwXY', '-d', 'mysource', 'mypackage')
41
+ expect { @provider.install }.to raise_error(Puppet::Error, "Package 'mypackage' is in a #{state} state and requires manual intervention")
42
+ end
43
+ end
44
+
35
45
  it "should fail if the specified version is superseded" do
36
46
  @resource[:ensure] = '1.2.3.3'
37
47
  allow(@provider).to receive(:installp).and_return(<<-OUTPUT)
@@ -126,4 +136,23 @@ END
126
136
  expect(described_class).to receive(:execute).and_return('mypackage:mypackage.rte:1.8.6.4::I:T:::::N:A Super Cool Package::::0::\n')
127
137
  described_class.prefetch({ 'mypackage' => latest, 'otherpackage' => absent })
128
138
  end
139
+
140
+ context "when querying instances" do
141
+ before(:each) do
142
+ allow(described_class).to receive(:execute).and_return(<<-END.chomp)
143
+ sysmgt.cim.providers:sysmgt.cim.providers.metrics:2.12.1.1: : :B: :Metrics Providers for AIX OS: : : : : : :1:0:/:
144
+ sysmgt.cim.providers:sysmgt.cim.providers.osbase:2.12.1.1: : :C: :Base Providers for AIX OS: : : : : : :1:0:/:
145
+ openssl.base:openssl.base:1.0.2.1800: : :?: :Open Secure Socket Layer: : : : : : :0:0:/:
146
+ END
147
+ end
148
+
149
+ it "should treat installed packages in broken and inconsistent state as absent" do
150
+ installed_packages = described_class.instances.map { |package| package.properties }
151
+ expected_packages = [{:name => 'sysmgt.cim.providers.metrics', :ensure => :absent, :status => :broken, :provider => :aix},
152
+ {:name => 'sysmgt.cim.providers.osbase', :ensure => '2.12.1.1', :status => :committed, :provider => :aix},
153
+ {:name => 'openssl.base', :ensure => :absent, :status => :inconsistent, :provider => :aix}]
154
+
155
+ expect(installed_packages).to eql(expected_packages)
156
+ end
157
+ end
129
158
  end
@@ -18,7 +18,7 @@ describe Puppet::Type.type(:package).provider(:dnfmodule) do
18
18
  {:failonfail => true, :combine => true, :custom_environment => {}}
19
19
  end
20
20
 
21
- let(:packages) { File.read(my_fixture("dnf-module-list-enabled.txt")) }
21
+ let(:packages) { File.read(my_fixture("dnf-module-list.txt")) }
22
22
  let(:dnf_path) { '/usr/bin/dnf' }
23
23
 
24
24
  before(:each) { allow(Puppet::Util).to receive(:which).with('/usr/bin/dnf').and_return(dnf_path) }
@@ -81,7 +81,7 @@ describe Puppet::Type.type(:package).provider(:dnfmodule) do
81
81
  end
82
82
  end
83
83
 
84
- describe "when installing a module" do
84
+ describe "when ensuring a module" do
85
85
  let(:name) { 'baz' }
86
86
 
87
87
  let(:resource) do
@@ -200,14 +200,32 @@ describe Puppet::Type.type(:package).provider(:dnfmodule) do
200
200
  expect(provider.flavor).to eq('minimal')
201
201
  end
202
202
  end
203
+
204
+ context "when disabling a module" do
205
+
206
+ it "executed the disable command" do
207
+ resource[:ensure] = :disabled
208
+ expect(provider).to receive(:execute).with(array_including('disable'))
209
+ provider.disable
210
+ end
211
+
212
+ it "does not try to disable if package is already disabled" do
213
+ allow(described_class).to receive(:command).with(:dnf).and_return(dnf_path)
214
+ allow(Puppet::Util::Execution).to receive(:execute)
215
+ .with("/usr/bin/dnf module list -d 0 -e 1")
216
+ .and_return("baz 1.2 [d][x] common [d], complete Package Description")
217
+ resource[:ensure] = :disabled
218
+ expect(provider).to be_insync(:disabled)
219
+ end
220
+ end
203
221
  end
204
222
 
205
- context "parsing the output of module list --enabled" do
223
+ context "parsing the output of module list" do
206
224
  before { allow(described_class).to receive(:command).with(:dnf).and_return(dnf_path) }
207
225
 
208
226
  it "returns an array of enabled modules" do
209
227
  allow(Puppet::Util::Execution).to receive(:execute)
210
- .with("/usr/bin/dnf module list --enabled -d 0 -e 1")
228
+ .with("/usr/bin/dnf module list -d 0 -e 1")
211
229
  .and_return(packages)
212
230
 
213
231
  enabled_packages = described_class.instances.map { |package| package.properties }
@@ -219,7 +237,9 @@ describe Puppet::Type.type(:package).provider(:dnfmodule) do
219
237
  {name: "postgresql", ensure: "10", flavor: "server", provider: :dnfmodule},
220
238
  {name: "ruby", ensure: "2.5", flavor: :absent, provider: :dnfmodule},
221
239
  {name: "rust-toolset", ensure: "rhel8", flavor: "common", provider: :dnfmodule},
222
- {name: "subversion", ensure: "1.10", flavor: "server", provider: :dnfmodule}]
240
+ {name: "subversion", ensure: "1.10", flavor: "server", provider: :dnfmodule},
241
+ {name: "swig", ensure: :disabled, flavor: :absent, provider: :dnfmodule},
242
+ {name: "virt", ensure: :disabled, flavor: :absent, provider: :dnfmodule}]
223
243
 
224
244
  expect(enabled_packages).to eql(expected_packages)
225
245
  end
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  osfamilies = { 'windows' => ['pip.exe'], 'other' => ['pip', 'pip-python', 'pip2', 'pip-2'] }
4
+ pip_path_with_spaces = 'C:\Program Files (x86)\Python\Scripts\pip.exe'
4
5
 
5
6
  describe Puppet::Type.type(:package).provider(:pip) do
6
7
 
@@ -102,6 +103,16 @@ describe Puppet::Type.type(:package).provider(:pip) do
102
103
  expect(described_class.instances).to eq([])
103
104
  end
104
105
  end
106
+
107
+ context "when pip path location contains spaces" do
108
+ it "should quote the command before doing execpipe" do
109
+ allow(described_class).to receive(:which).and_return(pip_path_with_spaces)
110
+ allow(described_class).to receive(:pip_version).with(pip_path_with_spaces).and_return('8.0.1')
111
+
112
+ expect(described_class).to receive(:execpipe).with(["\"#{pip_path_with_spaces}\"", ["freeze"]])
113
+ described_class.instances
114
+ end
115
+ end
105
116
  end
106
117
 
107
118
  context "query" do
@@ -160,15 +171,18 @@ describe Puppet::Type.type(:package).provider(:pip) do
160
171
  end
161
172
 
162
173
  context "latest" do
174
+ before do
175
+ allow(described_class).to receive(:pip_version).with(pip_path).and_return(pip_version)
176
+ allow(described_class).to receive(:which).with('pip').and_return(pip_path)
177
+ allow(described_class).to receive(:which).with('pip-python').and_return(pip_path)
178
+ allow(described_class).to receive(:which).with('pip.exe').and_return(pip_path)
179
+ allow(described_class).to receive(:provider_command).and_return(pip_path)
180
+ allow(described_class).to receive(:validate_command).with(pip_path)
181
+ end
182
+
163
183
  context "with pip version < 1.5.4" do
164
- before :each do
165
- allow(described_class).to receive(:pip_version).with("/fake/bin/pip").and_return('1.0.1')
166
- allow(described_class).to receive(:which).with('pip').and_return("/fake/bin/pip")
167
- allow(described_class).to receive(:which).with('pip-python').and_return("/fake/bin/pip")
168
- allow(described_class).to receive(:which).with('pip.exe').and_return("/fake/bin/pip")
169
- allow(described_class).to receive(:provider_command).and_return('/fake/bin/pip')
170
- allow(described_class).to receive(:validate_command).with('/fake/bin/pip')
171
- end
184
+ let(:pip_version) { '1.0.1' }
185
+ let(:pip_path) { '/fake/bin/pip' }
172
186
 
173
187
  it "should find a version number for new_pip_package" do
174
188
  p = StringIO.new(
@@ -236,19 +250,22 @@ describe Puppet::Type.type(:package).provider(:pip) do
236
250
  @resource[:install_options] = ['--index' => 'https://fake.example.com']
237
251
  expect(@provider.latest).to eq(nil)
238
252
  end
253
+
254
+ context "when pip path location contains spaces" do
255
+ let(:pip_path) { pip_path_with_spaces }
256
+
257
+ it "should quote the command before doing execpipe" do
258
+ expect(Puppet::Util::Execution).to receive(:execpipe).with(array_including("\"#{pip_path}\""))
259
+ @provider.latest
260
+ end
261
+ end
239
262
  end
240
263
 
241
264
  context "with pip version >= 1.5.4" do
242
265
  # For Pip 1.5.4 and above, you can get a version list from CLI - which allows for native pip behavior
243
266
  # with regards to custom repositories, proxies and the like
244
- before :each do
245
- allow(described_class).to receive(:pip_version).with("/fake/bin/pip").and_return('1.5.4')
246
- allow(described_class).to receive(:which).with('pip').and_return("/fake/bin/pip")
247
- allow(described_class).to receive(:which).with('pip-python').and_return("/fake/bin/pip")
248
- allow(described_class).to receive(:which).with('pip.exe').and_return("/fake/bin/pip")
249
- allow(described_class).to receive(:provider_command).and_return('/fake/bin/pip')
250
- allow(described_class).to receive(:validate_command).with('/fake/bin/pip')
251
- end
267
+ let(:pip_version) { '1.5.4' }
268
+ let(:pip_path) { '/fake/bin/pip' }
252
269
 
253
270
  it "should find a version number for real_package" do
254
271
  p = StringIO.new(
@@ -296,6 +313,15 @@ describe Puppet::Type.type(:package).provider(:pip) do
296
313
  @resource[:install_options] = ['--index' => 'https://fake.example.com']
297
314
  expect(@provider.latest).to eq(nil)
298
315
  end
316
+
317
+ context "when pip path location contains spaces" do
318
+ let(:pip_path) { pip_path_with_spaces }
319
+
320
+ it "should quote the command before doing execpipe" do
321
+ expect(Puppet::Util::Execution).to receive(:execpipe).with(array_including("\"#{pip_path}\""))
322
+ @provider.latest
323
+ end
324
+ end
299
325
  end
300
326
  end
301
327
 
@@ -72,6 +72,11 @@ describe Puppet::Type.type(:package).provider(:portage) do
72
72
  expect(described_class).to be_reinstallable
73
73
  end
74
74
 
75
+ it "should be the default provider on :osfamily => Gentoo" do
76
+ expect(Facter).to receive(:value).with(:osfamily).and_return("Gentoo")
77
+ expect(described_class.default?).to be_truthy
78
+ end
79
+
75
80
  it 'should support string install options' do
76
81
  expect(@provider).to receive(:emerge).with('--foo', '--bar', @resource[:name])
77
82
 
@@ -259,7 +259,7 @@ describe Puppet::Type.type(:package).provider(:yum) do
259
259
 
260
260
  describe 'insync?' do
261
261
  context 'when version is not a valid RPM version' do
262
- let(:is) { 'a:123' }
262
+ let(:is) { '>===a:123' }
263
263
 
264
264
  before do
265
265
  resource[:ensure] = is
@@ -269,18 +269,26 @@ describe Puppet::Type.type(:package).provider(:yum) do
269
269
  expect(Puppet).to receive(:debug).with("Cannot parse #{is} as a RPM version range")
270
270
  provider.insync?(is)
271
271
  end
272
+ end
273
+
274
+ context 'with valid semantic versions' do
275
+ let(:is) { '1:1.2.3.4-5.el4' }
272
276
 
273
- context 'when requested version equals installed version' do
274
- it { expect(provider).to be_insync(is) }
277
+ it 'returns true if the current version matches the given semantic version' do
278
+ resource[:ensure] = is
279
+ expect(provider).to be_insync(is)
275
280
  end
276
281
 
277
- context 'when requested version is different than installed versions' do
278
- it { expect(provider).not_to be_insync('999') }
282
+ it 'returns false if the current version does not match the given semantic version' do
283
+ resource[:ensure] = '999r'
284
+ expect(provider).not_to be_insync(is)
279
285
  end
280
- end
281
286
 
282
- context 'with valid semantic versions' do
283
- let(:is) { '1:1.2.3.4-5.el4' }
287
+ it 'no debug logs if the current version matches the given semantic version' do
288
+ resource[:ensure] = is
289
+ expect(Puppet).not_to receive(:debug)
290
+ provider.insync?(is)
291
+ end
284
292
 
285
293
  it 'returns true if current version matches the greater or equal semantic version in ensure' do
286
294
  resource[:ensure] = '<=1:1.2.3.4-5.el4'