chef 12.4.0 → 12.4.1

Sign up to get free protection for your applications and to get access to all the features.
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