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,665 @@
1
+ require 'spec_helper'
2
+ require 'rest_spec_helper'
3
+ require 'rhc/commands/cartridge'
4
+ require 'rhc/config'
5
+
6
+ describe RHC::Commands::Cartridge do
7
+
8
+ def exit_with_code_and_message(code, message = nil)
9
+ run_output.should match(message) if message
10
+ expect{ run }.to exit_with_code(code)
11
+ end
12
+
13
+ def succeed_with_message(message = "done")
14
+ exit_with_code_and_message(0,message)
15
+ end
16
+
17
+ def fail_with_message(message,code = 1)
18
+ exit_with_code_and_message(code, message)
19
+ end
20
+
21
+ def fail_with_code(code = 1)
22
+ exit_with_code_and_message(code)
23
+ end
24
+
25
+ before{ user_config }
26
+
27
+ describe 'run' do
28
+ let!(:rest_client){ MockRestClient.new }
29
+ context "with all arguments" do
30
+ let(:arguments) { ['cartridges', '--trace'] }
31
+ it { succeed_with_message /mock_cart-1.*mock_cart-2.*unique_mock_cart-1/m }
32
+ end
33
+ context "without password" do
34
+ let(:arguments) { ['cartridges', '--trace'] }
35
+ it { succeed_with_message /mock_cart-1.*mock_cart-2.*unique_mock_cart-1/m }
36
+ end
37
+ end
38
+
39
+ describe 'cartridge list' do
40
+ let(:arguments){ ['cartridge', 'list'] }
41
+ let(:username){ nil }
42
+ let(:password){ nil }
43
+ let(:server){ mock_uri }
44
+ let(:user_auth){ false }
45
+
46
+ context 'with valid carts' do
47
+ before{ stub_api; stub_simple_carts }
48
+
49
+ it{ run_output.should match /mock_standalone_cart\-1\s+Mock1 Cart\s+web/ }
50
+ it{ run_output.should match /mock_standalone_cart\-2\s+web/ }
51
+ it{ run_output.should match /mock_embedded_cart\-1\s+Mock1 Embedded Cart\s+addon/ }
52
+ it{ run_output.should match /premium_cart\-1 \(\*\)\s+Premium Cart\s+web/ }
53
+ it{ expect{ run }.to exit_with_code(0) }
54
+
55
+ context 'with verbose list' do
56
+ let(:arguments){ ['cartridge', 'list', '--verbose', '--trace'] }
57
+ it{ run_output.should match /Mock1 Cart.*\[mock_standalone_cart\-1\] \(web\)/ }
58
+ it{ run_output.should match /mock_standalone_cart\-2 \(web\)/ }
59
+ it{ run_output.should match "Mock2 description\n\n" }
60
+ it{ run_output.should match "Tagged with: scheduled" }
61
+ it{ run_output.should_not match("Tagged with: cartridge") }
62
+ it{ run_output.should match /Premium Cart.*\[premium_cart\-1\*\] \(web\)/ }
63
+ end
64
+ end
65
+ end
66
+
67
+ describe 'alias app cartridge' do
68
+ let!(:rest_client){ MockRestClient.new }
69
+ let(:arguments) { ['app', 'cartridge', 'list'] }
70
+
71
+ context 'when run' do
72
+ it { succeed_with_message /mock_cart-1.*mock_cart-2.*unique_mock_cart-1/m }
73
+ end
74
+ end
75
+
76
+ describe 'cartridge add' do
77
+ let!(:rest_client){ MockRestClient.new }
78
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1', '--app', 'app1'] }
79
+
80
+ context 'when run' do
81
+ before do
82
+ domain = rest_client.add_domain("mock_domain")
83
+ app = domain.add_application("app1", "mock_type")
84
+ end
85
+ it { succeed_with_message /Adding mock_cart-1 to application 'app1' \.\.\. / }
86
+ it { succeed_with_message /Connection URL:\s+http\:\/\/fake\.url/ }
87
+ it { succeed_with_message /Prop1:\s+value1/ }
88
+ it { succeed_with_message /Cartridge added with properties/ }
89
+ it "should not contain env var info" do
90
+ run_output.should_not match(/Environment Variables/)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe 'cartridge add' do
96
+ let!(:rest_client){ MockRestClient.new }
97
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1', '--app', 'app1', '--gear-size', 'small'] }
98
+
99
+ context 'with gear size' do
100
+ before do
101
+ domain = rest_client.add_domain("mock_domain")
102
+ app = domain.add_application("app1", "mock_type", true)
103
+ end
104
+ it { succeed_with_message /Adding mock_cart-1 to application 'app1' \.\.\. / }
105
+ it { succeed_with_message /Connection URL:\s+http\:\/\/fake\.url/ }
106
+ it { succeed_with_message /Prop1:\s+value1/ }
107
+ it { succeed_with_message /Cartridge added with properties/ }
108
+ it "should not contain env var info" do
109
+ run_output.should_not match(/Environment Variables/)
110
+ end
111
+ it { succeed_with_message /Gears:\s+1 small/ }
112
+ end
113
+
114
+ context 'with gear size on unsupported server' do
115
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1', '--app', 'app1', '--gear-size', 'small'] }
116
+ before do
117
+ domain = rest_client.add_domain("mock_domain")
118
+ app = domain.add_application("app1", "mock_type", true)
119
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','environment_variables').and_return(true)
120
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','gear_size').and_return(false)
121
+ end
122
+ it { expect { run }.to exit_with_code(0) }
123
+ it { run_output.should match(/Server does not support gear sizes for cartridges/) }
124
+ end
125
+ end
126
+
127
+ describe 'cartridge add' do
128
+ let!(:rest_client){ MockRestClient.new }
129
+ let(:instance) do
130
+ domain = rest_client.add_domain("mock_domain")
131
+ @app = domain.add_application("app1", "mock_type")
132
+ instance = RHC::Commands::Cartridge.new
133
+ RHC::Commands::Cartridge.stub(:new) { instance }
134
+ instance
135
+ end
136
+
137
+ context 'with app context' do
138
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1'] }
139
+ before do
140
+ instance.stub(:git_config_get) { |key| @app.id if key == "rhc.app-id" }
141
+ end
142
+ it{ succeed_with_message }
143
+ end
144
+
145
+ context 'with named app context' do
146
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1'] }
147
+ before do
148
+ instance.stub(:git_config_get) { |key| @app.name if key == "rhc.app-name" }
149
+ end
150
+ it{ succeed_with_message }
151
+ end
152
+
153
+ context 'without app context' do
154
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1'] }
155
+ before do
156
+ instance.should_receive(:git_config_get).with('rhc.domain-name').and_return(nil)
157
+ instance.should_receive(:git_config_get).with('rhc.app-name').and_return(nil)
158
+ instance.should_receive(:git_config_get).with('rhc.app-id').and_return('')
159
+ end
160
+ it{ fail_with_code }
161
+ end
162
+ context 'with unrecognized app context' do
163
+ let(:arguments) { ['cartridge', 'add', 'mock_cart-1'] }
164
+ before do
165
+ instance.should_receive(:git_config_get).with('rhc.domain-name').and_return(nil)
166
+ instance.should_receive(:git_config_get).with('rhc.app-name').and_return(nil)
167
+ instance.should_receive(:git_config_get).with('rhc.app-id').and_return('find')
168
+ end
169
+ it{ fail_with_code(101) }
170
+ end
171
+ end
172
+
173
+ describe 'cartridge add' do
174
+ let!(:rest_client){ MockRestClient.new }
175
+
176
+ context 'when invoked through an alias' do
177
+ let(:arguments) { ['app', 'cartridge', 'add', 'unique_mock_cart', '--app', 'app1'] }
178
+ before do
179
+ domain = rest_client.add_domain("mock_domain")
180
+ app = domain.add_application("app1", "mock_type")
181
+ end
182
+ it {
183
+ succeed_with_message
184
+ }
185
+ end
186
+
187
+ context 'when cartridge with regex breaking name does not exist' do
188
+ let(:arguments) { ['cartridge', 'add', '*##', '--app', 'app1'] }
189
+ before do
190
+ domain = rest_client.add_domain("mock_domain")
191
+ app = domain.add_application("app1", "mock_type")
192
+ end
193
+ it{ fail_with_code 154 }
194
+ end
195
+
196
+ context 'when cartridge does not exist' do
197
+ let(:arguments) { ['cartridge', 'add', 'nomatch_cart', '--app', 'app1'] }
198
+ before do
199
+ domain = rest_client.add_domain("mock_domain")
200
+ app = domain.add_application("app1", "mock_type")
201
+ end
202
+ it{ fail_with_code 154 }
203
+ end
204
+
205
+ context 'when multiple carts match' do
206
+ let(:arguments) { ['cartridge', 'add', 'mock_cart', '-a', 'app1'] }
207
+ before do
208
+ domain = rest_client.add_domain("mock_domain")
209
+ app = domain.add_application("app1", "mock_type")
210
+ end
211
+ it {
212
+ fail_with_code 155
213
+ }
214
+ end
215
+
216
+ context 'when cart is premium' do
217
+ let(:arguments) { ['cartridge', 'add', 'premium_cart', '-a', 'app1'] }
218
+ before do
219
+ domain = rest_client.add_domain("mock_domain")
220
+ app = domain.add_application("app1", "mock_type")
221
+ end
222
+ it {
223
+ succeed_with_message /This gear costs an additional \$0\.05 per gear after the first 3 gears\./
224
+ }
225
+ end
226
+ end
227
+
228
+ describe 'cartridge remove' do
229
+ let!(:rest_client){ MockRestClient.new }
230
+
231
+ context 'when run with --noprompt and without --confirm' do
232
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '-a', 'app1', '--noprompt'] }
233
+ before do
234
+ domain = rest_client.add_domain("mock_domain")
235
+ app = domain.add_application("app1", "mock_type")
236
+ app.add_cartridge('mock_cart-1')
237
+ end
238
+
239
+ it{ fail_with_message "This action requires the --confirm option" }
240
+ end
241
+
242
+ context 'when run with confirmation' do
243
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '--confirm', '--trace', '-a', 'app1'] }
244
+ before do
245
+ domain = rest_client.add_domain("mock_domain")
246
+ @app = domain.add_application("app1", "mock_type")
247
+ end
248
+ it "should remove cartridge" do
249
+ @app.add_cartridge('mock_cart-1')
250
+ expect { run }.to exit_with_code(0)
251
+ # framework cart should be the only one listed
252
+ @app.cartridges.length.should == 1
253
+ end
254
+ it "should raise cartridge not found exception" do
255
+ expect { run }.to raise_error RHC::CartridgeNotFoundException
256
+ end
257
+ end
258
+
259
+ context 'when run with custom cart url' do
260
+ let(:arguments) { ['cartridge', 'remove', 'https://foo.bar.com', '--confirm', '-a', 'app1'] }
261
+ before do
262
+ @domain = rest_client.add_domain("mockdomain")
263
+ @app = @domain.add_application("app1", "mock_type")
264
+ cart1 = @app.add_cartridge('mock_cart-1')
265
+ cart1.url = 'https://foo.bar.com'
266
+ end
267
+ it "should remove cartridge" do
268
+ expect { run }.to exit_with_code(0)
269
+ # framework cart should be the only one listed
270
+ @app.cartridges.length.should == 1
271
+ end
272
+ end
273
+
274
+ context "against a 1.5 server" do
275
+ let!(:rest_client){ nil }
276
+ let(:username){ mock_user }
277
+ let(:password){ 'password' }
278
+ let(:server){ mock_uri }
279
+ let(:arguments){ ['remove-cartridge', 'jenkins-1', '-a', 'foo', '--confirm', '--trace'] }
280
+ before do
281
+ stub_api(false)
282
+ challenge{ stub_one_domain('test') }
283
+ stub_one_application('test', 'foo').with(:query => {:include => 'cartridges'})
284
+ stub_application_cartridges('test', 'foo', [{:name => 'php-5.3'}, {:name => 'jenkins-1'}])
285
+ end
286
+ before do
287
+ stub_api_request(:delete, "broker/rest/domains/test/applications/foo/cartridges/jenkins-1").
288
+ to_return({
289
+ :body => {
290
+ :type => nil,
291
+ :data => nil,
292
+ :messages => [
293
+ {:exit_code => 0, :field => nil, :severity => 'info', :text => 'Removed Jenkins'},
294
+ {:exit_code => 0, :field => nil, :severity => 'result', :text => 'Job URL changed'},
295
+ ]
296
+ }.to_json,
297
+ :status => 200
298
+ })
299
+ end
300
+
301
+ it("should not display info returned by the server"){ run_output.should_not match "Removed Jenkins" }
302
+ it("should display prefix returned by the server"){ run_output.should match "Removing jenkins-1" }
303
+ it("should display results returned by the server"){ run_output.should match "Job URL changed" }
304
+ it('should exit successfully'){ expect{ run }.to exit_with_code(0) }
305
+ end
306
+ end
307
+
308
+ describe 'cartridge status' do
309
+ let!(:rest_client){ MockRestClient.new }
310
+ let(:arguments) { ['cartridge', 'status', 'mock_cart-1', '-a', 'app1'] }
311
+
312
+ before do
313
+ @domain = rest_client.add_domain("mock_domain")
314
+ @app = @domain.add_application("app1", "mock_type")
315
+ @app.add_cartridge('mock_cart-1')
316
+ end
317
+
318
+ context 'when run' do
319
+ it { run_output.should match('started') }
320
+ end
321
+
322
+ context 'when run with cart stopped' do
323
+ before { @app.find_cartridge('mock_cart-1').stop }
324
+ it { run_output.should match('stopped') }
325
+ end
326
+ end
327
+
328
+ describe 'cartridge start' do
329
+ let!(:rest_client){ MockRestClient.new }
330
+ let(:arguments) { ['cartridge', 'start', 'mock_cart-1', '-a', 'app1'] }
331
+
332
+ context 'when run' do
333
+ before do
334
+ domain = rest_client.add_domain("mock_domain")
335
+ app = domain.add_application("app1", "mock_type")
336
+ app.add_cartridge('mock_cart-1')
337
+ end
338
+ it { run_output.should match(/Starting mock_cart-1 .*done/) }
339
+ end
340
+ end
341
+
342
+ describe 'cartridge stop' do
343
+ let!(:rest_client){ MockRestClient.new }
344
+ let(:arguments) { ['cartridge', 'stop', 'mock_cart-1', '-a', 'app1'] }
345
+
346
+ context 'when run' do
347
+ before do
348
+ domain = rest_client.add_domain("mock_domain")
349
+ app = domain.add_application("app1", "mock_type")
350
+ app.add_cartridge('mock_cart-1')
351
+ end
352
+ it { run_output.should match(/Stopping mock_cart-1 .*done/) }
353
+ end
354
+ end
355
+
356
+ describe 'cartridge restart' do
357
+ let!(:rest_client){ MockRestClient.new }
358
+ let(:arguments) { ['cartridge', 'restart', 'mock_cart-1', '-a', 'app1'] }
359
+
360
+ context 'when run' do
361
+ before do
362
+ domain = rest_client.add_domain("mock_domain")
363
+ app = domain.add_application("app1", "mock_type")
364
+ app.add_cartridge('mock_cart-1')
365
+ end
366
+ it { run_output.should match(/Restarting mock_cart-1 .*done/) }
367
+ end
368
+ end
369
+
370
+ describe 'cartridge reload' do
371
+ let!(:rest_client){ MockRestClient.new }
372
+ let(:arguments) { ['cartridge', 'reload', 'mock_cart-1', '-a', 'app1'] }
373
+
374
+ context 'when run' do
375
+ before do
376
+ domain = rest_client.add_domain("mock_domain")
377
+ app = domain.add_application("app1", "mock_type")
378
+ app.add_cartridge('mock_cart-1')
379
+ end
380
+ it { run_output.should match(/Reloading mock_cart-1 .*done/) }
381
+ end
382
+ end
383
+
384
+ describe 'cartridge show' do
385
+ let!(:rest_client){ MockRestClient.new }
386
+ let(:arguments) { ['cartridge', 'show', 'mock_cart-1', '-a', 'app1'] }
387
+
388
+ before do
389
+ domain = rest_client.add_domain("mock_domain")
390
+ app = domain.add_application("app1", "mock_type")
391
+ app.add_cartridge('mock_cart-1')
392
+ end
393
+
394
+ context 'when run with exactly the same case as how cartridge was created' do
395
+ it { run_output.should match('Connection URL: http://fake.url') }
396
+ it { run_output.should match(/Prop1:\s+value1/) }
397
+ end
398
+ end
399
+
400
+ describe 'cartridge show' do
401
+ let(:arguments) { ['cartridge', 'show', 'Mock_Cart-1', '-a', 'app1'] }
402
+
403
+ before do
404
+ @rc = MockRestClient.new
405
+ domain = @rc.add_domain("mock_domain")
406
+ app = domain.add_application("app1", "mock_type")
407
+ app.add_cartridge('mock_cart-1')
408
+ end
409
+
410
+ context 'when run with different case from how cartrige was created' do
411
+ it { run_output.should match('Connection URL: http://fake.url') }
412
+ it { run_output.should match(/Prop1:\s+value1/) }
413
+ end
414
+ end
415
+
416
+ describe 'cartridge show' do
417
+ let(:arguments) { ['cartridge', 'show', 'premium_cart', '-a', 'app1'] }
418
+
419
+ before do
420
+ @rc = MockRestClient.new
421
+ domain = @rc.add_domain("mock_domain")
422
+ app = domain.add_application("app1", "mock_type")
423
+ app.cartridges << @rc.cartridges.find {|c| c.name == 'premium_cart'}
424
+ end
425
+
426
+ context 'when run with a premium cartridge' do
427
+ it { run_output.should match(/This gear costs an additional \$0\.05 per gear after the first 3 gears./) }
428
+ end
429
+ end
430
+
431
+ describe 'cartridge show scaled' do
432
+ let!(:rest_client){ MockRestClient.new }
433
+ let(:arguments) { ['cartridge', 'show', 'mock_type', '-a', 'app1'] }
434
+
435
+ context 'when run' do
436
+ before do
437
+ domain = rest_client.add_domain("mock_domain")
438
+ app = domain.add_application("app1", "mock_type", true)
439
+ end
440
+ it { run_output.should match(/Scaling: .*x2 \(minimum/) }
441
+ it { run_output.should match('minimum: 2') }
442
+ it { run_output.should match('maximum: available') }
443
+ end
444
+ end
445
+
446
+ describe 'cartridge scale' do
447
+ let!(:rest_client){ MockRestClient.new }
448
+ let(:arguments) { ['cartridge', 'scale', @cart_type || 'mock_type', '-a', 'app1'] | (@extra_args || []) }
449
+
450
+ let(:current_scale) { 1 }
451
+ before do
452
+ domain = rest_client.add_domain("mock_domain")
453
+ @app = domain.add_application("app1", "mock_type", scalable)
454
+ @app.cartridges.first.stub(:current_scale).and_return(current_scale)
455
+ end
456
+
457
+ context 'when run with scalable app' do
458
+ let(:scalable){ true }
459
+
460
+ it "with no values" do
461
+ fail_with_message "Must provide either a min or max"
462
+ end
463
+
464
+ it "with a min value" do
465
+ @extra_args = ["--min","6"]
466
+ succeed_with_message "minimum: 6"
467
+ end
468
+
469
+ it "with an explicit value" do
470
+ @extra_args = ["6"]
471
+ succeed_with_message "minimum: 6, maximum: 6"
472
+ end
473
+
474
+ it "with an invalid explicit value" do
475
+ @extra_args = ["a6"]
476
+ fail_with_message "Multiplier must be a positive integer"
477
+ end
478
+
479
+ it "with an explicit value and a different minimum" do
480
+ @extra_args = ["6", "--min", "5"]
481
+ succeed_with_message "minimum: 5, maximum: 6"
482
+ end
483
+
484
+ it "with a max value" do
485
+ @extra_args = ["--max","3"]
486
+ succeed_with_message 'maximum: 3'
487
+ end
488
+
489
+ it "with an invalid min value" do
490
+ @extra_args = ["--min","a"]
491
+ fail_with_message "invalid argument: --min"
492
+ end
493
+
494
+ it "with an invalid max value" do
495
+ @extra_args = ["--max","a"]
496
+ fail_with_message "invalid argument: --max"
497
+ end
498
+
499
+ context "when the operation times out" do
500
+ before{ @app.cartridges.first.should_receive(:set_scales).twice.and_raise(RHC::Rest::TimeoutException.new('Timeout', HTTPClient::ReceiveTimeoutError.new)) }
501
+ it "displays an error" do
502
+ @extra_args = ["--min","2"]
503
+ fail_with_message "The server has closed the connection, but your scaling operation is still in progress"
504
+ end
505
+ end
506
+ end
507
+
508
+ context 'when run with a nonscalable app' do
509
+ let(:scalable){ false }
510
+
511
+ it "with a min value" do
512
+ @extra_args = ["--min","6"]
513
+ fail_with_message "Cartridge is not scalable"
514
+ end
515
+ end
516
+ end
517
+
518
+ describe 'cartridge storage' do
519
+ let!(:rest_client){ MockRestClient.new(RHC::Config, 1.3) }
520
+ let(:cmd_base) { ['cartridge', 'storage'] }
521
+ let(:std_args) { ['-a', 'app1'] | (@extra_args || []) }
522
+ let(:cart_type) { ['mock_cart-1'] }
523
+
524
+ before do
525
+ domain = rest_client.add_domain("mock_domain")
526
+ app = domain.add_application("app1", "mock_type", false)
527
+ app.add_cartridge('mock_cart-1', true)
528
+ end
529
+
530
+ context 'when run with no arguments' do
531
+ let(:arguments) { cmd_base | std_args }
532
+ it ("should show the mock_type"){ run_output.should match('mock_type') }
533
+ it ('should show mock_cart-1'){ run_output.should match('mock_cart-1') }
534
+ end
535
+
536
+ context 'when run for a non-existent cartridge' do
537
+ let(:arguments) { cmd_base | ['bogus_cart'] | std_args }
538
+ it { fail_with_message("There are no cartridges that match 'bogus_cart'.", 154) }
539
+ end
540
+
541
+ context 'when run with -c flag' do
542
+ let(:arguments) { cmd_base | ['-c', 'mock_cart-1'] | std_args}
543
+ it "should show storage info for the indicated app and cart" do
544
+ run_output.should match('mock_cart-1')
545
+ run_output.should_not match('mock_type')
546
+ end
547
+
548
+ it "should set storage for the indicated app and cart" do
549
+ @extra_args = ["--set", "6GB"]
550
+ run_output.should match('6GB')
551
+ end
552
+ end
553
+
554
+ context 'when run with valid arguments' do
555
+ let(:arguments) { cmd_base | cart_type | std_args }
556
+ it "should show storage info for the indicated app and cart" do
557
+ @extra_args = ["--show"]
558
+ run_output.should match('mock_cart-1')
559
+ run_output.should_not match('mock_type')
560
+ end
561
+ it "should add storage for the indicated app and cart" do
562
+ @extra_args = ["--add", "5GB"]
563
+ run_output.should match('10GB')
564
+ end
565
+ it "should remove storage for the indicated app and cart" do
566
+ @extra_args = ["--remove", "5GB"]
567
+ run_output.should match('None')
568
+ end
569
+ it "should warn when told to remove more storage than the indicated app and cart have" do
570
+ @extra_args = ["--remove", "70GB"]
571
+ fail_with_message('The amount of additional storage to be removed exceeds the total amount in use')
572
+ end
573
+ it "should not warn when told to remove more storage than the indicated app and cart have when forced" do
574
+ @extra_args = ["--remove", "70GB", "--force"]
575
+ run_output.should match('None')
576
+ end
577
+ it "should set storage for the indicated app and cart" do
578
+ @extra_args = ["--set", "6GB"]
579
+ run_output.should match('6GB')
580
+ end
581
+ it "should work correctly with a bare number value" do
582
+ @extra_args = ["--set", "6"]
583
+ run_output.should match('6GB')
584
+ end
585
+ end
586
+
587
+ context 'when run with invalid arguments' do
588
+ let(:arguments) { cmd_base | cart_type | std_args }
589
+ it "should raise an error when multiple storage operations are provided" do
590
+ @extra_args = ["--show", "--add", "5GB"]
591
+ fail_with_message('Only one storage action can be performed at a time')
592
+ end
593
+ it "should raise an error when the storage amount is not provided" do
594
+ @extra_args = ["--set"]
595
+ fail_with_message('missing argument')
596
+ end
597
+ it "should raise an error when the storage amount is invalid" do
598
+ @extra_args = ["--set", "5ZB"]
599
+ fail_with_message("The amount format must be a number, optionally followed by 'GB'")
600
+ end
601
+ end
602
+
603
+ context 'when run against an outdated broker' do
604
+ before { rest_client.stub(:api_version_negotiated).and_return(1.2) }
605
+ let(:arguments) { cmd_base | cart_type | std_args }
606
+
607
+ it 'adding storage should raise a version error' do
608
+ @extra_args = ["--add", "1GB"]
609
+ fail_with_message('The server does not support this command \(requires 1.3, found 1.2\).')
610
+ end
611
+
612
+ end
613
+ end
614
+
615
+ describe 'cartridge add with env vars' do
616
+ let!(:rest_client){ MockRestClient.new }
617
+ before do
618
+ domain = rest_client.add_domain("mock_domain")
619
+ @app = domain.add_application("app1", "mock_type")
620
+ end
621
+
622
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO=BAR', '--app', 'app1'],
623
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO=BAR', '--app', 'app1']
624
+ ].each_with_index do |args, i|
625
+ context "when run with single env var #{i}" do
626
+ let(:arguments) { args }
627
+ it { succeed_with_message(/Environment Variables:\s+FOO=BAR/) }
628
+ end
629
+ end
630
+
631
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO1=BAR1', '-e', 'FOO2=BAR2', '--app', 'app1'],
632
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO1=BAR1', '--env', 'FOO2=BAR2', '--app', 'app1']
633
+ ].each_with_index do |args, i|
634
+ context "when run with multiple env vars #{i}" do
635
+ let(:arguments) { args }
636
+ it { succeed_with_message(/Environment Variables:\s+FOO1=BAR1, FOO2=BAR2/) }
637
+ end
638
+ end
639
+
640
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', File.expand_path('../../assets/env_vars.txt', __FILE__), '--app', 'app1'],
641
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', File.expand_path('../../assets/env_vars.txt', __FILE__), '--app', 'app1']
642
+ ].each_with_index do |args, i|
643
+ context "when run with env vars from files #{i}" do
644
+ let(:arguments) { args }
645
+ it { succeed_with_message(/Environment Variables:\s+BAR=456, FOO=123, MY_EMPTY_ENV_VAR=, MY_OPENSHIFT_ENV_VAR=mongodb:\/\/user:pass@host:port\/\n/) }
646
+ end
647
+ end
648
+
649
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO=BAR', '--app', 'app1', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password'],
650
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO=BAR', '--app', 'app1', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password']
651
+ ].each_with_index do |args, i|
652
+ context "when run against a server without env vars support #{i}" do
653
+ let(:arguments) { args }
654
+ before do
655
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','environment_variables').and_return(false)
656
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','gear_size').and_return(true)
657
+ end
658
+ it { expect { run }.to exit_with_code(0) }
659
+ it { run_output.should match(/Server does not support environment variables/) }
660
+ it { run_output.should_not match(/Environment Variables:\s+FOO=BAR/) }
661
+ end
662
+ end
663
+
664
+ end
665
+ end