startapp 0.1.6

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 (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