pbox 1.17.2

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +40 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/pbox_bash +1639 -0
  7. data/bin/pbox +37 -0
  8. data/conf/protonbox.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +178 -0
  11. data/features/deployments_feature.rb +127 -0
  12. data/features/domains_feature.rb +49 -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 +186 -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 +701 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +96 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +326 -0
  31. data/lib/rhc/commands/deployment.rb +82 -0
  32. data/lib/rhc/commands/domain.rb +167 -0
  33. data/lib/rhc/commands/env.rb +142 -0
  34. data/lib/rhc/commands/git_clone.rb +29 -0
  35. data/lib/rhc/commands/logout.rb +51 -0
  36. data/lib/rhc/commands/member.rb +148 -0
  37. data/lib/rhc/commands/port_forward.rb +197 -0
  38. data/lib/rhc/commands/server.rb +40 -0
  39. data/lib/rhc/commands/setup.rb +60 -0
  40. data/lib/rhc/commands/snapshot.rb +137 -0
  41. data/lib/rhc/commands/ssh.rb +51 -0
  42. data/lib/rhc/commands/sshkey.rb +97 -0
  43. data/lib/rhc/commands/tail.rb +47 -0
  44. data/lib/rhc/commands/threaddump.rb +14 -0
  45. data/lib/rhc/commands.rb +396 -0
  46. data/lib/rhc/config.rb +320 -0
  47. data/lib/rhc/context_helper.rb +121 -0
  48. data/lib/rhc/core_ext.rb +202 -0
  49. data/lib/rhc/coverage_helper.rb +33 -0
  50. data/lib/rhc/deployment_helpers.rb +88 -0
  51. data/lib/rhc/exceptions.rb +232 -0
  52. data/lib/rhc/git_helpers.rb +91 -0
  53. data/lib/rhc/help_formatter.rb +55 -0
  54. data/lib/rhc/helpers.rb +477 -0
  55. data/lib/rhc/highline_extensions.rb +479 -0
  56. data/lib/rhc/json.rb +51 -0
  57. data/lib/rhc/output_helpers.rb +260 -0
  58. data/lib/rhc/rest/activation.rb +11 -0
  59. data/lib/rhc/rest/alias.rb +42 -0
  60. data/lib/rhc/rest/api.rb +87 -0
  61. data/lib/rhc/rest/application.rb +332 -0
  62. data/lib/rhc/rest/attributes.rb +36 -0
  63. data/lib/rhc/rest/authorization.rb +8 -0
  64. data/lib/rhc/rest/base.rb +79 -0
  65. data/lib/rhc/rest/cartridge.rb +154 -0
  66. data/lib/rhc/rest/client.rb +650 -0
  67. data/lib/rhc/rest/deployment.rb +18 -0
  68. data/lib/rhc/rest/domain.rb +98 -0
  69. data/lib/rhc/rest/environment_variable.rb +15 -0
  70. data/lib/rhc/rest/gear_group.rb +16 -0
  71. data/lib/rhc/rest/httpclient.rb +145 -0
  72. data/lib/rhc/rest/key.rb +44 -0
  73. data/lib/rhc/rest/membership.rb +105 -0
  74. data/lib/rhc/rest/mock.rb +1024 -0
  75. data/lib/rhc/rest/user.rb +32 -0
  76. data/lib/rhc/rest.rb +148 -0
  77. data/lib/rhc/ssh_helpers.rb +378 -0
  78. data/lib/rhc/tar_gz.rb +51 -0
  79. data/lib/rhc/usage_templates/command_help.erb +51 -0
  80. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  81. data/lib/rhc/usage_templates/help.erb +35 -0
  82. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  83. data/lib/rhc/usage_templates/options_help.erb +12 -0
  84. data/lib/rhc/vendor/okjson.rb +600 -0
  85. data/lib/rhc/vendor/parseconfig.rb +178 -0
  86. data/lib/rhc/vendor/sshkey.rb +253 -0
  87. data/lib/rhc/vendor/zliby.rb +628 -0
  88. data/lib/rhc/version.rb +5 -0
  89. data/lib/rhc/wizard.rb +633 -0
  90. data/lib/rhc.rb +34 -0
  91. data/spec/coverage_helper.rb +89 -0
  92. data/spec/direct_execution_helper.rb +338 -0
  93. data/spec/keys/example.pem +23 -0
  94. data/spec/keys/example_private.pem +27 -0
  95. data/spec/keys/server.pem +19 -0
  96. data/spec/rest_spec_helper.rb +31 -0
  97. data/spec/rhc/assets/cert.crt +22 -0
  98. data/spec/rhc/assets/cert_key_rsa +27 -0
  99. data/spec/rhc/assets/empty.txt +0 -0
  100. data/spec/rhc/assets/env_vars.txt +7 -0
  101. data/spec/rhc/assets/env_vars_2.txt +1 -0
  102. data/spec/rhc/assets/foo.txt +1 -0
  103. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  104. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  105. data/spec/rhc/auth_spec.rb +442 -0
  106. data/spec/rhc/cli_spec.rb +188 -0
  107. data/spec/rhc/command_spec.rb +435 -0
  108. data/spec/rhc/commands/account_spec.rb +42 -0
  109. data/spec/rhc/commands/alias_spec.rb +333 -0
  110. data/spec/rhc/commands/app_spec.rb +754 -0
  111. data/spec/rhc/commands/apps_spec.rb +39 -0
  112. data/spec/rhc/commands/authorization_spec.rb +145 -0
  113. data/spec/rhc/commands/cartridge_spec.rb +641 -0
  114. data/spec/rhc/commands/deployment_spec.rb +286 -0
  115. data/spec/rhc/commands/domain_spec.rb +383 -0
  116. data/spec/rhc/commands/env_spec.rb +493 -0
  117. data/spec/rhc/commands/git_clone_spec.rb +80 -0
  118. data/spec/rhc/commands/logout_spec.rb +86 -0
  119. data/spec/rhc/commands/member_spec.rb +228 -0
  120. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  121. data/spec/rhc/commands/server_spec.rb +69 -0
  122. data/spec/rhc/commands/setup_spec.rb +118 -0
  123. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  124. data/spec/rhc/commands/ssh_spec.rb +163 -0
  125. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  126. data/spec/rhc/commands/tail_spec.rb +81 -0
  127. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  128. data/spec/rhc/config_spec.rb +407 -0
  129. data/spec/rhc/helpers_spec.rb +524 -0
  130. data/spec/rhc/highline_extensions_spec.rb +314 -0
  131. data/spec/rhc/json_spec.rb +30 -0
  132. data/spec/rhc/rest_application_spec.rb +248 -0
  133. data/spec/rhc/rest_client_spec.rb +752 -0
  134. data/spec/rhc/rest_spec.rb +740 -0
  135. data/spec/rhc/targz_spec.rb +55 -0
  136. data/spec/rhc/wizard_spec.rb +756 -0
  137. data/spec/spec_helper.rb +575 -0
  138. data/spec/wizard_spec_helper.rb +330 -0
  139. metadata +435 -0
@@ -0,0 +1,641 @@
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 == "pbox.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 == "pbox.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('pbox.domain-name').and_return(nil)
157
+ instance.should_receive(:git_config_get).with('pbox.app-name').and_return(nil)
158
+ instance.should_receive(:git_config_get).with('pbox.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('pbox.domain-name').and_return(nil)
166
+ instance.should_receive(:git_config_get).with('pbox.app-name').and_return(nil)
167
+ instance.should_receive(:git_config_get).with('pbox.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 does not exist' do
188
+ let(:arguments) { ['cartridge', 'add', 'nomatch_cart', '--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 multiple carts match' do
197
+ let(:arguments) { ['cartridge', 'add', 'mock_cart', '-a', 'app1'] }
198
+ before do
199
+ domain = rest_client.add_domain("mock_domain")
200
+ app = domain.add_application("app1", "mock_type")
201
+ end
202
+ it {
203
+ fail_with_code 155
204
+ }
205
+ end
206
+
207
+ context 'when cart is premium' do
208
+ let(:arguments) { ['cartridge', 'add', 'premium_cart', '-a', 'app1'] }
209
+ before do
210
+ domain = rest_client.add_domain("mock_domain")
211
+ app = domain.add_application("app1", "mock_type")
212
+ end
213
+ it {
214
+ succeed_with_message /This gear costs an additional \$0\.05 per gear after the first 3 gears\./
215
+ }
216
+ end
217
+ end
218
+
219
+ describe 'cartridge remove' do
220
+ let!(:rest_client){ MockRestClient.new }
221
+
222
+ context 'when run with --noprompt and without --confirm' do
223
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '-a', 'app1', '--noprompt'] }
224
+ before do
225
+ domain = rest_client.add_domain("mock_domain")
226
+ app = domain.add_application("app1", "mock_type")
227
+ app.add_cartridge('mock_cart-1')
228
+ end
229
+
230
+ it{ fail_with_message "This action requires the --confirm option" }
231
+ end
232
+
233
+ context 'when run with confirmation' do
234
+ let(:arguments) { ['cartridge', 'remove', 'mock_cart-1', '--confirm', '--trace', '-a', 'app1'] }
235
+ before do
236
+ domain = rest_client.add_domain("mock_domain")
237
+ @app = domain.add_application("app1", "mock_type")
238
+ end
239
+ it "should remove cartridge" do
240
+ @app.add_cartridge('mock_cart-1')
241
+ expect { run }.to exit_with_code(0)
242
+ # framework cart should be the only one listed
243
+ @app.cartridges.length.should == 1
244
+ end
245
+ it "should raise cartridge not found exception" do
246
+ expect { run }.to raise_error RHC::CartridgeNotFoundException
247
+ end
248
+ end
249
+
250
+ context "against a 1.5 server" do
251
+ let!(:rest_client){ nil }
252
+ let(:username){ mock_user }
253
+ let(:password){ 'password' }
254
+ let(:server){ mock_uri }
255
+ let(:arguments){ ['remove-cartridge', 'jenkins-1', '-a', 'foo', '--confirm', '--trace'] }
256
+ before do
257
+ stub_api(false)
258
+ challenge{ stub_one_domain('test') }
259
+ stub_one_application('test', 'foo').with(:query => {:include => 'cartridges'})
260
+ stub_application_cartridges('test', 'foo', [{:name => 'php-5.3'}, {:name => 'jenkins-1'}])
261
+ end
262
+ before do
263
+ stub_api_request(:delete, "broker/rest/domains/test/applications/foo/cartridges/jenkins-1").
264
+ to_return({
265
+ :body => {
266
+ :type => nil,
267
+ :data => nil,
268
+ :messages => [
269
+ {:exit_code => 0, :field => nil, :severity => 'info', :text => 'Removed Jenkins'},
270
+ {:exit_code => 0, :field => nil, :severity => 'result', :text => 'Job URL changed'},
271
+ ]
272
+ }.to_json,
273
+ :status => 200
274
+ })
275
+ end
276
+
277
+ it("should not display info returned by the server"){ run_output.should_not match "Removed Jenkins" }
278
+ it("should display prefix returned by the server"){ run_output.should match "Removing jenkins-1" }
279
+ it("should display results returned by the server"){ run_output.should match "Job URL changed" }
280
+ it('should exit successfully'){ expect{ run }.to exit_with_code(0) }
281
+ end
282
+ end
283
+
284
+ describe 'cartridge status' do
285
+ let!(:rest_client){ MockRestClient.new }
286
+ let(:arguments) { ['cartridge', 'status', 'mock_cart-1', '-a', 'app1'] }
287
+
288
+ before do
289
+ @domain = rest_client.add_domain("mock_domain")
290
+ @app = @domain.add_application("app1", "mock_type")
291
+ @app.add_cartridge('mock_cart-1')
292
+ end
293
+
294
+ context 'when run' do
295
+ it { run_output.should match('started') }
296
+ end
297
+
298
+ context 'when run with cart stopped' do
299
+ before { @app.find_cartridge('mock_cart-1').stop }
300
+ it { run_output.should match('stopped') }
301
+ end
302
+ end
303
+
304
+ describe 'cartridge start' do
305
+ let!(:rest_client){ MockRestClient.new }
306
+ let(:arguments) { ['cartridge', 'start', 'mock_cart-1', '-a', 'app1'] }
307
+
308
+ context 'when run' do
309
+ before do
310
+ domain = rest_client.add_domain("mock_domain")
311
+ app = domain.add_application("app1", "mock_type")
312
+ app.add_cartridge('mock_cart-1')
313
+ end
314
+ it { run_output.should match(/Starting mock_cart-1 .*done/) }
315
+ end
316
+ end
317
+
318
+ describe 'cartridge stop' do
319
+ let!(:rest_client){ MockRestClient.new }
320
+ let(:arguments) { ['cartridge', 'stop', 'mock_cart-1', '-a', 'app1'] }
321
+
322
+ context 'when run' do
323
+ before do
324
+ domain = rest_client.add_domain("mock_domain")
325
+ app = domain.add_application("app1", "mock_type")
326
+ app.add_cartridge('mock_cart-1')
327
+ end
328
+ it { run_output.should match(/Stopping mock_cart-1 .*done/) }
329
+ end
330
+ end
331
+
332
+ describe 'cartridge restart' do
333
+ let!(:rest_client){ MockRestClient.new }
334
+ let(:arguments) { ['cartridge', 'restart', 'mock_cart-1', '-a', 'app1'] }
335
+
336
+ context 'when run' do
337
+ before do
338
+ domain = rest_client.add_domain("mock_domain")
339
+ app = domain.add_application("app1", "mock_type")
340
+ app.add_cartridge('mock_cart-1')
341
+ end
342
+ it { run_output.should match(/Restarting mock_cart-1 .*done/) }
343
+ end
344
+ end
345
+
346
+ describe 'cartridge reload' do
347
+ let!(:rest_client){ MockRestClient.new }
348
+ let(:arguments) { ['cartridge', 'reload', 'mock_cart-1', '-a', 'app1'] }
349
+
350
+ context 'when run' do
351
+ before do
352
+ domain = rest_client.add_domain("mock_domain")
353
+ app = domain.add_application("app1", "mock_type")
354
+ app.add_cartridge('mock_cart-1')
355
+ end
356
+ it { run_output.should match(/Reloading mock_cart-1 .*done/) }
357
+ end
358
+ end
359
+
360
+ describe 'cartridge show' do
361
+ let!(:rest_client){ MockRestClient.new }
362
+ let(:arguments) { ['cartridge', 'show', 'mock_cart-1', '-a', 'app1'] }
363
+
364
+ before do
365
+ domain = rest_client.add_domain("mock_domain")
366
+ app = domain.add_application("app1", "mock_type")
367
+ app.add_cartridge('mock_cart-1')
368
+ end
369
+
370
+ context 'when run with exactly the same case as how cartridge was created' do
371
+ it { run_output.should match('Connection URL: http://fake.url') }
372
+ it { run_output.should match(/Prop1:\s+value1/) }
373
+ end
374
+ end
375
+
376
+ describe 'cartridge show' do
377
+ let(:arguments) { ['cartridge', 'show', 'Mock_Cart-1', '-a', 'app1'] }
378
+
379
+ before do
380
+ @rc = MockRestClient.new
381
+ domain = @rc.add_domain("mock_domain")
382
+ app = domain.add_application("app1", "mock_type")
383
+ app.add_cartridge('mock_cart-1')
384
+ end
385
+
386
+ context 'when run with different case from how cartrige was created' do
387
+ it { run_output.should match('Connection URL: http://fake.url') }
388
+ it { run_output.should match(/Prop1:\s+value1/) }
389
+ end
390
+ end
391
+
392
+ describe 'cartridge show' do
393
+ let(:arguments) { ['cartridge', 'show', 'premium_cart', '-a', 'app1'] }
394
+
395
+ before do
396
+ @rc = MockRestClient.new
397
+ domain = @rc.add_domain("mock_domain")
398
+ app = domain.add_application("app1", "mock_type")
399
+ app.cartridges << @rc.cartridges.find {|c| c.name == 'premium_cart'}
400
+ end
401
+
402
+ context 'when run with a premium cartridge' do
403
+ it { run_output.should match(/This gear costs an additional \$0\.05 per gear after the first 3 gears./) }
404
+ end
405
+ end
406
+
407
+ describe 'cartridge show scaled' do
408
+ let!(:rest_client){ MockRestClient.new }
409
+ let(:arguments) { ['cartridge', 'show', 'mock_type', '-a', 'app1'] }
410
+
411
+ context 'when run' do
412
+ before do
413
+ domain = rest_client.add_domain("mock_domain")
414
+ app = domain.add_application("app1", "mock_type", true)
415
+ end
416
+ it { run_output.should match(/Scaling: .*x2 \(minimum/) }
417
+ it { run_output.should match('minimum: 2') }
418
+ it { run_output.should match('maximum: available') }
419
+ end
420
+ end
421
+
422
+ describe 'cartridge scale' do
423
+ let!(:rest_client){ MockRestClient.new }
424
+ let(:arguments) { ['cartridge', 'scale', @cart_type || 'mock_type', '-a', 'app1'] | (@extra_args || []) }
425
+
426
+ let(:current_scale) { 1 }
427
+ before do
428
+ domain = rest_client.add_domain("mock_domain")
429
+ @app = domain.add_application("app1", "mock_type", scalable)
430
+ @app.cartridges.first.stub(:current_scale).and_return(current_scale)
431
+ end
432
+
433
+ context 'when run with scalable app' do
434
+ let(:scalable){ true }
435
+
436
+ it "with no values" do
437
+ fail_with_message "Must provide either a min or max"
438
+ end
439
+
440
+ it "with a min value" do
441
+ @extra_args = ["--min","6"]
442
+ succeed_with_message "minimum: 6"
443
+ end
444
+
445
+ it "with an explicit value" do
446
+ @extra_args = ["6"]
447
+ succeed_with_message "minimum: 6, maximum: 6"
448
+ end
449
+
450
+ it "with an invalid explicit value" do
451
+ @extra_args = ["a6"]
452
+ fail_with_message "Multiplier must be a positive integer"
453
+ end
454
+
455
+ it "with an explicit value and a different minimum" do
456
+ @extra_args = ["6", "--min", "5"]
457
+ succeed_with_message "minimum: 5, maximum: 6"
458
+ end
459
+
460
+ it "with a max value" do
461
+ @extra_args = ["--max","3"]
462
+ succeed_with_message 'maximum: 3'
463
+ end
464
+
465
+ it "with an invalid min value" do
466
+ @extra_args = ["--min","a"]
467
+ fail_with_message "invalid argument: --min"
468
+ end
469
+
470
+ it "with an invalid max value" do
471
+ @extra_args = ["--max","a"]
472
+ fail_with_message "invalid argument: --max"
473
+ end
474
+
475
+ context "when the operation times out" do
476
+ before{ @app.cartridges.first.should_receive(:set_scales).twice.and_raise(RHC::Rest::TimeoutException.new('Timeout', HTTPClient::ReceiveTimeoutError.new)) }
477
+ it "displays an error" do
478
+ @extra_args = ["--min","2"]
479
+ fail_with_message "The server has closed the connection, but your scaling operation is still in progress"
480
+ end
481
+ end
482
+ end
483
+
484
+ context 'when run with a nonscalable app' do
485
+ let(:scalable){ false }
486
+
487
+ it "with a min value" do
488
+ @extra_args = ["--min","6"]
489
+ fail_with_message "Cartridge is not scalable"
490
+ end
491
+ end
492
+ end
493
+
494
+ describe 'cartridge storage' do
495
+ let!(:rest_client){ MockRestClient.new(RHC::Config, 1.3) }
496
+ let(:cmd_base) { ['cartridge', 'storage'] }
497
+ let(:std_args) { ['-a', 'app1'] | (@extra_args || []) }
498
+ let(:cart_type) { ['mock_cart-1'] }
499
+
500
+ before do
501
+ domain = rest_client.add_domain("mock_domain")
502
+ app = domain.add_application("app1", "mock_type", false)
503
+ app.add_cartridge('mock_cart-1', true)
504
+ end
505
+
506
+ context 'when run with no arguments' do
507
+ let(:arguments) { cmd_base | std_args }
508
+ it ("should show the mock_type"){ run_output.should match('mock_type') }
509
+ it ('should show mock_cart-1'){ run_output.should match('mock_cart-1') }
510
+ end
511
+
512
+ context 'when run for a non-existent cartridge' do
513
+ let(:arguments) { cmd_base | ['bogus_cart'] | std_args }
514
+ it { fail_with_message("There are no cartridges that match 'bogus_cart'.", 154) }
515
+ end
516
+
517
+ context 'when run with -c flag' do
518
+ let(:arguments) { cmd_base | ['-c', 'mock_cart-1'] | std_args}
519
+ it "should show storage info for the indicated app and cart" do
520
+ run_output.should match('mock_cart-1')
521
+ run_output.should_not match('mock_type')
522
+ end
523
+
524
+ it "should set storage for the indicated app and cart" do
525
+ @extra_args = ["--set", "6GB"]
526
+ run_output.should match('6GB')
527
+ end
528
+ end
529
+
530
+ context 'when run with valid arguments' do
531
+ let(:arguments) { cmd_base | cart_type | std_args }
532
+ it "should show storage info for the indicated app and cart" do
533
+ @extra_args = ["--show"]
534
+ run_output.should match('mock_cart-1')
535
+ run_output.should_not match('mock_type')
536
+ end
537
+ it "should add storage for the indicated app and cart" do
538
+ @extra_args = ["--add", "5GB"]
539
+ run_output.should match('10GB')
540
+ end
541
+ it "should remove storage for the indicated app and cart" do
542
+ @extra_args = ["--remove", "5GB"]
543
+ run_output.should match('None')
544
+ end
545
+ it "should warn when told to remove more storage than the indicated app and cart have" do
546
+ @extra_args = ["--remove", "70GB"]
547
+ fail_with_message('The amount of additional storage to be removed exceeds the total amount in use')
548
+ end
549
+ it "should not warn when told to remove more storage than the indicated app and cart have when forced" do
550
+ @extra_args = ["--remove", "70GB", "--force"]
551
+ run_output.should match('None')
552
+ end
553
+ it "should set storage for the indicated app and cart" do
554
+ @extra_args = ["--set", "6GB"]
555
+ run_output.should match('6GB')
556
+ end
557
+ it "should work correctly with a bare number value" do
558
+ @extra_args = ["--set", "6"]
559
+ run_output.should match('6GB')
560
+ end
561
+ end
562
+
563
+ context 'when run with invalid arguments' do
564
+ let(:arguments) { cmd_base | cart_type | std_args }
565
+ it "should raise an error when multiple storage operations are provided" do
566
+ @extra_args = ["--show", "--add", "5GB"]
567
+ fail_with_message('Only one storage action can be performed at a time')
568
+ end
569
+ it "should raise an error when the storage amount is not provided" do
570
+ @extra_args = ["--set"]
571
+ fail_with_message('missing argument')
572
+ end
573
+ it "should raise an error when the storage amount is invalid" do
574
+ @extra_args = ["--set", "5ZB"]
575
+ fail_with_message("The amount format must be a number, optionally followed by 'GB'")
576
+ end
577
+ end
578
+
579
+ context 'when run against an outdated broker' do
580
+ before { rest_client.stub(:api_version_negotiated).and_return(1.2) }
581
+ let(:arguments) { cmd_base | cart_type | std_args }
582
+
583
+ it 'adding storage should raise a version error' do
584
+ @extra_args = ["--add", "1GB"]
585
+ fail_with_message('The server does not support this command \(requires 1.3, found 1.2\).')
586
+ end
587
+
588
+ end
589
+ end
590
+
591
+ describe 'cartridge add with env vars' do
592
+ let!(:rest_client){ MockRestClient.new }
593
+ before do
594
+ domain = rest_client.add_domain("mock_domain")
595
+ @app = domain.add_application("app1", "mock_type")
596
+ end
597
+
598
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO=BAR', '--app', 'app1'],
599
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO=BAR', '--app', 'app1']
600
+ ].each_with_index do |args, i|
601
+ context "when run with single env var #{i}" do
602
+ let(:arguments) { args }
603
+ it { succeed_with_message(/Environment Variables:\s+FOO=BAR/) }
604
+ end
605
+ end
606
+
607
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO1=BAR1', '-e', 'FOO2=BAR2', '--app', 'app1'],
608
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO1=BAR1', '--env', 'FOO2=BAR2', '--app', 'app1']
609
+ ].each_with_index do |args, i|
610
+ context "when run with multiple env vars #{i}" do
611
+ let(:arguments) { args }
612
+ it { succeed_with_message(/Environment Variables:\s+FOO1=BAR1, FOO2=BAR2/) }
613
+ end
614
+ end
615
+
616
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', File.expand_path('../../assets/env_vars.txt', __FILE__), '--app', 'app1'],
617
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', File.expand_path('../../assets/env_vars.txt', __FILE__), '--app', 'app1']
618
+ ].each_with_index do |args, i|
619
+ context "when run with env vars from files #{i}" do
620
+ let(:arguments) { args }
621
+ it { succeed_with_message(/Environment Variables:\s+BAR=456, FOO=123, MY_EMPTY_ENV_VAR=, MY_PROTONBOX_ENV_VAR=mongodb:\/\/user:pass@host:port\/\n/) }
622
+ end
623
+ end
624
+
625
+ [['app', 'cartridge', 'add', 'unique_mock_cart', '-e', 'FOO=BAR', '--app', 'app1', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password'],
626
+ ['app', 'cartridge', 'add', 'unique_mock_cart', '--env', 'FOO=BAR', '--app', 'app1', '--noprompt', '--config', 'test.conf', '-l', 'test@test.foo', '-p', 'password']
627
+ ].each_with_index do |args, i|
628
+ context "when run against a server without env vars support #{i}" do
629
+ let(:arguments) { args }
630
+ before do
631
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','environment_variables').and_return(false)
632
+ @app.stub(:has_param?).with('ADD_CARTRIDGE','gear_size').and_return(true)
633
+ end
634
+ it { expect { run }.to exit_with_code(0) }
635
+ it { run_output.should match(/Server does not support environment variables/) }
636
+ it { run_output.should_not match(/Environment Variables:\s+FOO=BAR/) }
637
+ end
638
+ end
639
+
640
+ end
641
+ end