chef 13.2.20 → 13.3.42

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -1
  3. data/Gemfile +2 -8
  4. data/README.md +6 -2
  5. data/Rakefile +0 -11
  6. data/VERSION +1 -1
  7. data/acceptance/Gemfile.lock +1 -1
  8. data/acceptance/data-collector/.acceptance/data-collector-test/files/default/api.rb +34 -18
  9. data/acceptance/data-collector/.acceptance/data-collector-test/recipes/default.rb +6 -0
  10. data/lib/chef/cookbook/metadata.rb +2 -2
  11. data/lib/chef/deprecation/warnings.rb +3 -1
  12. data/lib/chef/exceptions.rb +1 -1
  13. data/lib/chef/http.rb +9 -10
  14. data/lib/chef/http/api_versions.rb +2 -0
  15. data/lib/chef/http/http_request.rb +3 -0
  16. data/lib/chef/knife/core/bootstrap_context.rb +1 -0
  17. data/lib/chef/knife/core/status_presenter.rb +1 -1
  18. data/lib/chef/knife/ssh.rb +4 -0
  19. data/lib/chef/provider/apt_preference.rb +99 -0
  20. data/lib/chef/provider/execute.rb +3 -2
  21. data/lib/chef/provider/http_request.rb +14 -0
  22. data/lib/chef/provider/mount/aix.rb +49 -8
  23. data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +1 -1
  24. data/lib/chef/provider/package/zypper.rb +5 -5
  25. data/lib/chef/provider/service/systemd.rb +12 -11
  26. data/lib/chef/provider/support/zypper_repo.erb +17 -0
  27. data/lib/chef/provider/systemd_unit.rb +3 -2
  28. data/lib/chef/provider/windows_task.rb +92 -71
  29. data/lib/chef/provider/zypper_repository.rb +81 -0
  30. data/lib/chef/providers.rb +2 -0
  31. data/lib/chef/resource/apt_preference.rb +36 -0
  32. data/lib/chef/resource/execute.rb +12 -2
  33. data/lib/chef/resource/http_request.rb +1 -1
  34. data/lib/chef/resource/zypper_repository.rb +51 -0
  35. data/lib/chef/resources.rb +2 -0
  36. data/lib/chef/search/query.rb +6 -1
  37. data/lib/chef/server_api_versions.rb +21 -2
  38. data/lib/chef/version.rb +3 -4
  39. data/lib/chef/win32/api/file.rb +1 -0
  40. data/lib/chef/win32/file.rb +2 -0
  41. data/lib/chef/win32/version.rb +6 -0
  42. data/spec/functional/knife/ssh_spec.rb +1 -1
  43. data/spec/functional/resource/execute_spec.rb +2 -2
  44. data/spec/spec_helper.rb +8 -1
  45. data/spec/unit/cookbook/metadata_spec.rb +3 -3
  46. data/spec/unit/http/api_versions_spec.rb +6 -3
  47. data/spec/unit/knife/bootstrap_spec.rb +4 -0
  48. data/spec/unit/knife/cookbook_show_spec.rb +3 -3
  49. data/spec/unit/knife/ssh_spec.rb +7 -1
  50. data/spec/unit/knife/status_spec.rb +2 -0
  51. data/spec/unit/provider/apt_preference_spec.rb +87 -0
  52. data/spec/unit/provider/apt_update_spec.rb +7 -7
  53. data/spec/unit/provider/dsc_resource_spec.rb +2 -2
  54. data/spec/unit/provider/execute_spec.rb +32 -14
  55. data/spec/unit/provider/mount/aix_spec.rb +33 -1
  56. data/spec/unit/provider/package/rubygems_spec.rb +1 -1
  57. data/spec/unit/provider/package/windows/registry_uninstall_entry_spec.rb +56 -3
  58. data/spec/unit/provider/package/windows_spec.rb +1 -1
  59. data/spec/unit/provider/package/zypper_spec.rb +43 -0
  60. data/spec/unit/provider/script_spec.rb +1 -1
  61. data/spec/unit/provider/service/systemd_service_spec.rb +23 -21
  62. data/spec/unit/provider/systemd_unit_spec.rb +42 -41
  63. data/spec/unit/provider/windows_task_spec.rb +40 -0
  64. data/spec/unit/resource/apt_preference_spec.rb +41 -0
  65. data/spec/unit/resource/execute_spec.rb +21 -1
  66. data/spec/unit/resource/powershell_script_spec.rb +2 -2
  67. data/spec/unit/resource/zypper_repository_spec.rb +65 -0
  68. data/spec/unit/search/query_spec.rb +13 -18
  69. data/spec/unit/server_api_spec.rb +75 -1
  70. data/spec/unit/server_api_versions_spec.rb +22 -0
  71. data/spec/unit/win32/link_spec.rb +73 -0
  72. data/tasks/dependencies.rb +0 -1
  73. metadata +13 -6
  74. data/tasks/changelog.rb +0 -37
  75. data/tasks/version.rb +0 -41
@@ -118,6 +118,7 @@ describe Chef::Provider::WindowsTask do
118
118
 
119
119
  it "creates the task if it's not already existing" do
120
120
  allow(provider).to receive(:task_need_update?).and_return(true)
121
+ allow(provider).to receive(:basic_validation).and_return(true)
121
122
  expect(provider).to receive(:run_schtasks).with("CREATE", { "F" => "", "SC" => :hourly, "MO" => 1, "TR" => nil, "RU" => "SYSTEM" })
122
123
  provider.run_action(:create)
123
124
  expect(new_resource).to be_updated_by_last_action
@@ -126,6 +127,7 @@ describe Chef::Provider::WindowsTask do
126
127
  it "updates the task XML if random_delay is provided" do
127
128
  new_resource.random_delay "20"
128
129
  allow(provider).to receive(:task_need_update?).and_return(true)
130
+ allow(provider).to receive(:basic_validation).and_return(true)
129
131
  expect(provider).to receive(:run_schtasks).with("CREATE", { "F" => "", "SC" => :hourly, "MO" => 1, "TR" => nil, "RU" => "SYSTEM" })
130
132
  expect(provider).to receive(:update_task_xml)
131
133
  provider.run_action(:create)
@@ -135,6 +137,7 @@ describe Chef::Provider::WindowsTask do
135
137
  it "updates the task XML if execution_time_limit is provided" do
136
138
  new_resource.execution_time_limit "20"
137
139
  allow(provider).to receive(:task_need_update?).and_return(true)
140
+ allow(provider).to receive(:basic_validation).and_return(true)
138
141
  expect(provider).to receive(:run_schtasks).with("CREATE", { "F" => "", "SC" => :hourly, "MO" => 1, "TR" => nil, "RU" => "SYSTEM" })
139
142
  expect(provider).to receive(:update_task_xml)
140
143
  provider.run_action(:create)
@@ -280,6 +283,29 @@ describe Chef::Provider::WindowsTask do
280
283
  end
281
284
  end
282
285
 
286
+ describe "#basic_validation" do
287
+ context "when command doesn't exist" do
288
+ it "raise error" do
289
+ new_resource.command ""
290
+ expect { provider.send(:basic_validation) }.to raise_error(Chef::Exceptions::ValidationFailed)
291
+ end
292
+ end
293
+
294
+ context "when task_name doesn't exist" do
295
+ let(:new_resource) { Chef::Resource::WindowsTask.new("") }
296
+ it "raise error" do
297
+ expect { provider.send(:basic_validation) }.to raise_error(Chef::Exceptions::ValidationFailed)
298
+ end
299
+ end
300
+
301
+ context "when task_name and command exists" do
302
+ it "returns true" do
303
+ new_resource.command "cd ~/"
304
+ expect(provider.send(:basic_validation)).to be(true)
305
+ end
306
+ end
307
+ end
308
+
283
309
  describe "#task_need_update?" do
284
310
  context "when task doesn't exist" do
285
311
  before do
@@ -325,6 +351,20 @@ describe Chef::Provider::WindowsTask do
325
351
  expect(provider.send(:task_need_update?)).to be(true)
326
352
  end
327
353
  end
354
+
355
+ context "when start_day is updated" do
356
+ it "returns true" do
357
+ new_resource.start_day "01/01/2000"
358
+ expect(provider.send(:task_need_update?)).to be(true)
359
+ end
360
+ end
361
+
362
+ context "when start_time updated" do
363
+ it "returns true" do
364
+ new_resource.start_time "01:01"
365
+ expect(provider.send(:task_need_update?)).to be(true)
366
+ end
367
+ end
328
368
  end
329
369
  end
330
370
 
@@ -0,0 +1,41 @@
1
+ #
2
+ # Author:: Tim Smith (<tsmith@chef.io>)
3
+ # Copyright:: 2016-2017, Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ describe Chef::Resource::AptPreference do
22
+ let(:node) { Chef::Node.new }
23
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
24
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
25
+ let(:resource) { Chef::Resource::AptPreference.new("libmysqlclient16", run_context) }
26
+
27
+ it "should create a new Chef::Resource::AptPreference" do
28
+ expect(resource).to be_a_kind_of(Chef::Resource)
29
+ expect(resource).to be_a_kind_of(Chef::Resource::AptPreference)
30
+ end
31
+
32
+ it "should resolve to a Noop class when apt-get is not found" do
33
+ expect(Chef::Provider::AptPreference).to receive(:which).with("apt-get").and_return(false)
34
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
35
+ end
36
+
37
+ it "should resolve to a AptPreference class when apt-get is found" do
38
+ expect(Chef::Provider::AptPreference).to receive(:which).with("apt-get").and_return(true)
39
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::AptPreference)
40
+ end
41
+ end
@@ -77,7 +77,7 @@ describe Chef::Resource::Execute do
77
77
  shared_examples_for "it received invalid credentials" do
78
78
  describe "the validation method" do
79
79
  it "should raise an error" do
80
- expect { execute_resource.validate_identity_platform(username, password, domain) }.to raise_error(ArgumentError)
80
+ expect { execute_resource.validate_identity_platform(username, password, domain, elevated) }.to raise_error(ArgumentError)
81
81
  end
82
82
  end
83
83
  end
@@ -113,6 +113,7 @@ describe Chef::Resource::Execute do
113
113
 
114
114
  context "when a valid username is specified" do
115
115
  let(:username) { "starchild" }
116
+ let(:elevated) { false }
116
117
  context "when a valid domain is specified" do
117
118
  let(:domain) { "mothership" }
118
119
 
@@ -129,6 +130,7 @@ describe Chef::Resource::Execute do
129
130
 
130
131
  context "when the domain is not specified" do
131
132
  let(:domain) { nil }
133
+ let(:elevated) { false }
132
134
 
133
135
  context "when the password is not specified" do
134
136
  let(:password) { nil }
@@ -179,6 +181,24 @@ describe Chef::Resource::Execute do
179
181
  it_behaves_like "it received invalid username and domain"
180
182
  end
181
183
  end
184
+
185
+ context "when elevated is passed" do
186
+ let(:elevated) { true }
187
+
188
+ context "when username and password are not passed" do
189
+ let(:username) { nil }
190
+ let(:domain) { nil }
191
+ let(:password) { nil }
192
+ it_behaves_like "it received invalid credentials"
193
+ end
194
+
195
+ context "when username and password are passed" do
196
+ let(:username) { "user" }
197
+ let(:domain) { nil }
198
+ let(:password) { "we.funk!" }
199
+ it_behaves_like "it received valid credentials"
200
+ end
201
+ end
182
202
  end
183
203
 
184
204
  context "when not running on Windows" do
@@ -59,9 +59,9 @@ describe Chef::Resource::PowershellScript do
59
59
  allow(resource).to receive(:updated).and_return(true)
60
60
  end
61
61
 
62
- it "inherits exactly the :cwd, :environment, :group, :path, :user, :umask, and :architecture attributes from a parent resource class" do
62
+ it "inherits exactly the :cwd, :environment, :group, :path, :user, :umask, :architecture, :elevated attributes from a parent resource class" do
63
63
  inherited_difference = Chef::Resource::PowershellScript.guard_inherited_attributes -
64
- [:cwd, :environment, :group, :path, :user, :umask, :architecture ]
64
+ [:cwd, :environment, :group, :path, :user, :umask, :architecture, :elevated ]
65
65
 
66
66
  expect(inherited_difference).to eq([])
67
67
  end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Author:: Tim Smith (<tsmith@chef.io>)
3
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ describe Chef::Resource::ZypperRepository do
22
+ let(:node) { Chef::Node.new }
23
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
24
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
25
+ let(:resource) { Chef::Resource::ZypperRepository.new("repo-source", run_context) }
26
+
27
+ context "on linux", :linux_only do
28
+ it "should create a new Chef::Resource::ZypperRepository" do
29
+ expect(resource).to be_a_kind_of(Chef::Resource)
30
+ expect(resource).to be_a_kind_of(Chef::Resource::ZypperRepository)
31
+ end
32
+
33
+ it "should have a name of repo-source" do
34
+ expect(resource.name).to eql("repo-source")
35
+ end
36
+
37
+ it "should have a default action of create" do
38
+ expect(resource.action).to eql([:create])
39
+ end
40
+
41
+ it "supports all valid actions" do
42
+ expect { resource.action :add }.not_to raise_error
43
+ expect { resource.action :remove }.not_to raise_error
44
+ expect { resource.action :create }.not_to raise_error
45
+ expect { resource.action :refresh }.not_to raise_error
46
+ expect { resource.action :delete }.to raise_error(ArgumentError)
47
+ end
48
+
49
+ it "should resolve to a Noop class when zypper is not found" do
50
+ expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(false)
51
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
52
+ end
53
+
54
+ it "should resolve to a ZypperRepository class when zypper is found" do
55
+ expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(true)
56
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository)
57
+ end
58
+ end
59
+
60
+ context "on windows", :windows_only do
61
+ it "should resolve to a NoOp provider" do
62
+ expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop)
63
+ end
64
+ end
65
+ end
@@ -22,9 +22,10 @@ require "chef/search/query"
22
22
  describe Chef::Search::Query do
23
23
  let(:rest) { double("Chef::ServerAPI") }
24
24
  let(:query) { Chef::Search::Query.new }
25
+ let(:default_rows) { 1000 }
25
26
 
26
27
  shared_context "filtered search" do
27
- let(:query_string) { "search/node?q=platform:rhel&start=0" }
28
+ let(:query_string) { "search/node?q=platform:rhel&start=0&rows=#{default_rows}" }
28
29
  let(:server_url) { "https://api.opscode.com/organizations/opscode/nodes" }
29
30
  let(:args) { { filter_key => filter_hash } }
30
31
  let(:filter_hash) do
@@ -81,8 +82,8 @@ describe Chef::Search::Query do
81
82
  end
82
83
 
83
84
  describe "search" do
84
- let(:query_string) { "search/node?q=platform:rhel&start=0" }
85
- let(:query_string_continue) { "search/node?q=platform:rhel&start=4" }
85
+ let(:query_string) { "search/node?q=platform:rhel&start=0&rows=#{default_rows}" }
86
+ let(:query_string_continue) { "search/node?q=platform:rhel&start=4&rows=#{default_rows}" }
86
87
  let(:query_string_with_rows) { "search/node?q=platform:rhel&start=0&rows=4" }
87
88
  let(:query_string_continue_with_rows) { "search/node?q=platform:rhel&start=4&rows=4" }
88
89
 
@@ -150,12 +151,6 @@ describe Chef::Search::Query do
150
151
  "total" => 4,
151
152
  } end
152
153
 
153
- let(:big_response) do
154
- r = response.dup
155
- r["total"] = 8
156
- r
157
- end
158
-
159
154
  let(:big_response_empty) do
160
155
  {
161
156
  "start" => 0,
@@ -178,17 +173,17 @@ describe Chef::Search::Query do
178
173
  end
179
174
 
180
175
  it "queries for every object of a type by default" do
181
- expect(rest).to receive(:get).with("search/node?q=*:*&start=0").and_return(response)
176
+ expect(rest).to receive(:get).with("search/node?q=*:*&start=0&rows=#{default_rows}").and_return(response)
182
177
  query.search(:node)
183
178
  end
184
179
 
185
180
  it "allows a custom query" do
186
- expect(rest).to receive(:get).with("search/node?q=platform:rhel&start=0").and_return(response)
181
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&start=0&rows=#{default_rows}").and_return(response)
187
182
  query.search(:node, "platform:rhel")
188
183
  end
189
184
 
190
185
  it "lets you set a starting object" do
191
- expect(rest).to receive(:get).with("search/node?q=platform:rhel&start=2").and_return(response)
186
+ expect(rest).to receive(:get).with("search/node?q=platform:rhel&start=2&rows=#{default_rows}").and_return(response)
192
187
  query.search(:node, "platform:rhel", start: 2)
193
188
  end
194
189
 
@@ -221,9 +216,9 @@ describe Chef::Search::Query do
221
216
  query.search(:node, "*:*", start: 0, rows: 4) { |r| @call_me.do(r) }
222
217
  end
223
218
 
224
- it "sends multiple API requests when the server indicates there is more data" do
225
- expect(rest).to receive(:get).with(query_string).and_return(big_response)
226
- expect(rest).to receive(:get).with(query_string_continue).and_return(big_response_end)
219
+ # This test would loop infinitely if pagination didn't advance
220
+ it "paginates correctly in the face of filtered nodes without explicit rows" do
221
+ allow(rest).to receive(:get).with(query_string).and_return(big_response_empty)
227
222
  query.search(:node, "platform:rhel") do |r|
228
223
  nil
229
224
  end
@@ -239,21 +234,21 @@ describe Chef::Search::Query do
239
234
 
240
235
  it "fuzzifies node searches when fuzz is set" do
241
236
  expect(rest).to receive(:get).with(
242
- "search/node?q=tags:*free.messi*%20OR%20roles:*free.messi*%20OR%20fqdn:*free.messi*%20OR%20addresses:*free.messi*%20OR%20policy_name:*free.messi*%20OR%20policy_group:*free.messi*&start=0"
237
+ "search/node?q=tags:*free.messi*%20OR%20roles:*free.messi*%20OR%20fqdn:*free.messi*%20OR%20addresses:*free.messi*%20OR%20policy_name:*free.messi*%20OR%20policy_group:*free.messi*&start=0&rows=#{default_rows}"
243
238
  ).and_return(response)
244
239
  query.search(:node, "free.messi", fuzz: true)
245
240
  end
246
241
 
247
242
  it "does not fuzzify node searches when fuzz is not set" do
248
243
  expect(rest).to receive(:get).with(
249
- "search/node?q=free.messi&start=0"
244
+ "search/node?q=free.messi&start=0&rows=#{default_rows}"
250
245
  ).and_return(response)
251
246
  query.search(:node, "free.messi")
252
247
  end
253
248
 
254
249
  it "does not fuzzify client searches" do
255
250
  expect(rest).to receive(:get).with(
256
- "search/client?q=messi&start=0"
251
+ "search/client?q=messi&start=0&rows=#{default_rows}"
257
252
  ).and_return(response)
258
253
  query.search(:client, "messi", fuzz: true)
259
254
  end
@@ -26,12 +26,22 @@ b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I
26
26
  YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12
27
27
  2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo
28
28
  Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ==
29
- -----END RSA PRIVATE KEY-----"
29
+ -----END RSA PRIVATE KEY-----".freeze
30
30
 
31
31
  describe Chef::ServerAPI do
32
32
  let(:url) { "http://chef.example.com:4000" }
33
33
  let(:key_path) { "/tmp/foo" }
34
34
 
35
+ let(:client) do
36
+ Chef::ServerAPI.new(url)
37
+ end
38
+
39
+ before do
40
+ Chef::Config[:node_name] = "silent-bob"
41
+ Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
42
+ Chef::Config[:http_retry_delay] = 0
43
+ end
44
+
35
45
  describe "#initialize" do
36
46
  it "uses the configured key file" do
37
47
  allow(IO).to receive(:read).with(key_path).and_return(SIGNING_KEY_DOT_PEM)
@@ -47,4 +57,68 @@ describe Chef::ServerAPI do
47
57
  expect(api.options[:raw_key]).to eql(SIGNING_KEY_DOT_PEM)
48
58
  end
49
59
  end
60
+
61
+ context "versioned apis" do
62
+ class VersionedClassV0
63
+ extend Chef::Mixin::VersionedAPI
64
+ minimum_api_version 0
65
+ end
66
+
67
+ class VersionedClassV2
68
+ extend Chef::Mixin::VersionedAPI
69
+ minimum_api_version 2
70
+ end
71
+
72
+ class VersionedClassVersions
73
+ extend Chef::Mixin::VersionedAPIFactory
74
+ add_versioned_api_class VersionedClassV0
75
+ add_versioned_api_class VersionedClassV2
76
+ end
77
+
78
+ before do
79
+ Chef::ServerAPIVersions.instance.reset!
80
+ end
81
+
82
+ let(:versioned_client) do
83
+ Chef::ServerAPI.new(url, version_class: VersionedClassVersions)
84
+ end
85
+
86
+ it "on protocol negotiation it posts the same message body without doubly-encoding the json string" do
87
+ WebMock.disable_net_connect!
88
+ post_body = { bar: "baz" }
89
+ body_406 = '{"error":"invalid-x-ops-server-api-version","message":"Specified version 2 not supported","min_version":0,"max_version":1}'
90
+ stub_request(:post, "http://chef.example.com:4000/foo").with(body: post_body.to_json, headers: { "X-Ops-Server-Api-Version" => "2" }).to_return(status: [406, "Not Acceptable"], body: body_406 )
91
+ stub_request(:post, "http://chef.example.com:4000/foo").with(body: post_body.to_json, headers: { "X-Ops-Server-Api-Version" => "0" }).to_return(status: 200, body: "", headers: {})
92
+ versioned_client.post("foo", post_body)
93
+ end
94
+ end
95
+
96
+ context "retrying normal requests" do
97
+ it "500 on a post retries and posts correctly " do
98
+ WebMock.disable_net_connect!
99
+ post_body = { bar: "baz" }
100
+ headers = { "Accept" => "application/json", "Content-Type" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "Content-Length" => "13", "Host" => "chef.example.com:4000", "X-Chef-Version" => Chef::VERSION, "X-Ops-Sign" => "algorithm=sha1;version=1.1;", "X-Ops-Userid" => "silent-bob" }
101
+ stub_request(:post, "http://chef.example.com:4000/foo").with(body: post_body.to_json, headers: headers).to_return(status: [500, "Internal Server Error"])
102
+ stub_request(:post, "http://chef.example.com:4000/foo").with(body: post_body.to_json, headers: headers).to_return(status: 200, body: "", headers: {})
103
+ client.post("foo", post_body)
104
+ end
105
+
106
+ it "500 on a put retries and puts correctly " do
107
+ WebMock.disable_net_connect!
108
+ put_body = { bar: "baz" }
109
+ headers = { "Accept" => "application/json", "Content-Type" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "Content-Length" => "13", "Host" => "chef.example.com:4000", "X-Chef-Version" => Chef::VERSION, "X-Ops-Sign" => "algorithm=sha1;version=1.1;", "X-Ops-Userid" => "silent-bob" }
110
+ stub_request(:put, "http://chef.example.com:4000/foo").with(body: put_body.to_json, headers: headers).to_return(status: [500, "Internal Server Error"])
111
+ stub_request(:put, "http://chef.example.com:4000/foo").with(body: put_body.to_json, headers: headers).to_return(status: 200, body: "", headers: {})
112
+ client.put("foo", put_body)
113
+ end
114
+
115
+ it "500 on a get retries and gets correctly " do
116
+ WebMock.disable_net_connect!
117
+ get_body = { bar: "baz" }
118
+ headers = { "Accept" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "Host" => "chef.example.com:4000", "X-Chef-Version" => Chef::VERSION, "X-Ops-Sign" => "algorithm=sha1;version=1.1;", "X-Ops-Userid" => "silent-bob" }
119
+ stub_request(:get, "http://chef.example.com:4000/foo").with(headers: headers).to_return(status: [500, "Internal Server Error"])
120
+ stub_request(:get, "http://chef.example.com:4000/foo").with(headers: headers).to_return(status: 200, body: "", headers: {})
121
+ client.get("foo")
122
+ end
123
+ end
50
124
  end
@@ -22,10 +22,28 @@ describe Chef::ServerAPIVersions do
22
22
  Chef::ServerAPIVersions.instance.reset!
23
23
  end
24
24
 
25
+ describe "#reset!" do
26
+ it "resets the version information" do
27
+ Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
28
+ Chef::ServerAPIVersions.instance.reset!
29
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to be_nil
30
+ end
31
+
32
+ it "resets the unversioned flag" do
33
+ Chef::ServerAPIVersions.instance.unversioned!
34
+ Chef::ServerAPIVersions.instance.reset!
35
+ expect(Chef::ServerAPIVersions.instance.unversioned?).to be false
36
+ end
37
+ end
38
+
25
39
  describe "#min_server_version" do
26
40
  it "returns nil if no versions have been recorded" do
27
41
  expect(Chef::ServerAPIVersions.instance.min_server_version).to be_nil
28
42
  end
43
+ it "returns 0 if unversioned" do
44
+ Chef::ServerAPIVersions.instance.unversioned!
45
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to eq(0)
46
+ end
29
47
  it "returns the correct value" do
30
48
  Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
31
49
  expect(Chef::ServerAPIVersions.instance.min_server_version).to eq(0)
@@ -36,6 +54,10 @@ describe Chef::ServerAPIVersions do
36
54
  it "returns nil if no versions have been recorded" do
37
55
  expect(Chef::ServerAPIVersions.instance.max_server_version).to be_nil
38
56
  end
57
+ it "returns 0 if unversioned" do
58
+ Chef::ServerAPIVersions.instance.unversioned!
59
+ expect(Chef::ServerAPIVersions.instance.min_server_version).to eq(0)
60
+ end
39
61
  it "returns the correct value" do
40
62
  Chef::ServerAPIVersions.instance.set_versions({ "min_version" => 0, "max_version" => 2 })
41
63
  expect(Chef::ServerAPIVersions.instance.max_server_version).to eq(2)