startapp 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,442 @@
1
+ require 'spec_helper'
2
+ require 'base64'
3
+ require 'rhc/commands'
4
+
5
+ describe RHC::Auth::Basic do
6
+ let(:user){ 'test_user' }
7
+ let(:password){ 'test pass' }
8
+ let(:auth_hash){ {:user => user, :password => password} }
9
+ let(:options){ (o = Commander::Command::Options.new).default(default_options); o }
10
+ let(:default_options){ {} }
11
+ let(:client){ double(:supports_sessions? => false) }
12
+
13
+ its(:username){ should be_nil }
14
+ its(:username?){ should be_false }
15
+ its(:password){ should be_nil }
16
+ its(:options){ should_not be_nil }
17
+ its(:can_authenticate?){ should be_false }
18
+ its(:openshift_server){ should == 'broker.startapp.bg' }
19
+
20
+ def resolved(hash)
21
+ hash.each_pair do |k,v|
22
+ hash[k] = v.call if v.is_a? Proc
23
+ end
24
+ hash
25
+ end
26
+
27
+ context "with user options" do
28
+ subject{ described_class.new(options) }
29
+
30
+ its(:username){ should be_nil }
31
+ its(:username?){ should be_false }
32
+ its(:password){ should be_nil }
33
+ its(:options){ should equal(options) }
34
+
35
+ context "that include user info" do
36
+ let(:default_options){ {:rhlogin => user, :password => password} }
37
+
38
+ its(:username){ should == user }
39
+ its(:username?){ should be_true }
40
+ its(:password){ should == password }
41
+ its(:can_authenticate?){ should be_true }
42
+ end
43
+
44
+ context "that includes server" do
45
+ let(:default_options){ {:server => 'test.com'} }
46
+
47
+ its(:openshift_server){ should == 'test.com' }
48
+ it do
49
+ subject.should_receive(:ask).with("Login to test.com: ").and_return(user)
50
+ subject.send(:ask_username).should == user
51
+ end
52
+ end
53
+
54
+ context "with --noprompt" do
55
+ let(:default_options){ {:noprompt => true} }
56
+
57
+ its(:ask_username){ should be_false }
58
+ its(:ask_password){ should be_false }
59
+ its(:username?){ should be_false }
60
+ it("should not retry") do
61
+ subject.should_not_receive(:ask_username)
62
+ subject.retry_auth?(double(:status => 401), client).should be_false
63
+ end
64
+ end
65
+ end
66
+
67
+ context "when initialized with a hash" do
68
+ subject{ described_class.new({:rhlogin => user, :password => password}) }
69
+ its(:username){ should == user }
70
+ its(:password){ should == password }
71
+ end
72
+
73
+
74
+ describe "#ask_username" do
75
+ before{ subject.should_receive(:openshift_server).and_return('test.com') }
76
+ before{ subject.should_receive(:ask).with("Login to test.com: ").and_return(user) }
77
+
78
+ it do
79
+ subject.send(:ask_username).should == user
80
+ subject.send(:username).should == user
81
+ end
82
+
83
+ context "with a different user" do
84
+ subject{ described_class.new('other', nil) }
85
+ it do
86
+ subject.send(:ask_username).should == user
87
+ subject.send(:username).should == user
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#ask_password" do
93
+ before{ subject.should_receive(:ask).with("Password: ").and_return(password) }
94
+ it do
95
+ subject.send(:ask_password).should == password
96
+ subject.send(:password).should == password
97
+ end
98
+
99
+ context "with a different password" do
100
+ subject{ described_class.new(user, 'other') }
101
+ it do
102
+ subject.send(:ask_password).should == password
103
+ subject.send(:password).should == password
104
+ end
105
+ end
106
+ end
107
+
108
+ describe "#to_request" do
109
+ let(:request){ {} }
110
+
111
+ context "when the request is lazy" do
112
+ let(:request){ {:lazy_auth => true} }
113
+ before{ subject.should_receive(:ask_username).never }
114
+ before{ subject.should_receive(:ask_password).never }
115
+
116
+ it { subject.to_request(request).should == request }
117
+ end
118
+
119
+ context "when password and user are provided" do
120
+ subject{ described_class.new(user, password) }
121
+
122
+ it { subject.to_request(request).should equal(request) }
123
+ it { resolved(subject.to_request(request)).should == auth_hash }
124
+
125
+ context "when the request is lazy" do
126
+ let(:request){ {:lazy_auth => true} }
127
+
128
+ it { subject.to_request(request).should == auth_hash.merge(request) }
129
+ end
130
+ end
131
+
132
+ context "when password is not provided" do
133
+ subject{ described_class.new(user, nil) }
134
+
135
+ its(:password){ should be_nil }
136
+ it "should ask for the password" do
137
+ subject.should_receive(:ask_password).and_return(password)
138
+ resolved(subject.to_request(request)).should == auth_hash
139
+ end
140
+ it "should remember the password" do
141
+ subject.should_receive(:ask_password).and_return(password)
142
+ subject.to_request(request)
143
+ resolved(subject.to_request(request)).should == auth_hash
144
+ end
145
+
146
+ context "when the request is lazy" do
147
+ let(:request){ {:lazy_auth => true} }
148
+ before{ subject.should_receive(:ask_password).never }
149
+
150
+ it { subject.to_request(request).should == auth_hash.merge(request) }
151
+ end
152
+ end
153
+
154
+ context "when user is not provided" do
155
+ subject{ described_class.new(nil, password) }
156
+
157
+ its(:username){ should be_nil }
158
+ it "should ask for the username" do
159
+ subject.should_receive(:ask_username).and_return(user)
160
+ resolved(subject.to_request(request)).should == auth_hash
161
+ end
162
+ it "should remember the username" do
163
+ subject.should_receive(:ask_username).and_return(user)
164
+ subject.to_request(request)
165
+ resolved(subject.to_request(request)).should == auth_hash
166
+ end
167
+
168
+ context "when the request is lazy" do
169
+ let(:request){ {:lazy_auth => true} }
170
+ before{ subject.should_receive(:ask_username).never }
171
+
172
+ it { subject.to_request(request).should == auth_hash.merge(request) }
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "#retry_auth?" do
178
+ context "when the response succeeds" do
179
+ let(:response){ double(:cookies => {}, :status => 200) }
180
+
181
+ it{ subject.retry_auth?(response, client).should be_false }
182
+ end
183
+ context "when the response succeeds with a cookie" do
184
+ let(:response){ double(:cookies => [double(:name => 'rh_sso', :value => '1')], :status => 200) }
185
+ it{ subject.retry_auth?(response, client).should be_false }
186
+ end
187
+ context "when the response requires authentication" do
188
+ let(:response){ double(:status => 401) }
189
+
190
+ context "with no user and no password" do
191
+ subject{ described_class.new(nil, nil) }
192
+ it("should ask for user and password") do
193
+ subject.should_receive(:ask_username).and_return(user)
194
+ subject.should_receive(:ask_password).and_return(password)
195
+ subject.retry_auth?(response, client).should be_true
196
+ end
197
+ end
198
+
199
+ context "with user and no password" do
200
+ subject{ described_class.new(user, nil) }
201
+ it("should ask for password only") do
202
+ subject.should_receive(:ask_password).and_return(password)
203
+ subject.retry_auth?(response, client).should be_true
204
+ end
205
+ it("should ask for password twice") do
206
+ subject.should_receive(:ask_password).twice.and_return(password)
207
+ subject.retry_auth?(response, client).should be_true
208
+ subject.retry_auth?(response, client).should be_true
209
+ end
210
+ end
211
+
212
+ context "with user and password" do
213
+ subject{ described_class.new(user, password) }
214
+ it("should not prompt for reauthentication") do
215
+ subject.should_not_receive(:ask_password)
216
+ subject.should_receive(:error).with("Username or password is not correct")
217
+ subject.retry_auth?(response, client).should be_false
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ describe RHC::Auth::Token do
225
+ subject{ described_class.new(options) }
226
+
227
+ let(:token){ 'a_token' }
228
+ let(:options){ (o = Commander::Command::Options.new).default(default_options); o }
229
+ let(:default_options){ {} }
230
+ let(:client){ double(:supports_sessions? => false) }
231
+ let(:auth){ nil }
232
+ let(:store){ nil }
233
+
234
+ its(:username){ should be_nil }
235
+ its(:options){ should_not be_nil }
236
+ its(:can_authenticate?){ should be_false }
237
+ its(:openshift_server){ should == 'broker.startapp.bg' }
238
+
239
+ context "with user options" do
240
+ its(:username){ should be_nil }
241
+ its(:options){ should equal(options) }
242
+
243
+ context "that include token" do
244
+ let(:default_options){ {:token => token} }
245
+ its(:can_authenticate?){ should be_true }
246
+ end
247
+
248
+ context "that includes server" do
249
+ let(:default_options){ {:server => 'test.com'} }
250
+ its(:openshift_server){ should == 'test.com' }
251
+ end
252
+
253
+ context "with --noprompt" do
254
+ let(:default_options){ {:noprompt => true} }
255
+
256
+ its(:username){ should be_nil }
257
+ it("should not retry") do
258
+ end
259
+ end
260
+ end
261
+
262
+ context "when initialized with a hash" do
263
+ subject{ described_class.new({:token => token}) }
264
+ its(:token){ should == token }
265
+ end
266
+
267
+ context "when initialized with a string" do
268
+ subject{ described_class.new(token) }
269
+ its(:token){ should == token }
270
+ end
271
+
272
+ context "when initialized with an auth object" do
273
+ subject{ described_class.new(nil, auth) }
274
+ let(:auth){ double(:username => 'foo') }
275
+ its(:username){ should == 'foo' }
276
+ end
277
+
278
+ context "when initialized with a store" do
279
+ subject{ described_class.new(nil, nil, store) }
280
+ let(:store){ double }
281
+ before{ store.should_receive(:get).with(nil, 'broker.startapp.bg').and_return(token) }
282
+ it("should read the token for the user") do
283
+ subject.send(:token).should == token
284
+ end
285
+ end
286
+
287
+ describe "#save" do
288
+ subject{ described_class.new(nil, nil, store) }
289
+ context "when store is set" do
290
+ let(:store){ double(:get => nil) }
291
+ it("should call put on store") do
292
+ subject.should_receive(:username).and_return('foo')
293
+ subject.should_receive(:openshift_server).and_return('bar')
294
+ store.should_receive(:put).with('foo', 'bar', token)
295
+ subject.save(token)
296
+ end
297
+ end
298
+ context "when store is nil" do
299
+ it("should skip calling store"){ subject.save(token) }
300
+ end
301
+ after{ subject.instance_variable_get(:@token).should == token }
302
+ end
303
+
304
+ describe "#to_request" do
305
+ let(:request){ {} }
306
+ subject{ described_class.new(token, auth) }
307
+
308
+ context "when token is provided" do
309
+ it("should pass bearer token to the server"){ subject.to_request(request).should == {:headers => {'authorization' => "Bearer #{token}"}} }
310
+
311
+ context "when the request is lazy" do
312
+ let(:request){ {:lazy_auth => true} }
313
+ it("should pass bearer token to the server"){ subject.to_request(request).should == {:lazy_auth => true, :headers => {'authorization' => "Bearer #{token}"}} }
314
+ end
315
+ end
316
+
317
+ context "when token is not provided" do
318
+ subject{ described_class.new(nil) }
319
+
320
+ it("should pass not bearer token to the server"){ subject.to_request(request).should == {} }
321
+ end
322
+
323
+ context "when a parent auth class is passed" do
324
+ subject{ described_class.new(nil, auth) }
325
+ let(:auth){ double }
326
+ it("should invoke the parent") do
327
+ auth.should_receive(:to_request).with(request).and_return(request)
328
+ subject.to_request(request).should == request
329
+ end
330
+ end
331
+ end
332
+
333
+ describe "#retry_auth?" do
334
+ subject{ described_class.new(token, auth) }
335
+
336
+ context "when the response succeeds" do
337
+ let(:response){ double(:cookies => {}, :status => 200) }
338
+ it{ subject.retry_auth?(response, client).should be_false }
339
+ end
340
+
341
+ context "when the response requires authentication" do
342
+ let(:response){ double(:status => 401) }
343
+
344
+ context "with no token" do
345
+ subject{ described_class.new(nil, nil) }
346
+ it("should return false"){ subject.retry_auth?(response, client).should be_false }
347
+ end
348
+
349
+ context "when a nested auth object can't authenticate" do
350
+ let(:auth){ double(:can_authenticate? => false) }
351
+ it("should raise an error"){ expect{ subject.retry_auth?(response, client) }.to raise_error(RHC::Rest::TokenExpiredOrInvalid) }
352
+ end
353
+
354
+ context "with a nested auth object" do
355
+ let(:auth){ double('nested_auth', :can_authenticate? => true) }
356
+ subject{ described_class.new(options, auth) }
357
+
358
+ it("should not use token auth") do
359
+ auth.should_receive(:retry_auth?).with(response, client).and_return true
360
+ subject.retry_auth?(response, client).should be_true
361
+ end
362
+
363
+ context "when noprompt is requested" do
364
+ let(:default_options){ {:token => token, :noprompt => true} }
365
+ it("should raise an error"){ expect{ subject.retry_auth?(response, client) }.to raise_error(RHC::Rest::TokenExpiredOrInvalid) }
366
+ end
367
+
368
+ context "when authorization tokens are enabled locally" do
369
+ let(:default_options){ {:use_authorization_tokens => true} }
370
+
371
+ context "without session support" do
372
+ let(:default_options){ {:use_authorization_tokens => true, :token => 'foo'} }
373
+ let(:client){ double('client', :supports_sessions? => false) }
374
+
375
+ it("should invoke raise an error on retry because sessions are not supported") do
376
+ expect{ subject.retry_auth?(response, client) }.to raise_error RHC::Rest::AuthorizationsNotSupported
377
+ end
378
+ end
379
+
380
+ context "we expect a warning and a call to client" do
381
+ let(:auth_token){ nil }
382
+ let(:client){ double('client', :supports_sessions? => true) }
383
+ before{ client.should_receive(:new_session).with(:auth => auth).and_return(auth_token) }
384
+
385
+ it("should print a message") do
386
+ subject.should_receive(:info).with("Please sign in to start a new session to #{subject.openshift_server}.")
387
+ auth.should_receive(:retry_auth?).with(response, client).and_return true
388
+ subject.retry_auth?(response, client).should be_true
389
+ end
390
+
391
+ context "with a token" do
392
+ let(:default_options){ {:use_authorization_tokens => true, :token => 'foo'} }
393
+ it("should invoke raise an error on retry because sessions are not supported") do
394
+ subject.should_receive(:warn).with("Your authorization token has expired. Please sign in now to continue on #{subject.openshift_server}.")
395
+ auth.should_receive(:retry_auth?).with(response, client).and_return true
396
+ subject.retry_auth?(response, client).should be_true
397
+ #expect{ subject.retry_auth?(response, client) }.to raise_error RHC::Rest::AuthorizationsNotSupported
398
+ end
399
+ end
400
+
401
+ context "when the token request fails" do
402
+ before{ subject.should_receive(:info).with("Please sign in to start a new session to #{subject.openshift_server}.") }
403
+ it("should invoke retry on the parent") do
404
+ auth.should_receive(:retry_auth?).with(response, client).and_return false
405
+ subject.retry_auth?(response, client).should be_false
406
+ end
407
+ end
408
+
409
+ context "when the token request succeeds" do
410
+ let(:auth_token){ double('auth_token', :token => 'bar') }
411
+ before{ subject.should_receive(:info).with("Please sign in to start a new session to #{subject.openshift_server}.") }
412
+ it("should save the token and return true") do
413
+ subject.should_receive(:save).with(auth_token.token).and_return true
414
+ subject.retry_auth?(response, client).should be_true
415
+ end
416
+ end
417
+ end
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+
424
+ describe RHC::Auth::TokenStore do
425
+ subject{ described_class.new(dir) }
426
+ let(:dir){ Dir.mktmpdir }
427
+
428
+ context "when a key is stored" do
429
+ before{ subject.put('foo', 'bar', 'token') }
430
+ it("can be retrieved"){ subject.get('foo', 'bar').should == 'token' }
431
+ end
432
+
433
+ it("should handle missing files"){ subject.get('foo', 'other').should be_nil }
434
+ it("should put a file on disk"){ expect{ subject.put('test', 'server', 'value') }.to change{ Dir.entries(dir).length }.by(1) }
435
+
436
+ describe "#clear" do
437
+ before{ subject.put('test', 'server2', 'value2') }
438
+ it("should return true"){ subject.clear.should be_true }
439
+ it("should empty the directory"){ expect{ subject.clear }.to change{ Dir.entries(dir).length }.by_at_least(-1) }
440
+ after{ Dir.entries(dir).length.should == 2 }
441
+ end
442
+ end
@@ -0,0 +1,186 @@
1
+ require 'spec_helper'
2
+ require 'rhc/wizard'
3
+
4
+ describe RHC::CLI do
5
+
6
+ shared_examples_for 'a global help page' do
7
+ let(:arguments) { @arguments or raise "no arguments" }
8
+ it('should contain the program description') { run_output.should =~ /Command line interface for StartApp/ }
9
+ it('should describe getting started') { run_output.should =~ /Getting started:/ }
10
+ it('should describe basic command') { run_output.should =~ /Working with apps:/ }
11
+ it('should mention the help command') { run_output.should =~ /See 'app help <command>'/ }
12
+ it('should mention the help options command') { run_output.should =~ /app help options/ }
13
+ end
14
+
15
+ shared_examples_for 'a first run wizard' do
16
+ let(:arguments) { @arguments or raise "no arguments" }
17
+ let!(:wizard){ RHC::Wizard.new }
18
+ before{ RHC::Wizard.should_receive(:new).and_return(wizard) }
19
+ it('should create and run a new wizard') { expect{ run }.to call(:run).on(wizard) }
20
+ end
21
+
22
+ shared_examples_for 'a help page' do
23
+ let(:arguments) { @arguments or raise "no arguments" }
24
+ it('should contain the program description') { run_output.should =~ /Command line interface for StartApp/ }
25
+ it('should contain the global options') { run_output.should =~ /Global Options/ }
26
+ it('should provide a --config switch') { run_output.should =~ /\-\-config FILE/ }
27
+ end
28
+
29
+ shared_examples_for 'a list of all commands' do
30
+ let(:arguments) { @arguments or raise "no arguments" }
31
+ it('should contain a message') { run_output.should =~ /Showing all commands/ }
32
+ it('should contain command help') { run_output.should =~ /Create an application./ }
33
+ it('should contain aliases') { run_output.should =~ /\(also/ }
34
+ end
35
+
36
+ shared_examples_for 'a list of commands' do
37
+ let(:arguments) { @arguments or raise "no arguments" }
38
+ it('should contain a message') { run_output.should =~ /Showing commands matching '/ }
39
+ it('should contain command help') { run_output.should =~ /Create an application./ }
40
+ it('should contain aliases') { run_output.should =~ /\(also/ }
41
+ end
42
+
43
+ shared_examples_for 'a command-line options help page' do
44
+ let(:arguments) { @arguments or raise "no arguments" }
45
+ it('should contain an introduction') { run_output.should =~ /The following options can be passed to any/ }
46
+ it('should reference the configuration') { run_output.should match(".startapp/express.conf") }
47
+ it('should describe the --config switch') { run_output.should =~ /\-\-config FILE/ }
48
+ it('should describe the --ssl-version switch') { run_output.should =~ /\-\-ssl\-version VERSION/ }
49
+ end
50
+
51
+ shared_examples_for 'an invalid command' do
52
+ let(:arguments) { @arguments }
53
+ it('should contain the invalid command message') { run_output.should =~ /is not recognized/ }
54
+ it('should contain the arguments') { run_output.should include(@arguments[0]) }
55
+ it('should reference --help') { run_output.should =~ / help\b/ }
56
+ end
57
+
58
+ shared_examples_for 'version output' do
59
+ let(:arguments) { @arguments }
60
+ it 'should contain version output' do
61
+ run_output.should =~ /app \d+\.\d+(:?\.d+)?/
62
+ end
63
+ end
64
+
65
+ before{ base_config }
66
+
67
+ describe "--version" do
68
+ context "by itself" do
69
+ before :each do
70
+ @arguments = ['--version']
71
+ end
72
+ it_should_behave_like 'version output'
73
+ end
74
+ end
75
+
76
+ describe '#start' do
77
+ before{ RHC::Wizard.stub(:has_configuration?).and_return(true) }
78
+
79
+ context 'with no arguments' do
80
+ before(:each) { @arguments = [] }
81
+ it_should_behave_like 'a global help page'
82
+
83
+ context "without a config file" do
84
+ it_should_behave_like 'a global help page'
85
+ end
86
+ end
87
+
88
+ context 'with an ambiguous option' do
89
+ let(:arguments){ ['help', '-s'] }
90
+ it('should describe an ambiguous error'){ run_output.should match("The option -s is ambiguous. You will need to specify the entire option.") }
91
+ end
92
+
93
+ context 'with an invalid command' do
94
+ before(:each) { @arguments = ['invalidcommand'] }
95
+ it_should_behave_like 'an invalid command'
96
+ end
97
+
98
+ context 'with --help and invalid command' do
99
+ before(:each) { @arguments = ['invalidcommand', '--help'] }
100
+ it_should_behave_like 'an invalid command'
101
+ end
102
+
103
+ context 'with help and invalid command' do
104
+ before(:each) { @arguments = ['help', 'invalidcommand'] }
105
+ it_should_behave_like 'an invalid command'
106
+ end
107
+
108
+ context 'with help commands' do
109
+ before(:each) { @arguments = ['help', 'commands'] }
110
+ it_should_behave_like 'a list of all commands'
111
+ end
112
+
113
+ context 'with help and possible command matches' do
114
+ before(:each) { @arguments = ['help', 'app c'] }
115
+ it_should_behave_like 'a list of commands'
116
+ end
117
+
118
+ context 'with help and a single matching command segment' do
119
+ let(:arguments){ ['help', 'app creat'] }
120
+ it("prints the usage for the command"){ run_output.should match('Usage: app app-create <') }
121
+ it("prints part of the description for the command"){ run_output.should match('StartApp runs the components of your') }
122
+ it("prints a local option"){ run_output.should match('--namespace NAME') }
123
+ end
124
+
125
+ context 'with --help' do
126
+ before(:each){ @arguments = ['--help'] }
127
+ it_should_behave_like 'a global help page'
128
+
129
+ context 'without a config file' do
130
+ before{ RHC::Wizard.stub(:has_configuration?).and_return(false) }
131
+ it_should_behave_like 'a global help page'
132
+ end
133
+ end
134
+
135
+ context 'with -h' do
136
+ before(:each){ @arguments = ['-h'] }
137
+ it_should_behave_like 'a global help page'
138
+ end
139
+
140
+ context 'with help' do
141
+ before(:each){ @arguments = ['help'] }
142
+ it_should_behave_like 'a global help page'
143
+ end
144
+
145
+ context 'with help options' do
146
+ before(:each){ @arguments = ['help', 'options'] }
147
+ it_should_behave_like 'a command-line options help page'
148
+ end
149
+ end
150
+
151
+ describe 'option provided twice' do
152
+ before{ user_config }
153
+ let!(:rest_client){ MockRestClient.new }
154
+ before(:each) do
155
+ domain = rest_client.add_domain("mock_domain")
156
+ @app = domain.add_application("app1", "mock_type")
157
+ end
158
+ context 'when run with -a provided twice, last being the valid one' do
159
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '--confirm', '--trace','-a', 'app2', '-a', 'app1', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password'] }
160
+ it "should remove cartridge" do
161
+ @app.add_cartridge('mock_cart-1')
162
+ expect { run }.to exit_with_code(0)
163
+ end
164
+ end
165
+ context 'when run with -a provided twice, last not being the valid one' do
166
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '--confirm', '--trace','-a', 'app1', '-a', 'app2', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password'] }
167
+ it "should raise an application not found exception" do
168
+ expect{ run }.to raise_error(RHC::Rest::ApplicationNotFoundException)
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '#set_terminal' do
174
+ before(:each) { mock_terminal }
175
+ it('should update $terminal.wrap_at') do
176
+ $stdout.should_receive(:tty?).twice.and_return(true)
177
+ HighLine::SystemExtensions.should_receive(:terminal_size).and_return([5])
178
+ expect { RHC::CLI.set_terminal }.to change($terminal, :wrap_at)
179
+ end
180
+ it('should not update $terminal.page_at') do
181
+ $stdout.should_receive(:tty?).twice.and_return(true)
182
+ expect { RHC::CLI.set_terminal }.to_not change($terminal, :page_at)
183
+ end
184
+ end
185
+
186
+ end