rhc 1.2.7 → 1.3.8

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