rhc 1.4.8 → 1.5.13

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 (65) hide show
  1. data/features/application.feature +1 -0
  2. data/features/lib/rhc_helper/app.rb +5 -3
  3. data/features/lib/rhc_helper/commandify.rb +2 -1
  4. data/features/step_definitions/application_steps.rb +2 -1
  5. data/features/support/env.rb +4 -1
  6. data/lib/rhc/auth/basic.rb +18 -13
  7. data/lib/rhc/auth/token.rb +98 -0
  8. data/lib/rhc/auth/token_store.rb +51 -0
  9. data/lib/rhc/auth.rb +3 -1
  10. data/lib/rhc/command_runner.rb +1 -0
  11. data/lib/rhc/commands/account.rb +47 -1
  12. data/lib/rhc/commands/alias.rb +2 -4
  13. data/lib/rhc/commands/app.rb +23 -18
  14. data/lib/rhc/commands/authorization.rb +93 -0
  15. data/lib/rhc/commands/base.rb +11 -3
  16. data/lib/rhc/commands/cartridge.rb +8 -16
  17. data/lib/rhc/commands/git_clone.rb +2 -3
  18. data/lib/rhc/commands/port_forward.rb +10 -11
  19. data/lib/rhc/commands/setup.rb +4 -1
  20. data/lib/rhc/commands/snapshot.rb +4 -3
  21. data/lib/rhc/commands/tail.rb +3 -4
  22. data/lib/rhc/commands/threaddump.rb +1 -2
  23. data/lib/rhc/commands.rb +37 -3
  24. data/lib/rhc/config.rb +10 -1
  25. data/lib/rhc/context_helper.rb +5 -1
  26. data/lib/rhc/core_ext.rb +10 -0
  27. data/lib/rhc/exceptions.rb +0 -12
  28. data/lib/rhc/git_helpers.rb +12 -0
  29. data/lib/rhc/helpers.rb +31 -1
  30. data/lib/rhc/output_helpers.rb +19 -3
  31. data/lib/rhc/rest/api.rb +2 -1
  32. data/lib/rhc/rest/application.rb +5 -4
  33. data/lib/rhc/rest/authorization.rb +10 -0
  34. data/lib/rhc/rest/base.rb +6 -1
  35. data/lib/rhc/rest/client.rb +243 -122
  36. data/lib/rhc/rest/domain.rb +0 -15
  37. data/lib/rhc/rest/gear_group.rb +0 -1
  38. data/lib/rhc/rest/mock.rb +118 -16
  39. data/lib/rhc/rest/user.rb +0 -1
  40. data/lib/rhc/rest.rb +28 -8
  41. data/lib/rhc/ssh_helpers.rb +5 -2
  42. data/lib/rhc/tar_gz.rb +16 -5
  43. data/lib/rhc/usage_templates/help.erb +1 -1
  44. data/lib/rhc/wizard.rb +54 -10
  45. data/spec/coverage_helper.rb +9 -0
  46. data/spec/rhc/auth_spec.rb +229 -22
  47. data/spec/rhc/cli_spec.rb +15 -0
  48. data/spec/rhc/command_spec.rb +100 -8
  49. data/spec/rhc/commands/account_spec.rb +75 -1
  50. data/spec/rhc/commands/app_spec.rb +23 -5
  51. data/spec/rhc/commands/authorization_spec.rb +120 -0
  52. data/spec/rhc/commands/domain_spec.rb +2 -2
  53. data/spec/rhc/commands/git_clone_spec.rb +24 -0
  54. data/spec/rhc/commands/port_forward_spec.rb +22 -23
  55. data/spec/rhc/commands/server_spec.rb +2 -2
  56. data/spec/rhc/commands/setup_spec.rb +12 -0
  57. data/spec/rhc/config_spec.rb +7 -3
  58. data/spec/rhc/helpers_spec.rb +62 -9
  59. data/spec/rhc/rest_application_spec.rb +24 -0
  60. data/spec/rhc/rest_client_spec.rb +66 -56
  61. data/spec/rhc/rest_spec.rb +11 -2
  62. data/spec/rhc/wizard_spec.rb +61 -12
  63. data/spec/spec_helper.rb +125 -42
  64. data/spec/wizard_spec_helper.rb +1 -0
  65. metadata +9 -3
@@ -25,7 +25,7 @@ describe RHC::Helpers do
25
25
  @config ||= RHC::Config.new
26
26
  end
27
27
  def options
28
- @options ||= OpenStruct.new([:server])
28
+ @options ||= OpenStruct.new(:server => nil)
29
29
  end
30
30
  end.new
31
31
  end
@@ -45,14 +45,34 @@ describe RHC::Helpers do
45
45
 
46
46
  it("should decode json"){ subject.decode_json("{\"a\" : 1}").should == {'a' => 1} }
47
47
 
48
- it("should output green on success") do
49
- capture{ subject.success 'this is green' }.should == "\e[32mthis is green\e[0m\n"
48
+ shared_examples_for "colorized output" do
49
+ it("should be colorized") do
50
+ message = "this is #{_color}"
51
+ output = capture{ subject.send(method,message) }
52
+ output.should be_colorized(message,_color)
53
+ end
54
+ it("should return true"){ subject.send(method,'anything').should be_true }
55
+ end
56
+
57
+ context "success output" do
58
+ let(:_color){ :green }
59
+ let(:method){ :success }
60
+ it_should_behave_like "colorized output"
61
+ end
62
+
63
+ context "warn output" do
64
+ let(:_color){ :yellow }
65
+ let(:method){ :warn }
66
+ it_should_behave_like "colorized output"
50
67
  end
51
- it("should output yellow on warn") do
52
- capture{ subject.success 'this is yellow' }.should == "\e[32mthis is yellow\e[0m\n"
68
+
69
+ context "info output" do
70
+ let(:_color){ :cyan }
71
+ let(:method){ :info }
72
+ it_should_behave_like "colorized output"
53
73
  end
54
- it("should return true on success"){ subject.success('anything').should be_true }
55
- it("should return true on success"){ subject.warn('anything').should be_true }
74
+
75
+ it("should invoke debug from debug_error"){ expect{ subject.debug_error(mock(:class => "Mock", :message => 'msg', :backtrace => [])) }.to call(:debug).on(subject).with("msg (Mock)\n ") }
56
76
 
57
77
  it("should draw a table") do
58
78
  subject.table([[10,2], [3,40]]) do |i|
@@ -60,7 +80,13 @@ describe RHC::Helpers do
60
80
  end.should == ['10 2','3 40']
61
81
  end
62
82
 
63
- it("should output a table") do
83
+ context "error output" do
84
+ let(:_color){ :red }
85
+ let(:method){ :error }
86
+ it_should_behave_like "colorized output"
87
+ end
88
+
89
+ it("should output a table") do
64
90
  subject.send(:display_no_info, 'test').should == ['This test has no information to show']
65
91
  end
66
92
 
@@ -71,6 +97,18 @@ describe RHC::Helpers do
71
97
  d.year.should == 2012
72
98
  end
73
99
 
100
+ describe "#distance_of_time_in_words" do
101
+ it{ subject.distance_of_time_in_words(0, 1).should == 'less than 1 minute' }
102
+ it{ subject.distance_of_time_in_words(0, 60).should == '1 minute' }
103
+ it{ subject.distance_of_time_in_words(0, 130).should == '2 minutes' }
104
+ it{ subject.distance_of_time_in_words(0, 50*60).should == 'about 1 hour' }
105
+ it{ subject.distance_of_time_in_words(0, 3*60*60).should == 'about 3 hours' }
106
+ it{ subject.distance_of_time_in_words(0, 25*60*60).should == 'about 1 day' }
107
+ it{ subject.distance_of_time_in_words(0, 3*24*60*60).should == '3 days' }
108
+ it{ subject.distance_of_time_in_words(0, 40*24*60*60).should == 'about 1 month' }
109
+ it{ subject.distance_of_time_in_words(0, 10*30*24*60*60).should == 'about 10 months' }
110
+ end
111
+
74
112
  context 'using the current time' do
75
113
  let(:date){ Time.local(2008,1,2,1,1,0) }
76
114
  let(:today){ Date.new(2008,1,2) }
@@ -200,6 +238,14 @@ describe RHC::Helpers do
200
238
  it{ run_output.should match("The certificate 'not_a_file' cannot be loaded: No such file or directory ") }
201
239
  end
202
240
 
241
+ describe "#get_properties" do
242
+ it{ tests.send(:get_properties, stub(:plan_id => 'freeshift'), :plan_id).should == [[:plan_id, 'FreeShift']] }
243
+ context "when an error is raised" do
244
+ subject{ stub.tap{ |s| s.should_receive(:foo).and_raise(::Exception) } }
245
+ it{ tests.send(:get_properties, subject, :foo).should == [[:foo, '<error>']] }
246
+ end
247
+ end
248
+
203
249
  context "Formatter" do
204
250
  before{ tests.reset }
205
251
 
@@ -320,8 +366,14 @@ describe RHC::Helpers do
320
366
  subject.should_receive(:error).with('An error')
321
367
  subject.fingerprint_for_local_key('1').should be_nil
322
368
  end
369
+
370
+ it "should catch exceptions from fingerprint failures" do
371
+ Net::SSH::KeyFactory.should_receive(:load_public_key).with('1').and_raise(StandardError.new("An error"))
372
+ subject.should_receive(:error).with('An error')
373
+ subject.fingerprint_for_local_key('1').should be_nil
374
+ end
323
375
  end
324
-
376
+
325
377
  context "Resolv helper" do
326
378
  let(:resolver) { Object.new }
327
379
  let(:existent_host) { 'real_host' }
@@ -353,6 +405,7 @@ describe RHC::Helpers do
353
405
  class OutputTests
354
406
  include RHC::Helpers
355
407
  include RHC::SSHHelpers
408
+ include RHC::OutputHelpers
356
409
 
357
410
  def initialize
358
411
  @print_num = 0
@@ -28,6 +28,30 @@ module RHC
28
28
  end
29
29
  end
30
30
 
31
+ describe "#ssh_string" do
32
+ context "with valid url" do
33
+ subject{ described_class.new('ssh_url' => "ssh://foo@bar.com/path") }
34
+ its(:ssh_string){ should == "foo@bar.com" }
35
+ end
36
+ context "with bad url" do
37
+ subject{ described_class.new('ssh_url' => "ssh://") }
38
+ its(:ssh_string){ should == "ssh://" }
39
+ end
40
+ end
41
+
42
+ describe "#host" do
43
+ context "with bad url" do
44
+ subject{ described_class.new('app_url' => "http://") }
45
+ its(:app_url){ should == "http://" }
46
+ its(:host){ should be_nil }
47
+ end
48
+ context "with http url" do
49
+ subject{ described_class.new('app_url' => "http://bar.com/path") }
50
+ its(:app_url){ should == "http://bar.com/path" }
51
+ its(:host){ should == "bar.com" }
52
+ end
53
+ end
54
+
31
55
  context "#add_cartridge" do
32
56
  before do
33
57
  stub_api_request(:any, app_links['ADD_CARTRIDGE']['relative']).
@@ -212,69 +212,52 @@ module RHC
212
212
  match.class.should == RHC::Rest::Domain
213
213
  end
214
214
  it "raise an error when no matching domain IDs can be found" do
215
- expect { client.find_domain('mock_domain_2') }.should raise_error(RHC::DomainNotFoundException)
215
+ expect { client.find_domain('mock_domain_2') }.should raise_error(RHC::Rest::DomainNotFoundException)
216
216
  end
217
217
  end
218
218
 
219
- context "#find_application" do
219
+ context "find_application" do
220
+ let(:mock_domain){ 'mock_domain_0' }
221
+ let(:mock_app){ 'mock_app' }
222
+ let(:missing){ 'no_match' }
220
223
  before(:each) do
221
- stub_api_request(:any, client_links['LIST_DOMAINS']['relative']).
222
- to_return({ :body => {
223
- :type => 'domains',
224
- :data =>
225
- [{ :id => 'mock_domain_0',
226
- :links => mock_response_links(mock_domain_links('mock_domain_0')),
227
- },
228
- { :id => 'mock_domain_1',
229
- :links => mock_response_links(mock_domain_links('mock_domain_1')),
230
- }]
231
- }.to_json,
232
- :status => 200
233
- })
234
- stub_api_request(:any, domain_0_links['LIST_APPLICATIONS']['relative']).
235
- to_return({ :body => {
236
- :type => 'applications',
237
- :data =>
238
- [{ :domain_id => 'mock_domain_0',
239
- :name => 'mock_app',
240
- :creation_time => Time.new.to_s,
241
- :uuid => 1234,
242
- :aliases => ['alias_1', 'alias_2'],
243
- :server_identity => 'mock_server_identity',
244
- :links => mock_response_links(mock_app_links('mock_domain_0','mock_app')),
245
- }]
246
- }.to_json,
247
- :status => 200
248
- })
249
- stub_api_request(:any, domain_1_links['LIST_APPLICATIONS']['relative']).
250
- to_return({ :body => {
251
- :type => 'applications',
252
- :data =>
253
- [{ :domain_id => 'mock_domain_1',
254
- :name => 'mock_app',
255
- :creation_time => Time.new.to_s,
256
- :uuid => 1234,
257
- :aliases => ['alias_1', 'alias_2'],
258
- :server_identity => 'mock_server_identity',
259
- :links => mock_response_links(mock_app_links('mock_domain_1','mock_app')),
260
- }]
261
- }.to_json,
262
- :status => 200
263
- })
264
- end
265
- it "returns application objects for matching application IDs" do
266
- domain = client.domains[0]
267
- domain.applications.each do |app|
268
- match = domain.find_application(app.name)
224
+ stub_one_application(mock_domain, mock_app)
225
+ stub_one_application(mock_domain, missing, {
226
+ :type => nil,
227
+ :data => nil,
228
+ :messages => [{
229
+ :exit_code => 101,
230
+ :field => nil,
231
+ :severity => 'error',
232
+ :text => "Application #{missing} not found"
233
+ }],
234
+ :status => 'not_found'
235
+ }, 404)
236
+ stub_one_application(missing, mock_app, {
237
+ :type => nil,
238
+ :data => nil,
239
+ :messages => [{
240
+ :exit_code => 127,
241
+ :field => nil,
242
+ :severity => 'error',
243
+ :text => "Domain #{missing} not found"
244
+ }],
245
+ :status => 'not_found'
246
+ }, 404)
247
+ end
248
+ it "returns application object for nested application IDs" do
249
+ match = client.find_application(mock_domain, mock_app)
269
250
  match.class.should == RHC::Rest::Application
270
- match.name.should == 'mock_app'
271
- match.domain_id.should == "#{domain.id}"
251
+ match.name.should == mock_app
252
+ match.domain_id.should == mock_domain
272
253
  match.send(:links).should ==
273
- mock_response_links(mock_app_links("#{domain.id}",'mock_app'))
274
- end
254
+ mock_response_links(mock_app_links(mock_domain, mock_app))
275
255
  end
276
- it "Raises an excpetion when no matching applications can be found" do
277
- expect { client.domains[0].find_application('no_match') }.should raise_error(RHC::ApplicationNotFoundException)
256
+ it "Raises an exception when no matching applications can be found" do
257
+ expect { client.find_application(mock_domain, missing) }.should raise_error(RHC::Rest::ApplicationNotFoundException)
258
+ end
259
+ it "Raises an exception when no matching domain can be found" do
260
+ expect { client.find_application(missing, mock_app) }.should raise_error(RHC::Rest::DomainNotFoundException)
278
261
  end
279
262
  end
280
263
 
@@ -581,6 +564,33 @@ module RHC
581
564
  end
582
565
  end
583
566
  end
567
+
568
+ describe "#supports_sessions?" do
569
+ before{ subject.should_receive(:api).at_least(2).times.and_return(stub) }
570
+ context "with ADD_AUTHORIZATION link" do
571
+ before{ subject.api.should_receive(:supports?).twice.with('ADD_AUTHORIZATION').and_return(true) }
572
+ its(:supports_sessions?){ should be_true }
573
+ end
574
+ context "without ADD_AUTHORIZATION link" do
575
+ before{ subject.api.should_receive(:supports?).twice.with('ADD_AUTHORIZATION').and_return(false) }
576
+ its(:supports_sessions?){ should be_false }
577
+ end
578
+ end
579
+
580
+ describe "#authorizations" do
581
+ before do
582
+ stub_api_request(:get, '').to_return({:body => {
583
+ :data => mock_response_links(mock_api_with_authorizations),
584
+ :supported_api_versions => [1.0, 1.1]
585
+ }.to_json,
586
+ :status => 200
587
+ })
588
+ stub_authorizations
589
+ end
590
+ it{ client.authorizations.first.token.should == 'a_token_value' }
591
+ it{ client.authorizations.first.note.should == 'an_authorization' }
592
+ it{ client.authorizations.first.expires_in_seconds.should == 60 }
593
+ end
584
594
  end
585
595
  end
586
596
  end
@@ -279,6 +279,15 @@ module RHC
279
279
  end
280
280
  end
281
281
 
282
+ describe "#new_request" do
283
+ it{ subject.send(:new_request, :api_version => 2.0).last[4]['accept'].should == 'application/json;version=2.0' }
284
+ it{ subject.send(:new_request, :headers => {:accept => :xml}, :api_version => 2.0).last[4]['accept'].should == 'application/xml;version=2.0' }
285
+ context "with the default api version" do
286
+ before{ subject.should_receive(:current_api_version).and_return('1.0') }
287
+ it{ subject.send(:new_request, {}).last[4]['accept'].should == 'application/json;version=1.0' }
288
+ end
289
+ end
290
+
282
291
  # request function
283
292
  describe "#request" do
284
293
  let(:response){ lambda { subject.request(request) } }
@@ -307,12 +316,12 @@ module RHC
307
316
  :status => 200,
308
317
  :headers => { 'Set-Cookie' => "rh_sso=test_ssh_cookie" }
309
318
  }
310
- stub_request(:get, mock_href).to_return(return_data)
319
+ stub_request(:get, mock_href).with{ |req| req.headers['Accept'].should == 'application/json;version=1.0' }.to_return(return_data)
311
320
  end
312
321
 
313
322
  it "sends the response to be deserialized" do
314
323
  dom_obj = RHC::Rest::Domain.new(object)
315
- subject.request(request.merge(:payload => {}, :timeout => 300)).should have_same_attributes_as(dom_obj)
324
+ subject.request(request.merge(:payload => {}, :api_version => '1.0', :timeout => 300)).should have_same_attributes_as(dom_obj)
316
325
  end
317
326
  end
318
327
 
@@ -22,13 +22,24 @@ describe RHC::Wizard do
22
22
  let(:default_options){ {} }
23
23
 
24
24
  describe "#finalize_stage" do
25
- subject{ RHC::Wizard.new(config, options) }
25
+ subject{ described_class.new(config, options) }
26
26
  before{ subject.should_receive(:say).with(/The OpenShift client tools have been configured/) }
27
27
  it{ subject.send(:finalize_stage).should be_true }
28
28
  end
29
29
 
30
+ describe "#token_store" do
31
+ subject{ described_class.new(config, options) }
32
+ it{ subject.send(:token_store).should be_a(RHC::Auth::TokenStore) }
33
+ end
34
+
35
+ describe "#has_configuration?" do
36
+ subject{ described_class }
37
+ before{ File.should_receive(:exists?).with(RHC::Config.local_config_path).at_least(1).times.and_return(true) }
38
+ its(:has_configuration?){ should be_true }
39
+ end
40
+
30
41
  describe "#test_ssh_connectivity" do
31
- subject{ RHC::Wizard.new(config, options) }
42
+ subject{ described_class.new(config, options) }
32
43
  let(:app) do
33
44
  app = Object.new
34
45
  app.should_receive(:host).at_least(1).and_return('foo.com')
@@ -66,30 +77,39 @@ describe RHC::Wizard do
66
77
  let(:rest_client){ stub }
67
78
  let(:auth){ subject.send(:auth) }
68
79
 
69
- subject{ RHC::Wizard.new(config, options) }
80
+ subject{ described_class.new(config, options) }
70
81
 
71
- def expect_client_test
82
+ def expect_client_test(with_sessions=false)
72
83
  subject.should_receive(:new_client_for_options).ordered.and_return(rest_client)
73
84
  rest_client.should_receive(:api).ordered
74
85
  rest_client.should_receive(:user).ordered.and_return(true)
86
+ rest_client.should_receive(:supports_sessions?).ordered.and_return(with_sessions)
75
87
  end
76
88
  def expect_raise_from_api(error)
77
- #subject.send(:auth).should_receive(:ask).with("Using #{user} to login to openshift.redhat.com").and_return(username).ordered
78
- #subject.send(:auth).should_receive(:ask).with("Password: ").and_return(password).ordered
79
89
  subject.should_receive(:new_client_for_options).ordered.and_return(rest_client)
80
90
  rest_client.should_receive(:api).ordered.and_raise(error)
81
91
  end
82
92
 
83
93
  it "should prompt for user and password" do
84
- #auth.should_receive(:ask).with("Login to openshift.redhat.com: ").ordered.and_return(user)
85
- #auth.should_receive(:ask).with("Password: ").ordered.and_return(password)
86
94
  expect_client_test
87
-
88
95
  subject.send(:login_stage).should be_true
89
96
  end
90
97
 
98
+ context "with token" do
99
+ let(:token){ 'a_test_value' }
100
+ let(:default_options){ {:token => token, :rhlogin => user} }
101
+ before{ subject.should_receive(:say).with(/Using an existing token for #{user} to login to /).ordered }
102
+
103
+ it "should continue without prompt" do
104
+ expect_client_test
105
+ subject.send(:login_stage).should be_true
106
+ end
107
+ end
108
+
91
109
  context "with credentials" do
92
- let(:default_options){ {:rhlogin => user, :password => password} }
110
+ let(:server){ mock_uri }
111
+ let(:default_options){ {:rhlogin => user, :password => password, :server => server} }
112
+ before{ subject.should_receive(:say).with(/Using #{user} to login to /).ordered }
93
113
 
94
114
  it "should warn about a self signed cert error" do
95
115
  expect_raise_from_api(RHC::Rest::SelfSignedCertificate.new('reason', 'message'))
@@ -131,6 +151,36 @@ describe RHC::Wizard do
131
151
  subject.send(:login_stage).should be_nil
132
152
  options.insecure.should be_false
133
153
  end
154
+
155
+ context "with a server that supports tokens" do
156
+ before{ expect_client_test(true) }
157
+ let(:token){ 'a_test_value' }
158
+ let(:auth_token){ mock(:token => token, :expires_in_seconds => 100) }
159
+ let(:store){ mock }
160
+ before{ RHC::Auth::TokenStore.should_receive(:new).any_number_of_times.and_return(store) }
161
+
162
+ it "should not generate a token if the user does not request it" do
163
+ subject.should_receive(:info).with(/OpenShift can create and store a token on disk/).ordered
164
+ subject.should_receive(:agree).with(/Generate a token now?/).ordered.and_return(false)
165
+
166
+ subject.send(:login_stage).should be_true
167
+ options.token.should be_nil
168
+ end
169
+
170
+ it "should generate a token if the user requests it" do
171
+ subject.should_receive(:info).with(/OpenShift can create and store a token on disk/).ordered
172
+ subject.should_receive(:agree).with(/Generate a token now?/).ordered.and_return(true)
173
+ subject.should_receive(:say).with(/Generating an authorization token for this client /).ordered
174
+ rest_client.should_receive(:new_session).ordered.and_return(auth_token)
175
+ store.should_receive(:put).with(user, server, token).ordered.and_return(true)
176
+ subject.should_receive(:new_client_for_options).ordered.and_return(rest_client)
177
+ rest_client.should_receive(:user).ordered.and_return(true)
178
+ subject.should_receive(:success).with(/lasts 1 minute/).ordered
179
+
180
+ subject.send(:login_stage).should be_true
181
+ options.token.should == token
182
+ end
183
+ end
134
184
  end
135
185
  end
136
186
 
@@ -231,9 +281,8 @@ describe RHC::Wizard do
231
281
  should_be_done
232
282
  end
233
283
  end
234
-
235
284
  context "when the user inputs incorrect authentication" do
236
- before{ stub_api_request(:get, 'broker/rest/user', :user => username, :password => 'invalid').to_return(:status => 401) }
285
+ before{ stub_api_request(:get, 'broker/rest/user', :user => username, :password => 'invalid').to_return(:status => 401).times(1).to_return(simple_user(username)) }
237
286
  it "should prompt them again" do
238
287
  should_greet_user
239
288
 
data/spec/spec_helper.rb CHANGED
@@ -72,6 +72,86 @@ module Commander::UI
72
72
  end
73
73
 
74
74
 
75
+ module CommandExampleHelpers
76
+ #
77
+ # Allow this example to stub command methods
78
+ # by guaranteeing the instance exists prior
79
+ # to command execution. Use with methods on
80
+ # CommandHelpers
81
+ #
82
+ def using_command_instance
83
+ subject{ described_class }
84
+ let(:instance) { described_class.new }
85
+ end
86
+ end
87
+ #
88
+ # Helper methods for executing commands and
89
+ # stubbing/mocking methods
90
+ #
91
+ module CommandHelpers
92
+ def command_runner(*args)
93
+ mock_terminal
94
+ new_command_runner *args do
95
+ instance #ensure instance is created before subject :new is mocked
96
+ subject.should_receive(:new).any_number_of_times.and_return(instance)
97
+ RHC::Commands.to_commander
98
+ end
99
+ end
100
+ def run!(*args)
101
+ command_runner(*args).run!
102
+ end
103
+ def expects_running(*args, &block)
104
+ r = command_runner(*args)
105
+ lambda { r.run! }
106
+ end
107
+ def command_for(*args)
108
+ command = nil
109
+ RHC::Commands.stub(:execute){ |cmd, method, args| command = cmd; 0 }
110
+ command_runner(*args).run!
111
+ command
112
+ end
113
+
114
+ #
115
+ # These methods assume the example has declared
116
+ # let(:arguments){ [<arguments>] }
117
+ #
118
+
119
+ def run_command
120
+ mock_terminal
121
+ input.each { |i| $terminal.write_line(i) } if respond_to?(:input)
122
+ $terminal.close_write
123
+ run!(*arguments)
124
+ end
125
+ def command_output
126
+ run_command
127
+ rescue SystemExit => e
128
+ "#{@output.string}\n#{$stderr.string}#{e}"
129
+ else
130
+ "#{@output.string}\n#{$stderr.string}"
131
+ end
132
+
133
+ #
134
+ # These methods bypass normal command stubbing.
135
+ # Should really be used when stubbing the whole
136
+ # path. Most specs should use run_instance.
137
+ #
138
+ def run(input=[])
139
+ mock_terminal
140
+ input.each { |i| $terminal.write_line(i) }
141
+ $terminal.close_write
142
+ RHC::CLI.start(arguments)
143
+ end
144
+
145
+ def run_output(input=[])
146
+ run(input)
147
+ rescue SystemExit => e
148
+ "#{@output.string}\n#{$stderr.string}#{e}"
149
+ else
150
+ "#{@output.string}\n#{$stderr.string}"
151
+ end
152
+
153
+ end
154
+
75
155
  module ClassSpecHelpers
76
156
 
77
157
  include Commander::Delegates
@@ -108,31 +188,6 @@ module ClassSpecHelpers
108
188
  Commander::Runner.instance
109
189
  end
110
190
 
111
- #
112
- #
113
- #
114
- def expects_running(*args, &block)
115
- mock_terminal
116
- r = new_command_runner *args do
117
- instance #ensure instance is created before subject :new is mocked
118
- subject.should_receive(:new).any_number_of_times.and_return(instance)
119
- RHC::Commands.to_commander
120
- end
121
- lambda { r.run! }
122
- end
123
- def command_for(*args)
124
- mock_terminal
125
- r = new_command_runner *args do
126
- instance #ensure instance is created before subject :new is mocked
127
- subject.should_receive(:new).any_number_of_times.and_return(instance)
128
- RHC::Commands.to_commander
129
- end
130
- command = nil
131
- RHC::Commands.stub(:execute){ |cmd, method, args| command = cmd; 0 }
132
- r.run!
133
- command
134
- end
135
-
136
191
  class MockHighLineTerminal < HighLine
137
192
  def initialize(input, output)
138
193
  super
@@ -224,23 +279,6 @@ module ClassSpecHelpers
224
279
  $terminal = old_terminal
225
280
  end
226
281
 
227
- def run(input=[])
228
- #Commander::Runner.instance_variable_set :"@singleton", nil
229
- mock_terminal
230
- input.each { |i| $terminal.write_line(i) }
231
- $terminal.close_write
232
- #"#{@output.string}\n#{$stderr.string}"
233
- RHC::CLI.start(arguments)
234
- end
235
-
236
- def run_output(input=[])
237
- run(input)
238
- rescue SystemExit => e
239
- "#{@output.string}\n#{$stderr.string}#{e}"
240
- else
241
- "#{@output.string}\n#{$stderr.string}"
242
- end
243
-
244
282
  #
245
283
  # usage: stub_request(...).with(&user_agent_header)
246
284
  #
@@ -329,6 +367,48 @@ module CommanderInvocationMatchers
329
367
  end
330
368
  end
331
369
 
370
+ module ColorMatchers
371
+ COLORS = {
372
+ :green => 32,
373
+ :yellow => 33,
374
+ :cyan => 36,
375
+ :red => 31,
376
+ :clear => 0
377
+ }
378
+
379
+ Spec::Matchers.define :be_colorized do |msg,color|
380
+ match do |actual|
381
+ actual == colorized_message(msg,color)
382
+ end
383
+
384
+ failure_message_for_should do |actual|
385
+ failure_message(actual,msg,color)
386
+ end
387
+
388
+ failure_message_for_should_not do |actual|
389
+ failure_message(actual,msg,color)
390
+ end
391
+
392
+ def failure_message(actual,msg,color)
393
+ "expected: #{colorized_message(msg,color).inspect}\n" +
394
+ " got: #{actual.inspect}"
395
+ end
396
+
397
+ def ansi_code(color)
398
+ "\e[#{ColorMatchers::COLORS[color]}m"
399
+ end
400
+
401
+ def colorized_message(msg,color)
402
+ [
403
+ ansi_code(color),
404
+ msg,
405
+ ansi_code(:clear),
406
+ "\n"
407
+ ].join('')
408
+ end
409
+ end
410
+ end
411
+
332
412
  def mac?
333
413
  RbConfig::CONFIG['host_os'] =~ /^darwin/
334
414
  end
@@ -336,7 +416,10 @@ end
336
416
  Spec::Runner.configure do |config|
337
417
  config.include(ExitCodeMatchers)
338
418
  config.include(CommanderInvocationMatchers)
419
+ config.include(ColorMatchers)
339
420
  config.include(ClassSpecHelpers)
421
+ config.include(CommandHelpers)
422
+ config.extend(CommandExampleHelpers)
340
423
  end
341
424
 
342
425
  module TestEnv
@@ -37,6 +37,7 @@ module WizardStepsHelper
37
37
  RHC::Vendor::ParseConfig.new(current_config_path).tap do |cp|
38
38
  cp["default_rhlogin"].should == username
39
39
  cp["libra_server"].should == mock_uri
40
+ cp["use_authorization_tokens"].should == 'false'
40
41
  end
41
42
  end
42
43