rhc 1.2.7 → 1.3.8

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 (97) hide show
  1. data/bin/rhc +6 -8
  2. data/bin/rhc-chk +23 -10
  3. data/features/domain.feature +1 -1
  4. data/features/lib/rhc_helper.rb +3 -2
  5. data/features/lib/rhc_helper/api.rb +7 -0
  6. data/features/lib/rhc_helper/app.rb +8 -10
  7. data/features/lib/rhc_helper/domain.rb +2 -1
  8. data/features/lib/rhc_helper/runnable.rb +2 -24
  9. data/features/sshkey.feature +3 -3
  10. data/features/step_definitions/cartridge_steps.rb +6 -6
  11. data/features/step_definitions/client_steps.rb +0 -1
  12. data/features/step_definitions/sshkey_steps.rb +2 -2
  13. data/features/support/before_hooks.rb +0 -1
  14. data/features/support/env.rb +5 -3
  15. data/lib/rhc-common.rb +1 -1
  16. data/lib/rhc.rb +9 -8
  17. data/lib/rhc/auth.rb +3 -0
  18. data/lib/rhc/auth/basic.rb +54 -0
  19. data/lib/rhc/cartridge_helpers.rb +11 -5
  20. data/lib/rhc/cli.rb +4 -2
  21. data/lib/rhc/command_runner.rb +35 -30
  22. data/lib/rhc/commands.rb +127 -18
  23. data/lib/rhc/commands/account.rb +24 -0
  24. data/lib/rhc/commands/alias.rb +1 -1
  25. data/lib/rhc/commands/app.rb +210 -209
  26. data/lib/rhc/commands/apps.rb +22 -0
  27. data/lib/rhc/commands/base.rb +10 -77
  28. data/lib/rhc/commands/cartridge.rb +35 -35
  29. data/lib/rhc/commands/domain.rb +20 -13
  30. data/lib/rhc/commands/git_clone.rb +30 -0
  31. data/lib/rhc/commands/{port-forward.rb → port_forward.rb} +3 -3
  32. data/lib/rhc/commands/server.rb +28 -16
  33. data/lib/rhc/commands/setup.rb +18 -1
  34. data/lib/rhc/commands/snapshot.rb +4 -4
  35. data/lib/rhc/commands/sshkey.rb +4 -18
  36. data/lib/rhc/commands/tail.rb +32 -9
  37. data/lib/rhc/config.rb +168 -99
  38. data/lib/rhc/context_helper.rb +22 -9
  39. data/lib/rhc/core_ext.rb +41 -1
  40. data/lib/rhc/exceptions.rb +21 -5
  41. data/lib/rhc/git_helpers.rb +81 -0
  42. data/lib/rhc/help_formatter.rb +21 -1
  43. data/lib/rhc/helpers.rb +222 -87
  44. data/lib/rhc/output_helpers.rb +94 -110
  45. data/lib/rhc/rest.rb +15 -198
  46. data/lib/rhc/rest/api.rb +88 -0
  47. data/lib/rhc/rest/application.rb +29 -30
  48. data/lib/rhc/rest/attributes.rb +27 -0
  49. data/lib/rhc/rest/base.rb +29 -33
  50. data/lib/rhc/rest/cartridge.rb +42 -20
  51. data/lib/rhc/rest/client.rb +351 -89
  52. data/lib/rhc/rest/domain.rb +7 -13
  53. data/lib/rhc/rest/gear_group.rb +1 -1
  54. data/lib/rhc/rest/key.rb +7 -2
  55. data/lib/rhc/rest/mock.rb +609 -0
  56. data/lib/rhc/rest/user.rb +6 -2
  57. data/lib/rhc/{ssh_key_helpers.rb → ssh_helpers.rb} +58 -28
  58. data/lib/rhc/{targz.rb → tar_gz.rb} +0 -0
  59. data/lib/rhc/usage_templates/command_help.erb +4 -1
  60. data/lib/rhc/usage_templates/help.erb +24 -11
  61. data/lib/rhc/usage_templates/options_help.erb +14 -0
  62. data/lib/rhc/wizard.rb +283 -213
  63. data/spec/keys/example.pem +23 -0
  64. data/spec/keys/example_private.pem +27 -0
  65. data/spec/keys/server.pem +19 -0
  66. data/spec/rest_spec_helper.rb +3 -371
  67. data/spec/rhc/auth_spec.rb +226 -0
  68. data/spec/rhc/cli_spec.rb +41 -14
  69. data/spec/rhc/command_spec.rb +44 -15
  70. data/spec/rhc/commands/account_spec.rb +41 -0
  71. data/spec/rhc/commands/alias_spec.rb +16 -15
  72. data/spec/rhc/commands/app_spec.rb +115 -92
  73. data/spec/rhc/commands/apps_spec.rb +39 -0
  74. data/spec/rhc/commands/cartridge_spec.rb +134 -112
  75. data/spec/rhc/commands/domain_spec.rb +31 -86
  76. data/spec/rhc/commands/git_clone_spec.rb +56 -0
  77. data/spec/rhc/commands/{port-forward_spec.rb → port_forward_spec.rb} +27 -32
  78. data/spec/rhc/commands/server_spec.rb +28 -3
  79. data/spec/rhc/commands/setup_spec.rb +29 -11
  80. data/spec/rhc/commands/snapshot_spec.rb +4 -3
  81. data/spec/rhc/commands/sshkey_spec.rb +24 -56
  82. data/spec/rhc/commands/tail_spec.rb +26 -9
  83. data/spec/rhc/commands/threaddump_spec.rb +12 -11
  84. data/spec/rhc/config_spec.rb +211 -164
  85. data/spec/rhc/context_spec.rb +2 -0
  86. data/spec/rhc/helpers_spec.rb +242 -46
  87. data/spec/rhc/rest_application_spec.rb +42 -28
  88. data/spec/rhc/rest_client_spec.rb +110 -93
  89. data/spec/rhc/rest_spec.rb +220 -131
  90. data/spec/rhc/targz_spec.rb +1 -1
  91. data/spec/rhc/wizard_spec.rb +435 -624
  92. data/spec/spec.opts +1 -1
  93. data/spec/spec_helper.rb +140 -6
  94. data/spec/wizard_spec_helper.rb +326 -0
  95. metadata +163 -143
  96. data/lib/rhc/client.rb +0 -17
  97. data/lib/rhc/git_helper.rb +0 -59
@@ -21,6 +21,18 @@ end
21
21
  module RHC
22
22
  module Rest
23
23
  describe Client do
24
+
25
+ let(:endpoint){ mock_href }
26
+ let(:username){ nil }# mock_user }
27
+ let(:password){ nil }# mock_pass }
28
+ let(:use_debug){ false }
29
+ #let(:spec_versions){ nil }
30
+ let(:client) do
31
+ respond_to?(:spec_versions) ?
32
+ RHC::Rest::Client.new(endpoint, username, password, use_debug, spec_versions) :
33
+ RHC::Rest::Client.new(endpoint, username, password, use_debug)
34
+ end
35
+
24
36
  let(:client_links) { mock_response_links(mock_client_links) }
25
37
  let(:domain_0_links) { mock_response_links(mock_domain_links('mock_domain_0')) }
26
38
  let(:domain_1_links) { mock_response_links(mock_domain_links('mock_domain_1')) }
@@ -35,32 +47,29 @@ module RHC
35
47
  :status => 200
36
48
  })
37
49
  stub_api_request(:get, 'api_error').
38
- to_raise(RestClient::ExceptionWithResponse.new('API Error'))
50
+ to_raise(HTTPClient::BadResponseError.new('API Error'))
39
51
  stub_api_request(:get, 'other_error').
40
- to_raise(Exception.new('Other Error'))
52
+ to_raise(StandardError.new('Other Error'))
41
53
  end
42
54
 
43
55
  it "returns a client object from the required arguments" do
44
56
  credentials = Base64.strict_encode64(mock_user + ":" + mock_pass)
45
- client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass)
46
- @@headers['Authorization'].should == "Basic #{credentials}"
47
- client.send(:links).should == client_links
57
+ client.api.send(:links).should == client_links
48
58
  end
49
- it "does not add newlines to username and password > 60 characters" do
50
- username = "a" * 45
51
- password = "p" * 45
52
- client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass)
53
- @@headers['Authorization'].should_not match("\n")
54
- end
55
- it "raises an error message if the API cannot be connected" do
56
- expect { MockClient.new(mock_href('api_error'), mock_user, mock_pass) }.should raise_error
59
+ context "against an endpoint that won't connect" do
60
+ let(:endpoint){ mock_href('api_error') }
61
+ it "raises an error message" do
62
+ expect{ client.api }.should raise_error
63
+ end
57
64
  end
58
- it "raises a generic error for any other error condition" do
59
- lambda{ RHC::Rest::Client.new(mock_href('other_error'), mock_user, mock_pass) }.
60
- should raise_error("Failed to access resource: Other Error")
65
+ context "against an endpoint that has a generic error" do
66
+ let(:endpoint){ mock_href('other_error') }
67
+ it "raises a generic error for any other error condition" do
68
+ expect{ client.api }.should raise_error(RHC::Rest::ConnectionException, "An unexpected error occured: Other Error")
69
+ end
61
70
  end
62
71
  end
63
-
72
+
64
73
  describe "#new" do
65
74
  context "when server supports API versions [1.0, 1.1]" do
66
75
  before :each do
@@ -69,44 +78,36 @@ module RHC
69
78
  :status => 200
70
79
  })
71
80
  stub_api_request(:get, 'api_error').
72
- to_raise(RestClient::ExceptionWithResponse.new('API Error'))
81
+ to_raise(HTTPClient::BadResponseError.new('API Error'))
73
82
  stub_api_request(:get, 'other_error').
74
- to_raise(Exception.new('Other Error'))
83
+ to_raise(StandardError.new('Other Error'))
75
84
  end
76
-
85
+
77
86
  context "when client is instantiated with [1.0, 1.1] as the preferred API versions" do
78
- before :each do
79
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.0, 1.1])
80
- end
87
+ let(:spec_versions){ [1.0, 1.1] }
81
88
  it "settles on 1.1 as the API version" do
82
- @client.api_version_negotiated.should == 1.1
89
+ client.api.api_version_negotiated.should == 1.1
83
90
  end
84
91
  end
85
-
92
+
86
93
  context "when client is instantiated with [1.1, 1.0] as the preferred API versions" do
87
- before :each do
88
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.1, 1.0])
89
- end
94
+ let(:spec_versions){ [1.1, 1.0] }
90
95
  it "settles on 1.0 as the API version" do
91
- @client.api_version_negotiated.should == 1.0
96
+ client.api.api_version_negotiated.should == 1.0
92
97
  end
93
98
  end
94
-
99
+
95
100
  context "when client is instantiated with [1.2, 1.3] as the preferred API versions" do
96
- before :each do
97
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.2, 1.3])
98
- end
101
+ let(:spec_versions){ [1.2, 1.3] }
99
102
  it "fails to negotiate an agreeable API version" do
100
- @client.api_version_negotiated.should be_nil
103
+ client.api.api_version_negotiated.should be_nil
101
104
  end
102
105
  end
103
-
106
+
104
107
  context "when client is instantiated with [1.1, 1.0, 1.3] as the preferred API versions" do
105
- before :each do
106
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.1, 1.0, 1.3])
107
- end
108
+ let(:spec_versions){ [1.1, 1.0, 1.3] }
108
109
  it "settles on 1.0 as the API version" do
109
- @client.api_version_negotiated.should == 1.0
110
+ client.api.api_version_negotiated.should == 1.0
110
111
  end
111
112
  end
112
113
  end
@@ -121,7 +122,6 @@ module RHC
121
122
  }.to_json,
122
123
  :status => 200
123
124
  })
124
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass)
125
125
  end
126
126
 
127
127
  context "#add_domain" do
@@ -139,7 +139,7 @@ module RHC
139
139
  })
140
140
  end
141
141
  it "returns a domain object" do
142
- domain = @client.add_domain('mock_domain')
142
+ domain = client.add_domain('mock_domain')
143
143
  domain.class.should == RHC::Rest::Domain
144
144
  domain.id.should == 'mock_domain'
145
145
  domain.send(:links).should ==
@@ -170,10 +170,10 @@ module RHC
170
170
  })
171
171
  end
172
172
  it "returns a list of existing domains" do
173
- domains = @client.domains
173
+ domains = client.domains
174
174
  domains.length.should equal(2)
175
175
  (0..1).each do |idx|
176
- domains[idx].class.should == RHC::Rest::Domain
176
+ domains[idx].class.should == RHC::Rest::Domain
177
177
  domains[idx].id.should == "mock_domain_#{idx}"
178
178
  domains[idx].send(:links).should ==
179
179
  mock_response_links(mock_domain_links("mock_domain_#{idx}"))
@@ -181,8 +181,9 @@ module RHC
181
181
  end
182
182
  it "returns an empty list when no domains exist" do
183
183
  # Disregard the first response; this is for the previous expectiation.
184
- domains = @client.domains
185
- domains = @client.domains
184
+ domains = client.domains
185
+ client.instance_variable_set(:@domains, nil)
186
+ domains = client.domains
186
187
  domains.length.should equal(0)
187
188
  end
188
189
  end
@@ -205,13 +206,13 @@ module RHC
205
206
  end
206
207
  it "returns a domain object for matching domain IDs" do
207
208
  match = nil
208
- expect { match = @client.find_domain('mock_domain_0') }.should_not raise_error
209
+ expect { match = client.find_domain('mock_domain_0') }.should_not raise_error
209
210
 
210
211
  match.id.should == 'mock_domain_0'
211
212
  match.class.should == RHC::Rest::Domain
212
213
  end
213
214
  it "raise an error when no matching domain IDs can be found" do
214
- expect { @client.find_domain('mock_domain_2') }.should raise_error(RHC::DomainNotFoundException)
215
+ expect { client.find_domain('mock_domain_2') }.should raise_error(RHC::DomainNotFoundException)
215
216
  end
216
217
  end
217
218
 
@@ -262,10 +263,10 @@ module RHC
262
263
  })
263
264
  end
264
265
  it "returns application objects for matching application IDs" do
265
- domain = @client.domains[0]
266
+ domain = client.domains[0]
266
267
  domain.applications.each do |app|
267
268
  match = domain.find_application(app.name)
268
- match.class.should == RHC::Rest::Application
269
+ match.class.should == RHC::Rest::Application
269
270
  match.name.should == 'mock_app'
270
271
  match.domain_id.should == "#{domain.id}"
271
272
  match.send(:links).should ==
@@ -273,7 +274,30 @@ module RHC
273
274
  end
274
275
  end
275
276
  it "Raises an excpetion when no matching applications can be found" do
276
- expect { @client.domains[0].find_application('no_match') }.should raise_error(RHC::ApplicationNotFoundException)
277
+ expect { client.domains[0].find_application('no_match') }.should raise_error(RHC::ApplicationNotFoundException)
278
+ end
279
+ end
280
+
281
+ describe RHC::Rest::Cartridge do
282
+ subject do
283
+ described_class.new({
284
+ :name => 'foo',
285
+ :links => mock_response_links([
286
+ ['GET', 'broker/rest/cartridge', 'get']
287
+ ])}, client)
288
+ end
289
+ context "when several messages are present" do
290
+ before do
291
+ stub_api_request(:get, 'broker/rest/cartridge', true).
292
+ with(:query => {:include => :status_messages}).
293
+ to_return(:body => {
294
+ :type => 'cartridge',
295
+ :data => {
296
+ :status_messages => [{:message => 'Test'}]
297
+ }
298
+ }.to_json)
299
+ end
300
+ its(:status){ should == [{'message' => 'Test'}] }
277
301
  end
278
302
  end
279
303
 
@@ -302,21 +326,22 @@ module RHC
302
326
  })
303
327
  end
304
328
  it "returns a list of existing cartridges" do
305
- carts = @client.cartridges
329
+ carts = client.cartridges
306
330
  carts.length.should equal(2)
307
331
  (0..1).each do |idx|
308
- carts[idx].class.should == RHC::Rest::Cartridge
332
+ carts[idx].class.should == RHC::Rest::Cartridge
309
333
  carts[idx].name.should == "mock_cart_#{idx}"
310
334
  carts[idx].type.should == "mock_cart_#{idx}_type"
311
335
  carts[idx].send(:links).should ==
312
336
  mock_response_links(mock_cart_links("mock_cart_#{idx}"))
313
337
  end
314
338
  end
315
- it "returns an empty list when no cartridges exist" do
339
+ it "caches cartridges on the client" do
316
340
  # Disregard the first response; this is for the previous expectiation.
317
- carts = @client.cartridges
318
- carts = @client.cartridges
319
- carts.length.should equal(0)
341
+ old = client.cartridges.length
342
+ client.cartridges.length.should equal(old)
343
+ client.instance_variable_set(:@cartridges, nil)
344
+ client.cartridges.length.should equal(0)
320
345
  end
321
346
  end
322
347
 
@@ -344,20 +369,20 @@ module RHC
344
369
  })
345
370
  end
346
371
  it "returns a list of cartridge objects for matching cartridges" do
347
- matches = @client.find_cartridges('mock_cart_0')
372
+ matches = client.find_cartridges('mock_cart_0')
348
373
  matches.length.should equal(1)
349
- matches[0].class.should == RHC::Rest::Cartridge
374
+ matches[0].class.should == RHC::Rest::Cartridge
350
375
  matches[0].name.should == 'mock_cart_0'
351
376
  matches[0].type.should == 'mock_cart_0_type'
352
377
  matches[0].send(:links).should ==
353
378
  mock_response_links(mock_cart_links('mock_cart_0'))
354
379
  end
355
380
  it "returns an empty list when no matching cartridges can be found" do
356
- matches = @client.find_cartridges('no_match')
381
+ matches = client.find_cartridges('no_match')
357
382
  matches.length.should equal(0)
358
383
  end
359
384
  it "returns multiple cartridge matches" do
360
- matches = @client.find_cartridges :regex => "mock_cart_[0-9]"
385
+ matches = client.find_cartridges :regex => "mock_cart_[0-9]"
361
386
  matches.length.should equal(2)
362
387
  end
363
388
  end
@@ -376,8 +401,8 @@ module RHC
376
401
  })
377
402
  end
378
403
  it "returns the user object associated with this client connection" do
379
- user = @client.user
380
- user.class.should == RHC::Rest::User
404
+ user = client.user
405
+ user.class.should == RHC::Rest::User
381
406
  user.login.should == mock_user
382
407
  user.send(:links).should == mock_response_links(mock_user_links)
383
408
  end
@@ -415,9 +440,9 @@ module RHC
415
440
  end
416
441
  it "returns a list of key objects for matching keys" do
417
442
  key = nil
418
- expect { key = @client.find_key('mock_key_0') }.should_not raise_error
443
+ expect { key = client.find_key('mock_key_0') }.should_not raise_error
419
444
 
420
- key.class.should == RHC::Rest::Key
445
+ key.class.should == RHC::Rest::Key
421
446
  key.name.should == 'mock_key_0'
422
447
  key.type.should == 'mock_key_0_type'
423
448
  key.content.should == '123456789:0'
@@ -425,7 +450,7 @@ module RHC
425
450
  mock_response_links(mock_key_links('mock_key_0'))
426
451
  end
427
452
  it "raise an error when no matching keys can be found" do
428
- expect { @client.find_key('no_match') }.should raise_error(RHC::KeyNotFoundException)
453
+ expect { client.find_key('no_match') }.should raise_error(RHC::KeyNotFoundException)
429
454
  end
430
455
  end
431
456
 
@@ -437,11 +462,10 @@ module RHC
437
462
  })
438
463
  end
439
464
  context "debug mode is on" do
465
+ let(:use_debug){ true }
440
466
  it "writes a message to the logger" do
441
467
  capture do
442
- @client = MockClient.new(mock_href, mock_user, mock_pass, true)
443
- @client.send logout_method.to_sym
444
-
468
+ client.send logout_method.to_sym
445
469
  stderr.should match(/Logout\/Close client$/)
446
470
  end
447
471
  end
@@ -449,8 +473,7 @@ module RHC
449
473
  context "debug mode is off" do
450
474
  it "does nothing" do
451
475
  capture do
452
- @client = MockClient.new(mock_href, mock_user, mock_pass, false)
453
- @client.send logout_method.to_sym
476
+ client.send logout_method.to_sym
454
477
  stderr.should be_empty
455
478
  end
456
479
  end
@@ -491,20 +514,18 @@ module RHC
491
514
  to_return({ :body => {}.to_json,
492
515
  :status => 200
493
516
  })
494
-
495
- @client = MockClient.new(mock_href, mock_user, mock_pass)
496
517
  end
497
-
518
+
498
519
  it "should delete keys" do
499
- expect { @client.delete_key('mock_key_0') }.should be_true
520
+ expect { client.delete_key('mock_key_0') }.should be_true
500
521
  end
501
-
522
+
502
523
  it 'raises an error if nonexistent key is requested' do
503
- expect { @client.find_key('no_match') }.
524
+ expect { client.find_key('no_match') }.
504
525
  should raise_error(RHC::KeyNotFoundException)
505
526
  end
506
527
  end
507
-
528
+
508
529
  context "#logout" do
509
530
  let(:logout_method) { :logout }
510
531
  it_should_behave_like "a logout method"
@@ -515,7 +536,7 @@ module RHC
515
536
  it_should_behave_like "a logout method"
516
537
  end
517
538
  end
518
-
539
+
519
540
  context "when server supports API versions 1.0 and 1.1" do
520
541
  before :each do
521
542
  stub_api_request(:get, '').
@@ -526,36 +547,33 @@ module RHC
526
547
  :status => 200
527
548
  })
528
549
  end
529
-
550
+
530
551
  context "when client supports API version 1.1" do
531
- before :each do
532
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.1])
533
- end
534
-
552
+ let(:spec_versions){ [1.1] }
553
+
535
554
  describe "#api_version_negotiated" do
536
555
  it "returns 1.1" do
537
- @client.api_version_negotiated.to_s.should == '1.1'
556
+ client.api.api_version_negotiated.to_s.should == '1.1'
538
557
  end
539
558
  end
540
559
  end
541
-
560
+
542
561
  context "when client supports only API version 1.2" do
543
- before :each do
544
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [1.2])
545
- end
546
-
562
+ let(:spec_versions){ [1.2] }
563
+
547
564
  describe "#api_version_negotiated" do
548
565
  it 'returns nil' do
549
- @client.api_version_negotiated.should be_nil
566
+ client.api.api_version_negotiated.should be_nil
550
567
  end
551
568
  end
552
569
  end
553
-
570
+
554
571
  context "when client supports only API version 0.9" do
555
572
  describe "#new" do
573
+ let(:spec_versions){ [0.9] }
556
574
  it "warns user that it is outdated" do
557
575
  capture do
558
- @client = RHC::Rest::Client.new(mock_href, mock_user, mock_pass, false, [0.9])
576
+ client.api
559
577
  @output.rewind
560
578
  @output.read.should =~ /client version may be outdated/
561
579
  end
@@ -563,7 +581,6 @@ module RHC
563
581
  end
564
582
  end
565
583
  end
566
-
567
584
  end
568
585
  end
569
586
  end
@@ -7,7 +7,7 @@ class RHCRest
7
7
  def debug?
8
8
  false
9
9
  end
10
- def debug
10
+ def debug(*args)
11
11
  raise "Unchecked debug"
12
12
  end
13
13
  end
@@ -16,17 +16,53 @@ module MockRestResponse
16
16
  attr_accessor :code, :read
17
17
  end
18
18
 
19
+
20
+ describe RHC::Rest::Cartridge do
21
+ context 'with a name' do
22
+ before{ subject.name = 'foo' }
23
+ its(:display_name){ should == 'foo' }
24
+
25
+ context 'when display name is present' do
26
+ before{ subject.display_name = 'bar' }
27
+ its(:display_name){ should == 'bar' }
28
+ end
29
+ end
30
+ end
31
+
19
32
  module RHC
20
33
 
21
34
  describe Rest do
22
- subject{ RHCRest.new }
35
+ subject{ RHC::Rest::Client.new }
23
36
 
24
37
  # logger function
25
38
  describe "#logger" do
26
39
  it "establishes a logger" do
27
40
  logger = Logger.new(STDOUT)
28
- subject.logger.should have_same_attributes_as(logger)
41
+ subject.send(:logger).should have_same_attributes_as(logger)
42
+ end
43
+ it "reuses a logger" do
44
+ subject.send(:logger).should equal(subject.send(:logger))
45
+ end
46
+ end
47
+
48
+ describe "#default_verify_callback" do
49
+ def invoked_with(is_ok, ctx)
50
+ subject.send(:default_verify_callback).call(is_ok, ctx)
29
51
  end
52
+ it{ invoked_with(true, nil).should be_true }
53
+
54
+ it{ expect{ invoked_with(false, nil) }.to raise_error(NoMethodError) }
55
+
56
+ context "with a self signed cert" do
57
+ it{ invoked_with(false, stub(:current_cert => stub(:issuer => '1', :subject => stub(:cmp => 0)))).should be_false }
58
+ after{ subject.send(:self_signed?).should be_true }
59
+ end
60
+
61
+ context "with an intermediate signed cert" do
62
+ it{ invoked_with(false, stub(:current_cert => stub(:issuer => '2', :subject => stub(:cmp => 1)), :error => 1, :error_string => 'a')).should be_false }
63
+ after{ subject.send(:self_signed?).should be_false }
64
+ end
65
+
30
66
  end
31
67
 
32
68
  # parse_response function
@@ -35,7 +71,7 @@ module RHC
35
71
  let(:object) {{ :links => { :foo => 'bar' } }}
36
72
  it "deserializes to the encapsulated data" do
37
73
  json_response = { :data => object }.to_json
38
- subject.parse_response(json_response).should have_same_attributes_as(object)
74
+ subject.send(:parse_response, json_response).should have_same_attributes_as(object)
39
75
  end
40
76
  end
41
77
 
@@ -52,7 +88,7 @@ module RHC
52
88
  it "deserializes to an application" do
53
89
  json_response = { :type => 'application', :data => object, :messages => [{'text' => 'test message'}]}.to_json
54
90
  app_obj = RHC::Rest::Application.new(object)
55
- subject.parse_response(json_response).should have_same_attributes_as(app_obj)
91
+ subject.send(:parse_response, json_response).should have_same_attributes_as(app_obj)
56
92
  end
57
93
  end
58
94
 
@@ -78,9 +114,9 @@ module RHC
78
114
  json_response = { :type => 'applications', :data => object }.to_json
79
115
  app_obj_1 = RHC::Rest::Application.new(object[0])
80
116
  app_obj_2 = RHC::Rest::Application.new(object[1])
81
- subject.parse_response(json_response).length.should equal(2)
82
- subject.parse_response(json_response)[0].should have_same_attributes_as(app_obj_1)
83
- subject.parse_response(json_response)[1].should have_same_attributes_as(app_obj_2)
117
+ subject.send(:parse_response, json_response).length.should equal(2)
118
+ subject.send(:parse_response, json_response)[0].should have_same_attributes_as(app_obj_1)
119
+ subject.send(:parse_response, json_response)[1].should have_same_attributes_as(app_obj_2)
84
120
  end
85
121
  end
86
122
 
@@ -94,7 +130,7 @@ module RHC
94
130
  it "deserializes to a cartridge" do
95
131
  json_response = { :type => 'cartridge', :data => object }.to_json
96
132
  cart_obj = RHC::Rest::Cartridge.new(object)
97
- subject.parse_response(json_response).should have_same_attributes_as(cart_obj)
133
+ subject.send(:parse_response, json_response).should have_same_attributes_as(cart_obj)
98
134
  end
99
135
  end
100
136
 
@@ -113,9 +149,9 @@ module RHC
113
149
  json_response = { :type => 'cartridges', :data => object }.to_json
114
150
  cart_obj_1 = RHC::Rest::Cartridge.new(object[0])
115
151
  cart_obj_2 = RHC::Rest::Cartridge.new(object[1])
116
- subject.parse_response(json_response).length.should equal(2)
117
- subject.parse_response(json_response)[0].should have_same_attributes_as(cart_obj_1)
118
- subject.parse_response(json_response)[1].should have_same_attributes_as(cart_obj_2)
152
+ subject.send(:parse_response, json_response).length.should equal(2)
153
+ subject.send(:parse_response, json_response)[0].should have_same_attributes_as(cart_obj_1)
154
+ subject.send(:parse_response, json_response)[1].should have_same_attributes_as(cart_obj_2)
119
155
  end
120
156
  end
121
157
 
@@ -128,7 +164,7 @@ module RHC
128
164
  it "deserializes to a domain" do
129
165
  json_response = { :type => 'domain', :data => object }.to_json
130
166
  dom_obj = RHC::Rest::Domain.new(object)
131
- subject.parse_response(json_response).should have_same_attributes_as(dom_obj)
167
+ subject.send(:parse_response, json_response).should have_same_attributes_as(dom_obj)
132
168
  end
133
169
  end
134
170
 
@@ -145,9 +181,9 @@ module RHC
145
181
  json_response = { :type => 'domains', :data => object }.to_json
146
182
  dom_obj_1 = RHC::Rest::Domain.new(object[0])
147
183
  dom_obj_2 = RHC::Rest::Domain.new(object[1])
148
- subject.parse_response(json_response).length.should equal(2)
149
- subject.parse_response(json_response)[0].should have_same_attributes_as(dom_obj_1)
150
- subject.parse_response(json_response)[1].should have_same_attributes_as(dom_obj_2)
184
+ subject.send(:parse_response, json_response).length.should equal(2)
185
+ subject.send(:parse_response, json_response)[0].should have_same_attributes_as(dom_obj_1)
186
+ subject.send(:parse_response, json_response)[1].should have_same_attributes_as(dom_obj_2)
151
187
  end
152
188
  end
153
189
 
@@ -162,7 +198,7 @@ module RHC
162
198
  it "deserializes to a key" do
163
199
  json_response = { :type => 'key', :data => object }.to_json
164
200
  key_obj = RHC::Rest::Key.new(object)
165
- subject.parse_response(json_response).should have_same_attributes_as(key_obj)
201
+ subject.send(:parse_response, json_response).should have_same_attributes_as(key_obj)
166
202
  end
167
203
  end
168
204
 
@@ -183,9 +219,9 @@ module RHC
183
219
  json_response = { :type => 'keys', :data => object }.to_json
184
220
  key_obj_1 = RHC::Rest::Key.new(object[0])
185
221
  key_obj_2 = RHC::Rest::Key.new(object[1])
186
- subject.parse_response(json_response).length.should equal(2)
187
- subject.parse_response(json_response)[0].should have_same_attributes_as(key_obj_1)
188
- subject.parse_response(json_response)[1].should have_same_attributes_as(key_obj_2)
222
+ subject.send(:parse_response, json_response).length.should equal(2)
223
+ subject.send(:parse_response, json_response)[0].should have_same_attributes_as(key_obj_1)
224
+ subject.send(:parse_response, json_response)[1].should have_same_attributes_as(key_obj_2)
189
225
  end
190
226
  end
191
227
 
@@ -198,13 +234,26 @@ module RHC
198
234
  it "deserializes to a user" do
199
235
  json_response = { :type => 'user', :data => object }.to_json
200
236
  user_obj = RHC::Rest::User.new(object)
201
- subject.parse_response(json_response).should have_same_attributes_as(user_obj)
237
+ subject.send(:parse_response, json_response).should have_same_attributes_as(user_obj)
202
238
  end
203
239
  end
204
240
  end
205
241
 
206
242
  # request function
207
243
  describe "#request" do
244
+ let(:response){ lambda { subject.request(request) } }
245
+ let(:request){ {:url => mock_href, :method => method, :headers => {:accept => :json} } }
246
+ let(:method){ :get }
247
+
248
+ if HTTPClient::SSLConfig.method_defined? :ssl_version
249
+ context "when an invalid ssl version is passed, OpenSSL should reject us" do
250
+ let(:request){ {:url => "https://openshift.redhat.com", :method => :get, :ssl_version => :SSLv3_server} }
251
+ before{ WebMock.allow_net_connect! }
252
+ it("fails to call openssl"){ response.should raise_error(RHC::Rest::SSLConnectionFailed, /called a function you should not call/) }
253
+ after{ WebMock.disable_net_connect! }
254
+ end
255
+ end
256
+
208
257
  context "with a successful request" do
209
258
  let(:object) {{
210
259
  :type => 'domain',
@@ -223,13 +272,7 @@ module RHC
223
272
 
224
273
  it "sends the response to be deserialized" do
225
274
  dom_obj = RHC::Rest::Domain.new(object)
226
- request = RestClient::Request.new(:url => mock_href,
227
- :method => 'get',
228
- :headers => { :accept => :json },
229
- :payload => {},
230
- :timeout => 300
231
- )
232
- subject.request(request).should have_same_attributes_as(dom_obj)
275
+ subject.request(request.merge(:payload => {}, :timeout => 300)).should have_same_attributes_as(dom_obj)
233
276
  end
234
277
  end
235
278
 
@@ -243,11 +286,7 @@ module RHC
243
286
  stub_request(:get, mock_href).to_return(return_data)
244
287
  end
245
288
  it "throws an error" do
246
- request = RestClient::Request.new(:url => mock_href,
247
- :method => 'get',
248
- :headers => {:accept => :json}
249
- )
250
- lambda { subject.request(request) }.should raise_error(RHC::Rest::ResourceAccessException, 'Failed to access resource: unexpected nil')
289
+ response.should raise_error(RHC::Rest::ConnectionException, 'An unexpected error occured: unexpected nil')
251
290
  end
252
291
  end
253
292
 
@@ -261,95 +300,103 @@ module RHC
261
300
  stub_request(:get, mock_href).to_return(return_data)
262
301
  end
263
302
  it "quietly exits" do
264
- request = RestClient::Request.new(:url => mock_href,
265
- :method => 'get',
266
- :headers => {:accept => :json}
267
- )
268
- subject.request(request).should equal(nil)
303
+ response.call.should equal(nil)
269
304
  end
270
305
  end
271
306
 
272
307
  context "with a 502 (Bad Gateway) error" do
273
308
  before{ stub_request(method, mock_href).to_return(:status => 502) }
274
- let(:req){ RestClient::Request.new(:url => mock_href, :method => method) }
275
- let(:method){ :get }
276
309
 
277
- it("should make two requests"){ subject.request(req) rescue nil; WebMock.should have_requested(method, mock_href).twice }
278
- it{ expect{ subject.request(req) }.should raise_error(RHC::Rest::ConnectionException, /communicating with the server.*temporary/i) }
310
+ context "on a GET request" do
311
+ it("repeats the call"){ response.should raise_error(RHC::Rest::ConnectionException, /communicating with the server.*temporary/i) }
312
+ after{ WebMock.should have_requested(method, mock_href).twice }
313
+ end
279
314
 
280
315
  context "on a POST request" do
281
316
  let(:method){ :post }
282
317
 
283
- it("should make one request"){ subject.request(req) rescue nil; WebMock.should have_requested(method, mock_href).once }
284
- it{ expect{ subject.request(req) }.should raise_error(RHC::Rest::ConnectionException, /communicating with the server.*temporary/i) }
318
+ it("does not repeat the call"){ response.should raise_error(RHC::Rest::ConnectionException, /communicating with the server.*temporary/i) }
319
+ after{ WebMock.should have_requested(method, mock_href).once }
285
320
  end
286
321
  end
287
322
 
288
- context "with a request timeout" do
289
- before do
290
- stub_request(:get, mock_href).to_timeout
323
+ context "with a GET request" do
324
+ it "serializes payload as query parameters" do
325
+ stub_request(:get, mock_href).with(:query => {:test => 1, :bar => 2}).to_return(:status => 204)
326
+ subject.request(request.merge(:payload => {:test => '1', :bar => 2})).should be_nil
291
327
  end
292
- it "raises a resource access exception error" do
293
- request = RestClient::Request.new(:url => mock_href,
294
- :method => 'get',
295
- :headers => {:accept => :json}
296
- )
297
- lambda { subject.request(request) }.should raise_error(RHC::Rest::TimeoutException, /Connection to server timed out. It is possible/)
328
+ end
329
+ context "with a POST request" do
330
+ let(:method){ :post }
331
+ it "serializes payload as urlencoded body parameters" do
332
+ stub_request(method, mock_href).
333
+ with(:headers => {:accept => 'application/json', :content_type => 'application/json'},
334
+ :body => {:test => '1', :bar => 2}.to_json).
335
+ to_return(:status => 204)
336
+ subject.request(request.merge(:payload => {:test => '1', :bar => 2})).should be_nil
298
337
  end
299
338
  end
300
339
 
340
+ context "with a request timeout" do
341
+ before{ stub_request(:get, mock_href).to_timeout }
342
+ it{ response.should raise_error(RHC::Rest::TimeoutException, /Connection to server timed out. It is possible/) }
343
+ end
344
+
301
345
  context "with a broken server connection" do
346
+ before{ stub_request(:get, mock_href).to_raise(EOFError.new('Lost Server Connection')) }
347
+ it{ response.should raise_error(RHC::Rest::ConnectionException, 'Connection to server got interrupted: Lost Server Connection') }
348
+ end
349
+
350
+ #FIXME: the type of this exception should be a subclass of CertificateValidationFailed
351
+ context "with a potentially missing cert store" do
352
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('unable to get local issuer certificate')) }
353
+ it{ response.should raise_error(RHC::Rest::SSLConnectionFailed, /You may need to specify your system CA certificate file/) }
354
+ end
355
+
356
+ context "with a self-signed SSL certificate" do
302
357
  before do
303
- stub_request(:get, mock_href).to_raise(RestClient::ServerBrokeConnection.new('Lost Server Connection'))
304
- end
305
- it "raises a resource access exception error" do
306
- request = RestClient::Request.new(:url => mock_href,
307
- :method => 'get',
308
- :headers => {:accept => :json}
309
- )
310
- lambda { subject.request(request) }.should raise_error(RHC::Rest::ConnectionException, 'Connection to server got interrupted: Lost Server Connection')
358
+ subject.should_receive(:self_signed?).and_return(true)
359
+ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('Unverified SSL Certificate'))
311
360
  end
361
+ it{ response.should raise_error(RHC::Rest::CertificateVerificationFailed, /The server is using a self-signed certificate/) }
312
362
  end
313
363
 
314
364
  context "with an unverified SSL certificate" do
315
- before do
316
- stub_request(:get, mock_href).to_raise(RestClient::SSLCertificateNotVerified.new('Unverified SSL Certificate'))
317
- end
318
- it "raises a resource access exception error" do
319
- request = RestClient::Request.new(:url => mock_href,
320
- :method => 'get',
321
- :headers => {:accept => :json}
322
- )
323
- lambda { subject.request(request) }.should raise_error(RHC::Rest::ResourceAccessException, 'Failed to access resource: Unverified SSL Certificate')
324
- end
365
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('self signed certificate')) }
366
+ it{ response.should raise_error(RHC::Rest::CertificateVerificationFailed, /The server is using a self-signed certificate/) }
325
367
  end
326
368
 
327
- context "with a socket errort" do
369
+ context "with an failed SSL certificate verification" do
370
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('certificate verify failed')) }
371
+ it{ response.should raise_error(RHC::Rest::CertificateVerificationFailed, /The server's certificate could not be verified.*test\.domain\.com/) }
372
+ end
373
+
374
+ context "with a socket error" do
328
375
  before{ stub_request(:get, mock_href).to_raise(SocketError) }
329
- it "raises a resource access exception error" do
330
- request = RestClient::Request.new(:url => mock_href,
331
- :method => 'get',
332
- :headers => {:accept => :json}
333
- )
334
- lambda { subject.request(request) }.should raise_error(RHC::Rest::ConnectionException, /unable to connect to the server/i)
335
- end
376
+ it{ response.should raise_error(RHC::Rest::ConnectionException, /unable to connect to the server/i) }
336
377
  end
337
378
 
338
- context "with a generic exception error" do
339
- before do
340
- stub_request(:get, mock_href).to_raise(Exception.new('Generic Error'))
341
- end
379
+ context "with an SSL connection error" do
380
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError) }
381
+ it{ response.should raise_error(RHC::Rest::SSLConnectionFailed, /a secure connection could not be established/i) }
382
+ end
342
383
 
343
- it "raises a resource access exception error" do
344
- request = RestClient::Request.new(:url => mock_href,
345
- :method => 'get',
346
- :headers => {:accept => :json}
347
- )
348
- lambda { subject.request(request) }.should raise_error(RHC::Rest::ResourceAccessException, 'Failed to access resource: Generic Error')
349
- end
384
+ context "with an SSL certificate error" do
385
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('certificate verify failed')) }
386
+ it{ response.should raise_error(RHC::Rest::CertificateVerificationFailed, /the server's certificate could not be verified/i) }
387
+ end
388
+
389
+ context "with an SSL version exception" do
390
+ before{ stub_request(:get, mock_href).to_raise(OpenSSL::SSL::SSLError.new('SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A')) }
391
+ it{ response.should raise_error(RHC::Rest::SSLVersionRejected, /connection attempt with an older ssl protocol/i) }
350
392
  end
351
393
 
352
- context "with a specific error response" do
394
+ context "with a generic exception error" do
395
+ before{ stub_request(:get, mock_href).to_raise(Exception.new('Generic Error')) }
396
+ it{ response.should raise_error(RHC::Rest::ConnectionException, "An unexpected error occured: Generic Error") }
397
+ end
398
+
399
+ context "with a an unauthorized request" do
353
400
  before do
354
401
  return_data = {
355
402
  :body => nil,
@@ -358,40 +405,32 @@ module RHC
358
405
  }
359
406
  stub_request(:get, mock_href).to_return(return_data)
360
407
  end
361
-
362
- it "passes the response off for interpretation" do
363
- request = RestClient::Request.new(:url => mock_href,
364
- :method => 'get',
365
- :headers => {:accept => :json}
366
- )
367
- lambda { subject.request(request) }.should raise_error(RHC::Rest::UnAuthorizedException, 'Not authenticated')
368
- end
408
+ it("raises not authenticated"){ response.should raise_error(RHC::Rest::UnAuthorizedException, 'Not authenticated') }
369
409
  end
370
410
  end
371
411
 
372
- # process_error_response function
373
- describe "#process_error_response" do
412
+ # handle_error! function
413
+ describe "#handle_error!" do
374
414
  let(:json){ nil }
375
415
  let(:body){ "<html><body>Something failed</body></html>" }
376
416
  let(:code){ nil }
417
+ let(:client){ HTTPClient.new(:proxy => proxy) }
418
+ let(:url){ "http://fake.url" }
419
+ let(:proxy){ nil }
377
420
  def response
378
- (response = {}).extend(MockRestResponse)
379
- response.code = code
380
- response.read = json ? RHC::Json.encode(json) : body
381
- response
421
+ mock(:status => code, :content => json ? RHC::Json.encode(json) : body)
382
422
  end
423
+ let(:method) { lambda{ subject.send(:handle_error!, response, url, client) } }
383
424
 
384
425
  context "with a 400 response" do
385
426
  let(:code){ 400 }
386
427
 
387
- it "raises a generic server error" do
388
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException)
389
- end
428
+ it{ method.should raise_error(RHC::Rest::ServerErrorException) }
390
429
 
391
430
  context "with a formatted JSON response" do
392
431
  let(:json){ {:messages => [{ :severity => 'error', :text => 'mock error message' }] } }
393
432
  it "raises a client error" do
394
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ClientErrorException, 'mock error message')
433
+ method.should raise_error(RHC::Rest::ClientErrorException, 'mock error message')
395
434
  end
396
435
  end
397
436
  end
@@ -400,7 +439,7 @@ module RHC
400
439
  let(:code){ 401 }
401
440
  let(:json){ {} }
402
441
  it "raises an 'unauthorized exception' error" do
403
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::UnAuthorizedException, 'Not authenticated')
442
+ method.should raise_error(RHC::Rest::UnAuthorizedException, 'Not authenticated')
404
443
  end
405
444
  end
406
445
 
@@ -408,13 +447,13 @@ module RHC
408
447
  let(:code){ 403 }
409
448
 
410
449
  it "raises a request denied error" do
411
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::RequestDeniedException)
450
+ method.should raise_error(RHC::Rest::RequestDeniedException)
412
451
  end
413
452
 
414
453
  context "with a formatted JSON response" do
415
454
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
416
455
  it "raises a 'request denied' error" do
417
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::RequestDeniedException, 'mock error message')
456
+ method.should raise_error(RHC::Rest::RequestDeniedException, 'mock error message')
418
457
  end
419
458
  end
420
459
  end
@@ -423,13 +462,13 @@ module RHC
423
462
  let(:code){ 404 }
424
463
 
425
464
  it "raises a Not Found error" do
426
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ResourceNotFoundException)
465
+ method.should raise_error(RHC::Rest::ResourceNotFoundException)
427
466
  end
428
467
 
429
468
  context "with a formatted JSON response" do
430
469
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
431
470
  it "raises a 'resource not found' error" do
432
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ResourceNotFoundException, 'mock error message')
471
+ method.should raise_error(RHC::Rest::ResourceNotFoundException, 'mock error message')
433
472
  end
434
473
  end
435
474
  end
@@ -438,13 +477,45 @@ module RHC
438
477
  let(:code){ 409 }
439
478
 
440
479
  it "raises a generic server error" do
441
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException)
480
+ method.should raise_error(RHC::Rest::ServerErrorException)
442
481
  end
443
482
 
444
483
  context "with a formatted JSON response" do
445
484
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
446
485
  it "raises a validation error" do
447
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ValidationException, 'mock error message')
486
+ method.should raise_error(RHC::Rest::ValidationException, 'mock error message')
487
+ end
488
+ end
489
+ context "with multiple JSON messages" do
490
+ let(:json){ { :messages => [{ :field => 'error', :text => 'mock error message 1' },
491
+ { :field => 'error', :text => 'mock error message 2' }] } }
492
+ it "raises a validation error with concatenated messages" do
493
+ method.should raise_error(RHC::Rest::ValidationException, "The operation did not complete successfully, but the server returned additional information:\n* mock error message 1\n* mock error message 2")
494
+ end
495
+ end
496
+ context "with multiple errors" do
497
+ let(:json){ { :messages => [
498
+ { :severity => 'error', :field => 'error', :text => 'mock 1' },
499
+ { :severity => 'error', :text => 'mock 2' },
500
+ ] } }
501
+ it "raises a validation error with concatenated messages" do
502
+ method.should raise_error(RHC::Rest::ValidationException, "The server reported multiple errors:\n* mock 1\n* mock 2")
503
+ end
504
+ end
505
+ context "with multiple messages and one error" do
506
+ let(:json){ { :messages => [
507
+ { :field => 'error', :text => 'mock 1' },
508
+ { :text => 'mock 2' },
509
+ { :severity => 'error', :text => 'mock 3' },
510
+ ] } }
511
+ it "raises a validation error with concatenated messages" do
512
+ method.should raise_error(RHC::Rest::ValidationException, "mock 3")
513
+ end
514
+ end
515
+ context "with an empty JSON response" do
516
+ let(:json){ {} }
517
+ it "raises a validation error" do
518
+ method.should raise_error(RHC::Rest::ServerErrorException)
448
519
  end
449
520
  end
450
521
  end
@@ -453,20 +524,20 @@ module RHC
453
524
  let(:code){ 422 }
454
525
 
455
526
  it "raises a generic server error" do
456
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException)
527
+ method.should raise_error(RHC::Rest::ServerErrorException)
457
528
  end
458
529
 
459
530
  context "with a single JSON message" do
460
531
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
461
532
  it "raises a validation error" do
462
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ValidationException, 'mock error message')
533
+ method.should raise_error(RHC::Rest::ValidationException, 'mock error message')
463
534
  end
464
535
  end
465
536
 
466
537
  context "with an empty JSON response" do
467
538
  let(:json){ {} }
468
539
  it "raises a validation error" do
469
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ValidationException, 'Not valid')
540
+ method.should raise_error(RHC::Rest::ServerErrorException)
470
541
  end
471
542
  end
472
543
 
@@ -474,7 +545,26 @@ module RHC
474
545
  let(:json){ { :messages => [{ :field => 'error', :text => 'mock error message 1' },
475
546
  { :field => 'error', :text => 'mock error message 2' }] } }
476
547
  it "raises a validation error with concatenated messages" do
477
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ValidationException, 'mock error message 1 mock error message 2')
548
+ method.should raise_error(RHC::Rest::ValidationException, "The operation did not complete successfully, but the server returned additional information:\n* mock error message 1\n* mock error message 2")
549
+ end
550
+ end
551
+ context "with multiple errors" do
552
+ let(:json){ { :messages => [
553
+ { :severity => 'error', :field => 'error', :text => 'mock 1' },
554
+ { :severity => 'error', :text => 'mock 2' },
555
+ ] } }
556
+ it "raises a validation error with concatenated messages" do
557
+ method.should raise_error(RHC::Rest::ValidationException, "The server reported multiple errors:\n* mock 1\n* mock 2")
558
+ end
559
+ end
560
+ context "with multiple messages and one error" do
561
+ let(:json){ { :messages => [
562
+ { :field => 'error', :text => 'mock 1' },
563
+ { :text => 'mock 2' },
564
+ { :severity => 'error', :text => 'mock 3' },
565
+ ] } }
566
+ it "raises a validation error with concatenated messages" do
567
+ method.should raise_error(RHC::Rest::ValidationException, "mock 3")
478
568
  end
479
569
  end
480
570
  end
@@ -483,26 +573,27 @@ module RHC
483
573
  let(:code){ 500 }
484
574
 
485
575
  it "raises a generic server error" do
486
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException, /server did not respond correctly.*verify that you can access the OpenShift server/i)
576
+ method.should raise_error(RHC::Rest::ServerErrorException, /server did not respond correctly.*verify that you can access the OpenShift server/i)
487
577
  end
488
578
 
489
579
  context "when proxy is set" do
490
- before{ RestClient.should_receive(:proxy).twice.and_return('http://foo.com') }
580
+ let(:proxy) { 'http://foo.com' }
491
581
  it "raises a generic server error with the proxy URL" do
492
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException, /foo\.com/i)
582
+ method.should raise_error(RHC::Rest::ServerErrorException, /foo\.com/i)
493
583
  end
494
584
  end
495
585
 
496
586
  context "when request url is present" do
587
+ let(:url){ 'foo.bar' }
497
588
  it "raises a generic server error with the request URL" do
498
- lambda { subject.process_error_response(response, 'foo.bar') }.should raise_error(RHC::Rest::ServerErrorException, /foo\.bar/i)
589
+ method.should raise_error(RHC::Rest::ServerErrorException, /foo\.bar/i)
499
590
  end
500
591
  end
501
592
 
502
593
  context "with a formatted JSON response" do
503
594
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
504
595
  it "raises a server error" do
505
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException, 'mock error message')
596
+ method.should raise_error(RHC::Rest::ServerErrorException, 'mock error message')
506
597
  end
507
598
  end
508
599
  end
@@ -511,13 +602,13 @@ module RHC
511
602
  let(:code){ 503 }
512
603
 
513
604
  it "raises a 'service unavailable' error" do
514
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServiceUnavailableException)
605
+ method.should raise_error(RHC::Rest::ServiceUnavailableException)
515
606
  end
516
607
 
517
608
  context "with a formatted JSON response" do
518
609
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
519
610
  it "raises a 'service unavailable' error" do
520
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServiceUnavailableException, 'mock error message')
611
+ method.should raise_error(RHC::Rest::ServiceUnavailableException, 'mock error message')
521
612
  end
522
613
  end
523
614
  end
@@ -525,14 +616,12 @@ module RHC
525
616
  context "with an unhandled response code" do
526
617
  let(:code){ 999 }
527
618
 
528
- it "raises a generic server error" do
529
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException)
530
- end
619
+ it{ method.should raise_error(RHC::Rest::ServerErrorException) }
531
620
 
532
621
  context "with a formatted JSON response" do
533
622
  let(:json){ { :messages => [{ :severity => 'error', :text => 'mock error message' }] } }
534
623
  it "raises a resource access error" do
535
- lambda { subject.process_error_response(response) }.should raise_error(RHC::Rest::ServerErrorException, 'Server returned an unexpected error code: 999')
624
+ method.should raise_error(RHC::Rest::ServerErrorException, 'mock error message')
536
625
  end
537
626
  end
538
627
  end