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.
- data/features/application.feature +1 -0
- data/features/lib/rhc_helper/app.rb +5 -3
- data/features/lib/rhc_helper/commandify.rb +2 -1
- data/features/step_definitions/application_steps.rb +2 -1
- data/features/support/env.rb +4 -1
- data/lib/rhc/auth/basic.rb +18 -13
- data/lib/rhc/auth/token.rb +98 -0
- data/lib/rhc/auth/token_store.rb +51 -0
- data/lib/rhc/auth.rb +3 -1
- data/lib/rhc/command_runner.rb +1 -0
- data/lib/rhc/commands/account.rb +47 -1
- data/lib/rhc/commands/alias.rb +2 -4
- data/lib/rhc/commands/app.rb +23 -18
- data/lib/rhc/commands/authorization.rb +93 -0
- data/lib/rhc/commands/base.rb +11 -3
- data/lib/rhc/commands/cartridge.rb +8 -16
- data/lib/rhc/commands/git_clone.rb +2 -3
- data/lib/rhc/commands/port_forward.rb +10 -11
- data/lib/rhc/commands/setup.rb +4 -1
- data/lib/rhc/commands/snapshot.rb +4 -3
- data/lib/rhc/commands/tail.rb +3 -4
- data/lib/rhc/commands/threaddump.rb +1 -2
- data/lib/rhc/commands.rb +37 -3
- data/lib/rhc/config.rb +10 -1
- data/lib/rhc/context_helper.rb +5 -1
- data/lib/rhc/core_ext.rb +10 -0
- data/lib/rhc/exceptions.rb +0 -12
- data/lib/rhc/git_helpers.rb +12 -0
- data/lib/rhc/helpers.rb +31 -1
- data/lib/rhc/output_helpers.rb +19 -3
- data/lib/rhc/rest/api.rb +2 -1
- data/lib/rhc/rest/application.rb +5 -4
- data/lib/rhc/rest/authorization.rb +10 -0
- data/lib/rhc/rest/base.rb +6 -1
- data/lib/rhc/rest/client.rb +243 -122
- data/lib/rhc/rest/domain.rb +0 -15
- data/lib/rhc/rest/gear_group.rb +0 -1
- data/lib/rhc/rest/mock.rb +118 -16
- data/lib/rhc/rest/user.rb +0 -1
- data/lib/rhc/rest.rb +28 -8
- data/lib/rhc/ssh_helpers.rb +5 -2
- data/lib/rhc/tar_gz.rb +16 -5
- data/lib/rhc/usage_templates/help.erb +1 -1
- data/lib/rhc/wizard.rb +54 -10
- data/spec/coverage_helper.rb +9 -0
- data/spec/rhc/auth_spec.rb +229 -22
- data/spec/rhc/cli_spec.rb +15 -0
- data/spec/rhc/command_spec.rb +100 -8
- data/spec/rhc/commands/account_spec.rb +75 -1
- data/spec/rhc/commands/app_spec.rb +23 -5
- data/spec/rhc/commands/authorization_spec.rb +120 -0
- data/spec/rhc/commands/domain_spec.rb +2 -2
- data/spec/rhc/commands/git_clone_spec.rb +24 -0
- data/spec/rhc/commands/port_forward_spec.rb +22 -23
- data/spec/rhc/commands/server_spec.rb +2 -2
- data/spec/rhc/commands/setup_spec.rb +12 -0
- data/spec/rhc/config_spec.rb +7 -3
- data/spec/rhc/helpers_spec.rb +62 -9
- data/spec/rhc/rest_application_spec.rb +24 -0
- data/spec/rhc/rest_client_spec.rb +66 -56
- data/spec/rhc/rest_spec.rb +11 -2
- data/spec/rhc/wizard_spec.rb +61 -12
- data/spec/spec_helper.rb +125 -42
- data/spec/wizard_spec_helper.rb +1 -0
- metadata +9 -3
data/spec/rhc/helpers_spec.rb
CHANGED
@@ -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(
|
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
|
-
|
49
|
-
|
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
|
-
|
52
|
-
|
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
|
-
|
55
|
-
it("should
|
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
|
-
|
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 "
|
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
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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 ==
|
271
|
-
match.domain_id.should ==
|
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(
|
274
|
-
end
|
254
|
+
mock_response_links(mock_app_links(mock_domain, mock_app))
|
275
255
|
end
|
276
|
-
it "Raises an
|
277
|
-
expect { client.
|
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
|
data/spec/rhc/rest_spec.rb
CHANGED
@@ -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
|
|
data/spec/rhc/wizard_spec.rb
CHANGED
@@ -22,13 +22,24 @@ describe RHC::Wizard do
|
|
22
22
|
let(:default_options){ {} }
|
23
23
|
|
24
24
|
describe "#finalize_stage" do
|
25
|
-
subject{
|
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{
|
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{
|
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(:
|
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
|
data/spec/wizard_spec_helper.rb
CHANGED