chef 12.4.0-universal-mingw32 → 12.4.1-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/api_client.rb +31 -129
  3. data/lib/chef/api_client_v1.rb +325 -0
  4. data/lib/chef/chef_class.rb +15 -7
  5. data/lib/chef/chef_fs/file_system/chef_server_root_dir.rb +2 -2
  6. data/lib/chef/dsl/resources.rb +6 -4
  7. data/lib/chef/exceptions.rb +2 -2
  8. data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +2 -1
  9. data/lib/chef/knife/bootstrap/templates/chef-full.erb +4 -4
  10. data/lib/chef/knife/client_bulk_delete.rb +2 -2
  11. data/lib/chef/knife/client_create.rb +4 -4
  12. data/lib/chef/knife/client_delete.rb +3 -3
  13. data/lib/chef/knife/client_edit.rb +10 -2
  14. data/lib/chef/knife/client_list.rb +2 -2
  15. data/lib/chef/knife/client_reregister.rb +2 -2
  16. data/lib/chef/knife/client_show.rb +2 -2
  17. data/lib/chef/knife/osc_user_create.rb +3 -3
  18. data/lib/chef/knife/osc_user_delete.rb +2 -2
  19. data/lib/chef/knife/osc_user_edit.rb +3 -3
  20. data/lib/chef/knife/osc_user_list.rb +2 -2
  21. data/lib/chef/knife/osc_user_reregister.rb +2 -2
  22. data/lib/chef/knife/osc_user_show.rb +2 -2
  23. data/lib/chef/knife/user_create.rb +3 -3
  24. data/lib/chef/knife/user_delete.rb +4 -4
  25. data/lib/chef/knife/user_edit.rb +3 -3
  26. data/lib/chef/knife/user_list.rb +2 -2
  27. data/lib/chef/knife/user_reregister.rb +2 -2
  28. data/lib/chef/knife/user_show.rb +2 -2
  29. data/lib/chef/node_map.rb +14 -18
  30. data/lib/chef/platform/handler_map.rb +45 -0
  31. data/lib/chef/platform/priority_map.rb +19 -32
  32. data/lib/chef/platform/provider_handler_map.rb +29 -0
  33. data/lib/chef/platform/provider_mapping.rb +3 -2
  34. data/lib/chef/platform/resource_handler_map.rb +29 -0
  35. data/lib/chef/platform/resource_priority_map.rb +0 -6
  36. data/lib/chef/provider.rb +1 -1
  37. data/lib/chef/provider/dsc_resource.rb +2 -2
  38. data/lib/chef/provider/dsc_script.rb +1 -1
  39. data/lib/chef/provider/mount/aix.rb +1 -1
  40. data/lib/chef/provider/package.rb +0 -31
  41. data/lib/chef/provider/package/aix.rb +1 -0
  42. data/lib/chef/provider/package/apt.rb +1 -0
  43. data/lib/chef/provider/package/homebrew.rb +1 -0
  44. data/lib/chef/provider/package/ips.rb +1 -0
  45. data/lib/chef/provider/package/macports.rb +1 -0
  46. data/lib/chef/provider/package/openbsd.rb +1 -0
  47. data/lib/chef/provider/package/pacman.rb +1 -0
  48. data/lib/chef/provider/package/paludis.rb +1 -0
  49. data/lib/chef/provider/package/portage.rb +2 -0
  50. data/lib/chef/provider/package/smartos.rb +1 -0
  51. data/lib/chef/provider/package/solaris.rb +2 -0
  52. data/lib/chef/provider/package/yum.rb +1 -0
  53. data/lib/chef/provider/package/zypper.rb +1 -0
  54. data/lib/chef/provider/service.rb +4 -22
  55. data/lib/chef/provider/service/debian.rb +2 -0
  56. data/lib/chef/provider/service/insserv.rb +2 -0
  57. data/lib/chef/provider/service/invokercd.rb +2 -0
  58. data/lib/chef/provider/service/openbsd.rb +1 -1
  59. data/lib/chef/provider/service/redhat.rb +2 -0
  60. data/lib/chef/provider/service/upstart.rb +3 -0
  61. data/lib/chef/provider_resolver.rb +59 -53
  62. data/lib/chef/resource.rb +22 -73
  63. data/lib/chef/resource/dsc_script.rb +1 -1
  64. data/lib/chef/resource/ips_package.rb +1 -0
  65. data/lib/chef/resource/mount.rb +8 -0
  66. data/lib/chef/resource/openbsd_package.rb +0 -11
  67. data/lib/chef/resource/solaris_package.rb +1 -4
  68. data/lib/chef/resource_resolver.rb +54 -26
  69. data/lib/chef/run_list/versioned_recipe_list.rb +6 -5
  70. data/lib/chef/user.rb +52 -188
  71. data/lib/chef/user_v1.rb +335 -0
  72. data/lib/chef/version.rb +1 -1
  73. data/spec/data/trusted_certs/opscode.pem +53 -56
  74. data/spec/functional/provider/whyrun_safe_ruby_block_spec.rb +1 -1
  75. data/spec/functional/resource/package_spec.rb +0 -2
  76. data/spec/integration/recipes/recipe_dsl_spec.rb +661 -126
  77. data/spec/spec_helper.rb +19 -13
  78. data/spec/support/shared/unit/api_versioning.rb +2 -2
  79. data/spec/unit/api_client_spec.rb +22 -201
  80. data/spec/unit/api_client_v1_spec.rb +457 -0
  81. data/spec/unit/knife/client_bulk_delete_spec.rb +4 -4
  82. data/spec/unit/knife/client_create_spec.rb +1 -1
  83. data/spec/unit/knife/client_delete_spec.rb +3 -3
  84. data/spec/unit/knife/client_edit_spec.rb +14 -1
  85. data/spec/unit/knife/client_list_spec.rb +1 -1
  86. data/spec/unit/knife/client_reregister_spec.rb +2 -2
  87. data/spec/unit/knife/client_show_spec.rb +2 -2
  88. data/spec/unit/knife/osc_user_create_spec.rb +5 -5
  89. data/spec/unit/knife/osc_user_delete_spec.rb +1 -1
  90. data/spec/unit/knife/osc_user_edit_spec.rb +1 -1
  91. data/spec/unit/knife/osc_user_list_spec.rb +1 -1
  92. data/spec/unit/knife/osc_user_reregister_spec.rb +1 -1
  93. data/spec/unit/knife/osc_user_show_spec.rb +1 -1
  94. data/spec/unit/knife/user_create_spec.rb +1 -1
  95. data/spec/unit/knife/user_delete_spec.rb +2 -2
  96. data/spec/unit/knife/user_edit_spec.rb +2 -2
  97. data/spec/unit/knife/user_list_spec.rb +1 -1
  98. data/spec/unit/knife/user_reregister_spec.rb +1 -1
  99. data/spec/unit/knife/user_show_spec.rb +2 -2
  100. data/spec/unit/lwrp_spec.rb +146 -134
  101. data/spec/unit/node_map_spec.rb +12 -0
  102. data/spec/unit/platform_spec.rb +1 -1
  103. data/spec/unit/provider/deploy_spec.rb +1 -1
  104. data/spec/unit/provider/dsc_resource_spec.rb +3 -3
  105. data/spec/unit/provider/dsc_script_spec.rb +2 -2
  106. data/spec/unit/provider_resolver_spec.rb +170 -135
  107. data/spec/unit/recipe_spec.rb +3 -3
  108. data/spec/unit/resource/breakpoint_spec.rb +1 -1
  109. data/spec/unit/resource/cron_spec.rb +1 -1
  110. data/spec/unit/resource/directory_spec.rb +1 -1
  111. data/spec/unit/resource/dsc_resource_spec.rb +1 -1
  112. data/spec/unit/resource/dsc_script_spec.rb +2 -2
  113. data/spec/unit/resource/env_spec.rb +1 -1
  114. data/spec/unit/resource/erl_call_spec.rb +1 -1
  115. data/spec/unit/resource/file_spec.rb +1 -1
  116. data/spec/unit/resource/group_spec.rb +1 -1
  117. data/spec/unit/resource/link_spec.rb +1 -1
  118. data/spec/unit/resource/mdadm_spec.rb +1 -1
  119. data/spec/unit/resource/mount_spec.rb +1 -1
  120. data/spec/unit/resource/ohai_spec.rb +1 -1
  121. data/spec/unit/resource/registry_key_spec.rb +1 -1
  122. data/spec/unit/resource/route_spec.rb +1 -1
  123. data/spec/unit/resource/ruby_block_spec.rb +3 -3
  124. data/spec/unit/resource/user_spec.rb +1 -1
  125. data/spec/unit/resource/windows_service_spec.rb +1 -1
  126. data/spec/unit/resource_resolver_spec.rb +8 -4
  127. data/spec/unit/resource_spec.rb +89 -3
  128. data/spec/unit/run_list/versioned_recipe_list_spec.rb +115 -48
  129. data/spec/unit/user_spec.rb +97 -405
  130. data/spec/unit/user_v1_spec.rb +584 -0
  131. metadata +11 -6
  132. data/lib/chef/osc_user.rb +0 -194
  133. data/spec/unit/osc_user_spec.rb +0 -276
@@ -0,0 +1,584 @@
1
+ #
2
+ # Author:: Steven Danna (steve@opscode.com)
3
+ # Copyright:: Copyright (c) 2012 Opscode, 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
+ require 'chef/user_v1'
22
+ require 'tempfile'
23
+
24
+ describe Chef::UserV1 do
25
+ before(:each) do
26
+ @user = Chef::UserV1.new
27
+ end
28
+
29
+ shared_examples_for "string fields with no contraints" do
30
+ it "should let you set the public key" do
31
+ expect(@user.send(method, "some_string")).to eq("some_string")
32
+ end
33
+
34
+ it "should return the current public key" do
35
+ @user.send(method, "some_string")
36
+ expect(@user.send(method)).to eq("some_string")
37
+ end
38
+
39
+ it "should throw an ArgumentError if you feed it something lame" do
40
+ expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError)
41
+ end
42
+ end
43
+
44
+ shared_examples_for "boolean fields with no constraints" do
45
+ it "should let you set the field" do
46
+ expect(@user.send(method, true)).to eq(true)
47
+ end
48
+
49
+ it "should return the current field value" do
50
+ @user.send(method, true)
51
+ expect(@user.send(method)).to eq(true)
52
+ end
53
+
54
+ it "should return the false value when false" do
55
+ @user.send(method, false)
56
+ expect(@user.send(method)).to eq(false)
57
+ end
58
+
59
+ it "should throw an ArgumentError if you feed it anything but true or false" do
60
+ expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError)
61
+ end
62
+ end
63
+
64
+ describe "initialize" do
65
+ it "should be a Chef::UserV1" do
66
+ expect(@user).to be_a_kind_of(Chef::UserV1)
67
+ end
68
+ end
69
+
70
+ describe "username" do
71
+ it "should let you set the username to a string" do
72
+ expect(@user.username("ops_master")).to eq("ops_master")
73
+ end
74
+
75
+ it "should return the current username" do
76
+ @user.username "ops_master"
77
+ expect(@user.username).to eq("ops_master")
78
+ end
79
+
80
+ # It is not feasible to check all invalid characters. Here are a few
81
+ # that we probably care about.
82
+ it "should not accept invalid characters" do
83
+ # capital letters
84
+ expect { @user.username "Bar" }.to raise_error(ArgumentError)
85
+ # slashes
86
+ expect { @user.username "foo/bar" }.to raise_error(ArgumentError)
87
+ # ?
88
+ expect { @user.username "foo?" }.to raise_error(ArgumentError)
89
+ # &
90
+ expect { @user.username "foo&" }.to raise_error(ArgumentError)
91
+ end
92
+
93
+
94
+ it "should not accept spaces" do
95
+ expect { @user.username "ops master" }.to raise_error(ArgumentError)
96
+ end
97
+
98
+ it "should throw an ArgumentError if you feed it anything but a string" do
99
+ expect { @user.username Hash.new }.to raise_error(ArgumentError)
100
+ end
101
+ end
102
+
103
+ describe "boolean fields" do
104
+ describe "create_key" do
105
+ it_should_behave_like "boolean fields with no constraints" do
106
+ let(:method) { :create_key }
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "string fields" do
112
+ describe "public_key" do
113
+ it_should_behave_like "string fields with no contraints" do
114
+ let(:method) { :public_key }
115
+ end
116
+ end
117
+
118
+ describe "private_key" do
119
+ it_should_behave_like "string fields with no contraints" do
120
+ let(:method) { :private_key }
121
+ end
122
+ end
123
+
124
+ describe "display_name" do
125
+ it_should_behave_like "string fields with no contraints" do
126
+ let(:method) { :display_name }
127
+ end
128
+ end
129
+
130
+ describe "first_name" do
131
+ it_should_behave_like "string fields with no contraints" do
132
+ let(:method) { :first_name }
133
+ end
134
+ end
135
+
136
+ describe "middle_name" do
137
+ it_should_behave_like "string fields with no contraints" do
138
+ let(:method) { :middle_name }
139
+ end
140
+ end
141
+
142
+ describe "last_name" do
143
+ it_should_behave_like "string fields with no contraints" do
144
+ let(:method) { :last_name }
145
+ end
146
+ end
147
+
148
+ describe "email" do
149
+ it_should_behave_like "string fields with no contraints" do
150
+ let(:method) { :email }
151
+ end
152
+ end
153
+
154
+ describe "password" do
155
+ it_should_behave_like "string fields with no contraints" do
156
+ let(:method) { :password }
157
+ end
158
+ end
159
+ end
160
+
161
+ describe "when serializing to JSON" do
162
+ before(:each) do
163
+ @user.username("black")
164
+ @json = @user.to_json
165
+ end
166
+
167
+ it "serializes as a JSON object" do
168
+ expect(@json).to match(/^\{.+\}$/)
169
+ end
170
+
171
+ it "includes the username value" do
172
+ expect(@json).to include(%q{"username":"black"})
173
+ end
174
+
175
+ it "includes the display name when present" do
176
+ @user.display_name("get_displayed")
177
+ expect(@user.to_json).to include(%{"display_name":"get_displayed"})
178
+ end
179
+
180
+ it "does not include the display name if not present" do
181
+ expect(@json).not_to include("display_name")
182
+ end
183
+
184
+ it "includes the first name when present" do
185
+ @user.first_name("char")
186
+ expect(@user.to_json).to include(%{"first_name":"char"})
187
+ end
188
+
189
+ it "does not include the first name if not present" do
190
+ expect(@json).not_to include("first_name")
191
+ end
192
+
193
+ it "includes the middle name when present" do
194
+ @user.middle_name("man")
195
+ expect(@user.to_json).to include(%{"middle_name":"man"})
196
+ end
197
+
198
+ it "does not include the middle name if not present" do
199
+ expect(@json).not_to include("middle_name")
200
+ end
201
+
202
+ it "includes the last name when present" do
203
+ @user.last_name("der")
204
+ expect(@user.to_json).to include(%{"last_name":"der"})
205
+ end
206
+
207
+ it "does not include the last name if not present" do
208
+ expect(@json).not_to include("last_name")
209
+ end
210
+
211
+ it "includes the email when present" do
212
+ @user.email("charmander@pokemon.poke")
213
+ expect(@user.to_json).to include(%{"email":"charmander@pokemon.poke"})
214
+ end
215
+
216
+ it "does not include the email if not present" do
217
+ expect(@json).not_to include("email")
218
+ end
219
+
220
+ it "includes the public key when present" do
221
+ @user.public_key("crowes")
222
+ expect(@user.to_json).to include(%{"public_key":"crowes"})
223
+ end
224
+
225
+ it "does not include the public key if not present" do
226
+ expect(@json).not_to include("public_key")
227
+ end
228
+
229
+ it "includes the private key when present" do
230
+ @user.private_key("monkeypants")
231
+ expect(@user.to_json).to include(%q{"private_key":"monkeypants"})
232
+ end
233
+
234
+ it "does not include the private key if not present" do
235
+ expect(@json).not_to include("private_key")
236
+ end
237
+
238
+ it "includes the password if present" do
239
+ @user.password "password"
240
+ expect(@user.to_json).to include(%q{"password":"password"})
241
+ end
242
+
243
+ it "does not include the password if not present" do
244
+ expect(@json).not_to include("password")
245
+ end
246
+
247
+ include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
248
+ let(:jsonable) { @user }
249
+ end
250
+ end
251
+
252
+ describe "when deserializing from JSON" do
253
+ before(:each) do
254
+ user = {
255
+ "username" => "mr_spinks",
256
+ "display_name" => "displayed",
257
+ "first_name" => "char",
258
+ "middle_name" => "man",
259
+ "last_name" => "der",
260
+ "email" => "charmander@pokemon.poke",
261
+ "password" => "password",
262
+ "public_key" => "turtles",
263
+ "private_key" => "pandas",
264
+ "create_key" => false
265
+ }
266
+ @user = Chef::UserV1.from_json(Chef::JSONCompat.to_json(user))
267
+ end
268
+
269
+ it "should deserialize to a Chef::UserV1 object" do
270
+ expect(@user).to be_a_kind_of(Chef::UserV1)
271
+ end
272
+
273
+ it "preserves the username" do
274
+ expect(@user.username).to eq("mr_spinks")
275
+ end
276
+
277
+ it "preserves the display name if present" do
278
+ expect(@user.display_name).to eq("displayed")
279
+ end
280
+
281
+ it "preserves the first name if present" do
282
+ expect(@user.first_name).to eq("char")
283
+ end
284
+
285
+ it "preserves the middle name if present" do
286
+ expect(@user.middle_name).to eq("man")
287
+ end
288
+
289
+ it "preserves the last name if present" do
290
+ expect(@user.last_name).to eq("der")
291
+ end
292
+
293
+ it "preserves the email if present" do
294
+ expect(@user.email).to eq("charmander@pokemon.poke")
295
+ end
296
+
297
+ it "includes the password if present" do
298
+ expect(@user.password).to eq("password")
299
+ end
300
+
301
+ it "preserves the public key if present" do
302
+ expect(@user.public_key).to eq("turtles")
303
+ end
304
+
305
+ it "includes the private key if present" do
306
+ expect(@user.private_key).to eq("pandas")
307
+ end
308
+
309
+ it "includes the create key status if not nil" do
310
+ expect(@user.create_key).to be_falsey
311
+ end
312
+ end
313
+
314
+ describe "Versioned API Interactions" do
315
+ let(:response_406) { OpenStruct.new(:code => '406') }
316
+ let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
317
+
318
+ before (:each) do
319
+ @user = Chef::UserV1.new
320
+ allow(@user).to receive(:chef_root_rest_v0).and_return(double('chef rest root v0 object'))
321
+ allow(@user).to receive(:chef_root_rest_v1).and_return(double('chef rest root v1 object'))
322
+ end
323
+
324
+ describe "update" do
325
+ before do
326
+ # populate all fields that are valid between V0 and V1
327
+ @user.username "some_username"
328
+ @user.display_name "some_display_name"
329
+ @user.first_name "some_first_name"
330
+ @user.middle_name "some_middle_name"
331
+ @user.last_name "some_last_name"
332
+ @user.email "some_email"
333
+ @user.password "some_password"
334
+ end
335
+
336
+ let(:payload) {
337
+ {
338
+ :username => "some_username",
339
+ :display_name => "some_display_name",
340
+ :first_name => "some_first_name",
341
+ :middle_name => "some_middle_name",
342
+ :last_name => "some_last_name",
343
+ :email => "some_email",
344
+ :password => "some_password"
345
+ }
346
+ }
347
+
348
+ context "when server API V1 is valid on the Chef Server receiving the request" do
349
+ context "when the user submits valid data" do
350
+ it "properly updates the user" do
351
+ expect(@user.chef_root_rest_v1).to receive(:put).with("users/some_username", payload).and_return({})
352
+ @user.update
353
+ end
354
+ end
355
+ end
356
+
357
+ context "when server API V1 is not valid on the Chef Server receiving the request" do
358
+ let(:payload) {
359
+ {
360
+ :username => "some_username",
361
+ :display_name => "some_display_name",
362
+ :first_name => "some_first_name",
363
+ :middle_name => "some_middle_name",
364
+ :last_name => "some_last_name",
365
+ :email => "some_email",
366
+ :password => "some_password",
367
+ :public_key => "some_public_key"
368
+ }
369
+ }
370
+
371
+ before do
372
+ @user.public_key "some_public_key"
373
+ allow(@user.chef_root_rest_v1).to receive(:put)
374
+ end
375
+
376
+ context "when the server returns a 400" do
377
+ let(:response_400) { OpenStruct.new(:code => '400') }
378
+ let(:exception_400) { Net::HTTPServerException.new("400 Bad Request", response_400) }
379
+
380
+ context "when the 400 was due to public / private key fields no longer being supported" do
381
+ let(:response_body_400) { '{"error":["Since Server API v1, all keys must be updated via the keys endpoint. "]}' }
382
+
383
+ before do
384
+ allow(response_400).to receive(:body).and_return(response_body_400)
385
+ allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
386
+ end
387
+
388
+ it "proceeds with the V0 PUT since it can handle public / private key fields" do
389
+ expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({})
390
+ @user.update
391
+ end
392
+
393
+ it "does not call server_client_api_version_intersection, since we know to proceed with V0 in this case" do
394
+ expect(@user).to_not receive(:server_client_api_version_intersection)
395
+ allow(@user.chef_root_rest_v0).to receive(:put).and_return({})
396
+ @user.update
397
+ end
398
+ end # when the 400 was due to public / private key fields
399
+
400
+ context "when the 400 was NOT due to public / private key fields no longer being supported" do
401
+ let(:response_body_400) { '{"error":["Some other error. "]}' }
402
+
403
+ before do
404
+ allow(response_400).to receive(:body).and_return(response_body_400)
405
+ allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
406
+ end
407
+
408
+ it "will not proceed with the V0 PUT since the original bad request was not key related" do
409
+ expect(@user.chef_root_rest_v0).to_not receive(:put).with("users/some_username", payload)
410
+ expect { @user.update }.to raise_error(exception_400)
411
+ end
412
+
413
+ it "raises the original error" do
414
+ expect { @user.update }.to raise_error(exception_400)
415
+ end
416
+
417
+ end
418
+ end # when the server returns a 400
419
+
420
+ context "when the server returns a 406" do
421
+ # from spec/support/shared/unit/api_versioning.rb
422
+ it_should_behave_like "version handling" do
423
+ let(:object) { @user }
424
+ let(:method) { :update }
425
+ let(:http_verb) { :put }
426
+ let(:rest_v1) { @user.chef_root_rest_v1 }
427
+ end
428
+
429
+ context "when the server supports API V0" do
430
+ before do
431
+ allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
432
+ allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_406)
433
+ end
434
+
435
+ it "properly updates the user" do
436
+ expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({})
437
+ @user.update
438
+ end
439
+ end # when the server supports API V0
440
+ end # when the server returns a 406
441
+
442
+ end # when server API V1 is not valid on the Chef Server receiving the request
443
+ end # update
444
+
445
+ describe "create" do
446
+ let(:payload) {
447
+ {
448
+ :username => "some_username",
449
+ :display_name => "some_display_name",
450
+ :first_name => "some_first_name",
451
+ :last_name => "some_last_name",
452
+ :email => "some_email",
453
+ :password => "some_password"
454
+ }
455
+ }
456
+ before do
457
+ @user.username "some_username"
458
+ @user.display_name "some_display_name"
459
+ @user.first_name "some_first_name"
460
+ @user.last_name "some_last_name"
461
+ @user.email "some_email"
462
+ @user.password "some_password"
463
+ end
464
+
465
+ # from spec/support/shared/unit/user_and_client_shared.rb
466
+ it_should_behave_like "user or client create" do
467
+ let(:object) { @user }
468
+ let(:error) { Chef::Exceptions::InvalidUserAttribute }
469
+ let(:rest_v0) { @user.chef_root_rest_v0 }
470
+ let(:rest_v1) { @user.chef_root_rest_v1 }
471
+ let(:url) { "users" }
472
+ end
473
+
474
+ context "when handling API V1" do
475
+ it "creates a new user via the API with a middle_name when it exists" do
476
+ @user.middle_name "some_middle_name"
477
+ expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({})
478
+ @user.create
479
+ end
480
+ end # when server API V1 is valid on the Chef Server receiving the request
481
+
482
+ context "when API V1 is not supported by the server" do
483
+ # from spec/support/shared/unit/api_versioning.rb
484
+ it_should_behave_like "version handling" do
485
+ let(:object) { @user }
486
+ let(:method) { :create }
487
+ let(:http_verb) { :post }
488
+ let(:rest_v1) { @user.chef_root_rest_v1 }
489
+ end
490
+ end
491
+
492
+ context "when handling API V0" do
493
+ before do
494
+ allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
495
+ allow(@user.chef_root_rest_v1).to receive(:post).and_raise(exception_406)
496
+ end
497
+
498
+ it "creates a new user via the API with a middle_name when it exists" do
499
+ @user.middle_name "some_middle_name"
500
+ expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({:middle_name => "some_middle_name"})).and_return({})
501
+ @user.create
502
+ end
503
+ end # when server API V1 is not valid on the Chef Server receiving the request
504
+
505
+ end # create
506
+
507
+ # DEPRECATION
508
+ # This can be removed after API V0 support is gone
509
+ describe "reregister" do
510
+ let(:payload) {
511
+ {
512
+ "username" => "some_username",
513
+ }
514
+ }
515
+
516
+ before do
517
+ @user.username "some_username"
518
+ end
519
+
520
+ context "when server API V0 is valid on the Chef Server receiving the request" do
521
+ it "creates a new object via the API" do
522
+ expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({"private_key" => true})).and_return({})
523
+ @user.reregister
524
+ end
525
+ end # when server API V0 is valid on the Chef Server receiving the request
526
+
527
+ context "when server API V0 is not supported by the Chef Server" do
528
+ # from spec/support/shared/unit/api_versioning.rb
529
+ it_should_behave_like "user and client reregister" do
530
+ let(:object) { @user }
531
+ let(:rest_v0) { @user.chef_root_rest_v0 }
532
+ end
533
+ end # when server API V0 is not supported by the Chef Server
534
+ end # reregister
535
+
536
+ end # Versioned API Interactions
537
+
538
+ describe "API Interactions" do
539
+ before (:each) do
540
+ @user = Chef::UserV1.new
541
+ @user.username "foobar"
542
+ @http_client = double("Chef::REST mock")
543
+ allow(Chef::REST).to receive(:new).and_return(@http_client)
544
+ end
545
+
546
+ describe "list" do
547
+ before(:each) do
548
+ Chef::Config[:chef_server_url] = "http://www.example.com"
549
+ @osc_response = { "admin" => "http://www.example.com/users/admin"}
550
+ @ohc_response = [ { "user" => { "username" => "admin" }} ]
551
+ allow(Chef::UserV1).to receive(:load).with("admin").and_return(@user)
552
+ @osc_inflated_response = { "admin" => @user }
553
+ end
554
+
555
+ it "lists all clients on an OHC/OPC server" do
556
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
557
+ # We expect that Chef::UserV1.list will give a consistent response
558
+ # so OHC API responses should be transformed to OSC-style output.
559
+ expect(Chef::UserV1.list).to eq(@osc_response)
560
+ end
561
+
562
+ it "inflate all clients on an OHC/OPC server" do
563
+ allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
564
+ expect(Chef::UserV1.list(true)).to eq(@osc_inflated_response)
565
+ end
566
+ end
567
+
568
+ describe "read" do
569
+ it "loads a named user from the API" do
570
+ expect(@http_client).to receive(:get).with("users/foobar").and_return({"username" => "foobar", "admin" => true, "public_key" => "pubkey"})
571
+ user = Chef::UserV1.load("foobar")
572
+ expect(user.username).to eq("foobar")
573
+ expect(user.public_key).to eq("pubkey")
574
+ end
575
+ end
576
+
577
+ describe "destroy" do
578
+ it "deletes the specified user via the API" do
579
+ expect(@http_client).to receive(:delete).with("users/foobar")
580
+ @user.destroy
581
+ end
582
+ end
583
+ end
584
+ end