cf 0.1.5 → 0.6.0.rc1

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 (140) hide show
  1. data/LICENSE +1277 -30
  2. data/Rakefile +12 -1
  3. data/bin/cf +0 -3
  4. data/lib/cf.rb +6 -0
  5. data/lib/cf/cli.rb +389 -190
  6. data/lib/cf/cli/app/app.rb +45 -0
  7. data/lib/cf/cli/app/apps.rb +99 -0
  8. data/lib/cf/cli/app/base.rb +90 -0
  9. data/lib/cf/cli/app/crashes.rb +42 -0
  10. data/lib/cf/cli/app/delete.rb +95 -0
  11. data/lib/cf/cli/app/deprecated.rb +11 -0
  12. data/lib/cf/cli/app/env.rb +78 -0
  13. data/lib/cf/cli/app/files.rb +137 -0
  14. data/lib/cf/cli/app/health.rb +26 -0
  15. data/lib/cf/cli/app/instances.rb +53 -0
  16. data/lib/cf/cli/app/logs.rb +76 -0
  17. data/lib/cf/cli/app/push.rb +105 -0
  18. data/lib/cf/cli/app/push/create.rb +149 -0
  19. data/lib/cf/cli/app/push/interactions.rb +94 -0
  20. data/lib/cf/cli/app/push/sync.rb +64 -0
  21. data/lib/cf/cli/app/rename.rb +35 -0
  22. data/lib/cf/cli/app/restart.rb +20 -0
  23. data/lib/cf/cli/app/scale.rb +69 -0
  24. data/lib/cf/cli/app/start.rb +143 -0
  25. data/lib/cf/cli/app/stats.rb +67 -0
  26. data/lib/cf/cli/app/stop.rb +27 -0
  27. data/lib/cf/cli/domain/base.rb +8 -0
  28. data/lib/cf/cli/domain/domains.rb +40 -0
  29. data/lib/cf/cli/domain/map.rb +55 -0
  30. data/lib/cf/cli/domain/unmap.rb +56 -0
  31. data/lib/cf/cli/help.rb +15 -0
  32. data/lib/cf/cli/interactive.rb +105 -0
  33. data/lib/cf/cli/organization/base.rb +12 -0
  34. data/lib/cf/cli/organization/create.rb +32 -0
  35. data/lib/cf/cli/organization/delete.rb +73 -0
  36. data/lib/cf/cli/organization/org.rb +45 -0
  37. data/lib/cf/cli/organization/orgs.rb +35 -0
  38. data/lib/cf/cli/organization/rename.rb +36 -0
  39. data/lib/cf/cli/route/base.rb +8 -0
  40. data/lib/cf/cli/route/map.rb +70 -0
  41. data/lib/cf/cli/route/routes.rb +26 -0
  42. data/lib/cf/cli/route/unmap.rb +62 -0
  43. data/lib/cf/cli/service/base.rb +8 -0
  44. data/lib/cf/cli/service/bind.rb +44 -0
  45. data/lib/cf/cli/service/create.rb +107 -0
  46. data/lib/cf/cli/service/delete.rb +82 -0
  47. data/lib/cf/cli/service/rename.rb +35 -0
  48. data/lib/cf/cli/service/service.rb +40 -0
  49. data/lib/cf/cli/service/services.rb +99 -0
  50. data/lib/cf/cli/service/unbind.rb +38 -0
  51. data/lib/cf/cli/space/base.rb +19 -0
  52. data/lib/cf/cli/space/create.rb +63 -0
  53. data/lib/cf/cli/space/delete.rb +95 -0
  54. data/lib/cf/cli/space/rename.rb +39 -0
  55. data/lib/cf/cli/space/space.rb +64 -0
  56. data/lib/cf/cli/space/spaces.rb +55 -0
  57. data/lib/cf/cli/space/switch.rb +16 -0
  58. data/lib/cf/cli/start/base.rb +93 -0
  59. data/lib/cf/cli/start/colors.rb +13 -0
  60. data/lib/cf/cli/start/info.rb +124 -0
  61. data/lib/cf/cli/start/login.rb +94 -0
  62. data/lib/cf/cli/start/logout.rb +17 -0
  63. data/lib/cf/cli/start/target.rb +69 -0
  64. data/lib/cf/cli/start/target_interactions.rb +37 -0
  65. data/lib/cf/cli/start/targets.rb +16 -0
  66. data/lib/cf/cli/user/base.rb +29 -0
  67. data/lib/cf/cli/user/create.rb +39 -0
  68. data/lib/cf/cli/user/passwd.rb +43 -0
  69. data/lib/cf/cli/user/register.rb +42 -0
  70. data/lib/cf/cli/user/users.rb +32 -0
  71. data/lib/cf/constants.rb +10 -7
  72. data/lib/cf/detect.rb +113 -48
  73. data/lib/cf/errors.rb +17 -0
  74. data/lib/cf/plugin.rb +28 -12
  75. data/lib/cf/spacing.rb +89 -0
  76. data/lib/cf/spec_helper.rb +1 -0
  77. data/lib/cf/test_support.rb +6 -0
  78. data/lib/cf/version.rb +1 -1
  79. data/spec/assets/hello-sinatra/Gemfile +3 -0
  80. data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
  81. data/spec/assets/hello-sinatra/config.ru +3 -0
  82. data/spec/assets/hello-sinatra/fat-cat-makes-app-larger.png +0 -0
  83. data/spec/assets/hello-sinatra/main.rb +6 -0
  84. data/spec/assets/specker_runner/specker_runner_input.rb +6 -0
  85. data/spec/assets/specker_runner/specker_runner_pause.rb +5 -0
  86. data/spec/cf/cli/app/base_spec.rb +17 -0
  87. data/spec/cf/cli/app/delete_spec.rb +188 -0
  88. data/spec/cf/cli/app/instances_spec.rb +65 -0
  89. data/spec/cf/cli/app/push/create_spec.rb +661 -0
  90. data/spec/cf/cli/app/push_spec.rb +369 -0
  91. data/spec/cf/cli/app/rename_spec.rb +104 -0
  92. data/spec/cf/cli/app/scale_spec.rb +75 -0
  93. data/spec/cf/cli/app/start_spec.rb +208 -0
  94. data/spec/cf/cli/app/stats_spec.rb +68 -0
  95. data/spec/cf/cli/domain/map_spec.rb +130 -0
  96. data/spec/cf/cli/domain/unmap_spec.rb +69 -0
  97. data/spec/cf/cli/organization/orgs_spec.rb +108 -0
  98. data/spec/cf/cli/organization/rename_spec.rb +113 -0
  99. data/spec/cf/cli/route/map_spec.rb +121 -0
  100. data/spec/cf/cli/route/unmap_spec.rb +155 -0
  101. data/spec/cf/cli/service/bind_spec.rb +25 -0
  102. data/spec/cf/cli/service/delete_spec.rb +22 -0
  103. data/spec/cf/cli/service/rename_spec.rb +105 -0
  104. data/spec/cf/cli/service/service_spec.rb +23 -0
  105. data/spec/cf/cli/service/unbind_spec.rb +25 -0
  106. data/spec/cf/cli/space/create_spec.rb +93 -0
  107. data/spec/cf/cli/space/rename_spec.rb +102 -0
  108. data/spec/cf/cli/space/spaces_spec.rb +104 -0
  109. data/spec/cf/cli/space/switch_space_spec.rb +55 -0
  110. data/spec/cf/cli/start/info_spec.rb +160 -0
  111. data/spec/cf/cli/start/login_spec.rb +142 -0
  112. data/spec/cf/cli/start/logout_spec.rb +50 -0
  113. data/spec/cf/cli/start/target_spec.rb +123 -0
  114. data/spec/cf/cli/user/create_spec.rb +54 -0
  115. data/spec/cf/cli/user/passwd_spec.rb +102 -0
  116. data/spec/cf/cli/user/register_spec.rb +140 -0
  117. data/spec/cf/cli_spec.rb +442 -0
  118. data/spec/cf/detect_spec.rb +54 -0
  119. data/spec/console_app_specker/console_app_specker_matchers_spec.rb +173 -0
  120. data/spec/console_app_specker/specker_runner_spec.rb +167 -0
  121. data/spec/features/account_lifecycle_spec.rb +85 -0
  122. data/spec/features/login_spec.rb +66 -0
  123. data/spec/features/push_flow_spec.rb +125 -0
  124. data/spec/features/switching_targets_spec.rb +32 -0
  125. data/spec/spec_helper.rb +72 -0
  126. data/spec/support/command_helper.rb +81 -0
  127. data/spec/support/config_helper.rb +15 -0
  128. data/spec/support/console_app_specker_matchers.rb +86 -0
  129. data/spec/support/fake_home_dir.rb +55 -0
  130. data/spec/support/interact_helper.rb +29 -0
  131. data/spec/support/shared_examples/errors.rb +40 -0
  132. data/spec/support/shared_examples/input.rb +14 -0
  133. data/spec/support/specker_runner.rb +80 -0
  134. data/spec/support/tracking_expector.rb +71 -0
  135. metadata +427 -66
  136. data/lib/cf/cli/app.rb +0 -595
  137. data/lib/cf/cli/command.rb +0 -444
  138. data/lib/cf/cli/dots.rb +0 -133
  139. data/lib/cf/cli/service.rb +0 -112
  140. data/lib/cf/cli/user.rb +0 -71
@@ -0,0 +1,661 @@
1
+ require 'spec_helper'
2
+ require 'fakefs/safe'
3
+
4
+ describe CF::App::Create do
5
+ let(:inputs) { {} }
6
+ let(:given) { {} }
7
+ let(:global) { { :color => false, :quiet => true } }
8
+
9
+ let(:frameworks) { fake_list(:framework, 3) }
10
+ let(:framework) { buildpack }
11
+ let(:buildpack) { fake(:framework, :name => "buildpack") }
12
+ let(:standalone) { fake(:framework, :name => "standalone") }
13
+
14
+ let(:runtimes) { fake_list(:runtime, 3) }
15
+ let(:runtime) { runtimes.first }
16
+
17
+ let(:service_instances) { fake_list(:service_instance, 5) }
18
+
19
+ let(:lucid64) { fake :stack, :name => "lucid64" }
20
+
21
+ let(:client) do
22
+ fake_client(
23
+ :frameworks => frameworks,
24
+ :runtimes => runtimes,
25
+ :service_instances => service_instances,
26
+ :stacks => [lucid64])
27
+ end
28
+
29
+ before do
30
+ any_instance_of(CF::CLI) do |cli|
31
+ stub(cli).client { client }
32
+ end
33
+ end
34
+
35
+ let(:path) { "some-path" }
36
+
37
+ subject(:create) do
38
+ command = Mothership.commands[:push]
39
+ create = CF::App::Push.new(command)
40
+ create.path = path
41
+ create.input = Mothership::Inputs.new(command, create, inputs, given, global)
42
+ create.extend CF::App::PushInteractions
43
+ create
44
+ end
45
+
46
+ describe '#get_inputs' do
47
+ subject { create.get_inputs }
48
+
49
+ let(:given) do
50
+ { :name => "some-name",
51
+ :instances => "1",
52
+ :plan => "p100",
53
+ :memory => "1G",
54
+ :command => "ruby main.rb",
55
+ :buildpack => "git://example.com",
56
+ :stack => "lucid64"
57
+ }
58
+ end
59
+
60
+ context 'when all the inputs are given' do
61
+ its([:name]) { should eq "some-name" }
62
+ its([:total_instances]) { should eq 1 }
63
+ its([:space]) { should eq client.current_space }
64
+ its([:production]) { should eq true }
65
+ its([:framework]) { should eq nil }
66
+ its([:runtime]) { should eq nil }
67
+ its([:command]) { should eq "ruby main.rb" }
68
+ its([:memory]) { should eq 1024 }
69
+ its([:buildpack]) { should eq "git://example.com" }
70
+ its([:stack]) { should eq lucid64 }
71
+ end
72
+
73
+ context 'when the command is given' do
74
+ context "and there is a Procfile in the application's root" do
75
+ before do
76
+ FakeFS.activate!
77
+ Dir.mkdir(path)
78
+
79
+ File.open("#{path}/Procfile", "w") do |file|
80
+ file.write("this is a procfile")
81
+ end
82
+ end
83
+
84
+ after do
85
+ FakeFS.deactivate!
86
+ FakeFS::FileSystem.clear
87
+ end
88
+
89
+ its([:command]) { should eq "ruby main.rb" }
90
+ end
91
+ end
92
+
93
+ context 'when certain inputs are not given' do
94
+ it 'asks for the name' do
95
+ given.delete(:name)
96
+ mock_ask("Name") { "some-name" }
97
+ subject
98
+ end
99
+
100
+ it 'asks for the total instances' do
101
+ given.delete(:instances)
102
+ mock_ask("Instances", anything) { 1 }
103
+ subject
104
+ end
105
+
106
+ it 'does not ask for the framework' do
107
+ dont_allow_ask('Framework', anything) do |_, options|
108
+ expect(options[:choices]).to eq frameworks.sort_by(&:name)
109
+ framework
110
+ end
111
+ subject
112
+ end
113
+
114
+ context 'when the command is not given' do
115
+ before { given.delete(:command) }
116
+
117
+ shared_examples 'an app that can have a custom start command' do
118
+ it "asks for a start command with a default as 'none'" do
119
+ mock_ask("Custom startup command", :default => "none") do
120
+ "abcd"
121
+ end
122
+
123
+ expect(subject[:command]).to eq "abcd"
124
+ end
125
+
126
+ context "when the user enters 'none'" do
127
+ it "has the command as nil" do
128
+ stub_ask("Custom startup command", :default => "none") do
129
+ "none"
130
+ end
131
+
132
+ expect(subject[:command]).to be_nil
133
+ end
134
+ end
135
+ end
136
+
137
+ context 'when the framework is "buildpack"' do
138
+ let(:framework) { buildpack }
139
+
140
+ include_examples 'an app that can have a custom start command'
141
+ end
142
+
143
+ context 'when the framework is "standalone"' do
144
+ let(:framework) { standalone }
145
+
146
+ include_examples 'an app that can have a custom start command'
147
+ end
148
+
149
+ describe "getting the start command" do
150
+ before do
151
+ FakeFS.activate!
152
+ Dir.mkdir(path)
153
+ end
154
+
155
+ after do
156
+ FakeFS.deactivate!
157
+ FakeFS::FileSystem.clear
158
+ end
159
+
160
+ context "when there is a Procfile in the app's root" do
161
+ before do
162
+ File.open("#{path}/Procfile", "w") do |file|
163
+ file.write("this is a procfile")
164
+ end
165
+ end
166
+
167
+ it 'does not ask for a start command' do
168
+ dont_allow_ask("Startup command")
169
+ subject
170
+ end
171
+ end
172
+
173
+ context "when there is no Procfile in the app's root" do
174
+ it 'asks for a start command' do
175
+ mock_ask("Custom startup command", :default => "none")
176
+ subject
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ it 'does not ask for the runtime' do
183
+ dont_allow_ask('Runtime', anything) do |_, options|
184
+ expect(options[:choices]).to eq runtimes.sort_by(&:name)
185
+ runtime
186
+ end
187
+ subject
188
+ end
189
+
190
+ it 'asks for the memory' do
191
+ given.delete(:memory)
192
+
193
+ memory_choices = %w(64M 128M 256M 512M 1G)
194
+ stub(create).memory_choices { memory_choices }
195
+
196
+ detector = mock
197
+ stub(create).detector { detector }
198
+
199
+ stub(detector).detected { Clouseau::Rails }
200
+
201
+ mock_ask('Memory Limit', anything) do |_, options|
202
+ expect(options[:choices]).to eq memory_choices
203
+ expect(options[:default]).to eq "256M"
204
+ "1G"
205
+ end
206
+
207
+ subject
208
+ end
209
+ end
210
+ end
211
+
212
+ describe '#determine_framework' do
213
+ subject { create.determine_framework }
214
+
215
+ context 'when framework is given' do
216
+ let(:inputs) { { :framework => framework } }
217
+
218
+ it 'does not try to get the frameworks' do
219
+ any_instance_of(CF::Detector) do |detector|
220
+ dont_allow(detector).detect_framework
221
+ dont_allow(detector).all_frameworks
222
+ end
223
+
224
+ dont_allow_ask
225
+ dont_allow(client).frameworks
226
+
227
+ subject
228
+ end
229
+
230
+ it { should eq framework }
231
+ end
232
+
233
+ context 'when framework is not given' do
234
+ context 'and a framework is detected' do
235
+ it "lists the detected framework and an 'other' option" do
236
+ any_instance_of(CF::Detector) do |detector|
237
+ mock(detector).detect_framework { framework }
238
+ end
239
+
240
+ mock_ask('Framework', anything) do |_, options|
241
+ expect(options[:choices]).to eq [framework, :other] #frameworks.sort_by(&:name)
242
+ framework
243
+ end
244
+
245
+ subject
246
+ end
247
+ end
248
+
249
+ context 'and a framework is not detected' do
250
+ it "lists all available frameworks" do
251
+ any_instance_of(CF::Detector) do |detector|
252
+ stub(detector).detect_framework
253
+ end
254
+
255
+ mock_ask('Framework', anything) do |_, options|
256
+ expect(options[:choices]).to eq frameworks.sort_by(&:name)
257
+ framework
258
+ end
259
+
260
+ subject
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ describe '#detect_runtimes' do
267
+ subject { create.determine_runtime(framework) }
268
+
269
+ context 'when runtime is given' do
270
+ let(:inputs) { { :runtime => runtime } }
271
+
272
+ it 'does not try to get the runtime' do
273
+ any_instance_of(CF::Detector) do |detector|
274
+ dont_allow(detector).detect_runtime
275
+ dont_allow(detector).all_runtimes
276
+ end
277
+
278
+ dont_allow_ask
279
+ dont_allow(client).runtimes
280
+
281
+ subject
282
+ end
283
+
284
+ it { should eq runtime }
285
+ end
286
+
287
+ context 'when runtime is not given' do
288
+ context 'and the framework is standalone' do
289
+ let(:framework) { standalone }
290
+
291
+ it "detects the runtime" do
292
+ any_instance_of(CF::Detector) do |detector|
293
+ mock(detector).detect_runtimes { runtimes }
294
+ end
295
+
296
+ mock_ask('Runtime', anything) do |_, options|
297
+ expect(options[:choices]).to eq(runtimes.sort_by(&:name) + [:other])
298
+ runtime
299
+ end
300
+
301
+ subject
302
+ end
303
+ end
304
+
305
+ context 'and the framework is not standalone' do
306
+ it "gets the runtimes based on the framework" do
307
+ any_instance_of(CF::Detector) do |detector|
308
+ mock(detector).runtimes(framework) { runtimes }
309
+ end
310
+
311
+ mock_ask('Runtime', anything) do |_, options|
312
+ expect(options[:choices]).to eq(runtimes.sort_by(&:name) + [:other])
313
+ runtime
314
+ end
315
+
316
+ subject
317
+ end
318
+ end
319
+ end
320
+ end
321
+
322
+ describe '#create_app' do
323
+ before { dont_allow_ask }
324
+
325
+ let(:app) { fake(:app, :guid => nil) }
326
+ let(:space) { fake(:space, :name => "some-space") }
327
+
328
+ let(:attributes) do
329
+ { :name => "some-app",
330
+ :total_instances => 2,
331
+ :framework => framework,
332
+ :runtime => runtime,
333
+ :production => false,
334
+ :memory => 1024,
335
+ :buildpack => "git://example.com"
336
+ }
337
+ end
338
+
339
+ before do
340
+ stub(client).app { app }
341
+ stub(client).current_space { space }
342
+ end
343
+
344
+ subject { create.create_app(attributes) }
345
+
346
+ it 'creates an app based on the resulting inputs' do
347
+ mock(create).filter(:create_app, app) { app }
348
+
349
+ mock(app).create!
350
+
351
+ subject
352
+
353
+ attributes.each do |key, val|
354
+ expect(app.send(key)).to eq val
355
+ end
356
+ end
357
+
358
+ context "when the user does not have permission to create apps" do
359
+ it "fails with a friendly message" do
360
+ stub(app).create! { raise CFoundry::NotAuthorized, "foo" }
361
+
362
+ expect { subject }.to raise_error(
363
+ CF::UserError,
364
+ "You need the Project Developer role in some-space to push.")
365
+ end
366
+ end
367
+
368
+ context "with an invalid buildpack" do
369
+ before do
370
+ stub(app).create! do
371
+ raise CFoundry::MessageParseError.new(
372
+ "Request invalid due to parse error: Field: buildpack, Error: Value git@github.com:cloudfoundry/heroku-buildpack-ruby.git doesn't match regexp String /GIT_URL_REGEX/",
373
+ 1001)
374
+ end
375
+ end
376
+
377
+ it "fails and prints a pretty message" do
378
+ stub(create).line(anything)
379
+ expect { subject }.to raise_error(
380
+ CF::UserError, "Buildpack must be a public git repository URI.")
381
+ end
382
+ end
383
+ end
384
+
385
+ describe '#map_url' do
386
+ let(:app) { fake(:app, :space => space) }
387
+ let(:space) { fake(:space, :domains => domains) }
388
+ let(:domains) { [fake(:domain, :name => "foo.com")] }
389
+ let(:hosts) { [app.name] }
390
+
391
+ subject { create.map_route(app) }
392
+
393
+ it "asks for a subdomain with 'none' as an option" do
394
+ mock_ask('Subdomain', anything) do |_, options|
395
+ expect(options[:choices]).to eq(hosts + %w(none))
396
+ expect(options[:default]).to eq hosts.first
397
+ hosts.first
398
+ end
399
+
400
+ stub_ask("Domain", anything) { domains.first }
401
+
402
+ stub(create).invoke
403
+
404
+ subject
405
+ end
406
+
407
+ it "asks for a domain with 'none' as an option" do
408
+ stub_ask("Subdomain", anything) { hosts.first }
409
+
410
+ mock_ask('Domain', anything) do |_, options|
411
+ expect(options[:choices]).to eq(domains + %w(none))
412
+ expect(options[:default]).to eq domains.first
413
+ domains.first
414
+ end
415
+
416
+ stub(create).invoke
417
+
418
+ subject
419
+ end
420
+
421
+ it "maps the host and domain after both are given" do
422
+ stub_ask('Subdomain', anything) { hosts.first }
423
+ stub_ask('Domain', anything) { domains.first }
424
+
425
+ mock(create).invoke(:map,
426
+ :app => app, :host => hosts.first,
427
+ :domain => domains.first)
428
+
429
+ subject
430
+ end
431
+
432
+ context "when 'none' is given as the host" do
433
+ context "and a domain is provided afterwards" do
434
+ it "invokes 'map' with an empty host" do
435
+ mock_ask('Subdomain', anything) { "none" }
436
+ stub_ask('Domain', anything) { domains.first }
437
+
438
+ mock(create).invoke(:map,
439
+ :host => "", :domain => domains.first, :app => app)
440
+
441
+ subject
442
+ end
443
+ end
444
+ end
445
+
446
+ context "when 'none' is given as the domain" do
447
+ it "does not perform any mapping" do
448
+ stub_ask('Subdomain', anything) { "foo" }
449
+ mock_ask('Domain', anything) { "none" }
450
+
451
+ dont_allow(create).invoke(:map, anything)
452
+
453
+ subject
454
+ end
455
+ end
456
+
457
+ context "when mapping fails" do
458
+ before do
459
+ mock_ask('Subdomain', anything) { "foo" }
460
+ mock_ask('Domain', anything) { domains.first }
461
+
462
+ mock(create).invoke(:map,
463
+ :host => "foo", :domain => domains.first, :app => app) do
464
+ raise CFoundry::RouteHostTaken.new("foo", 1234)
465
+ end
466
+ end
467
+
468
+ it "asks again" do
469
+ stub(create).line
470
+
471
+ mock_ask('Subdomain', anything) { hosts.first }
472
+ mock_ask('Domain', anything) { domains.first }
473
+
474
+ stub(create).invoke
475
+
476
+ subject
477
+ end
478
+
479
+ it "reports the failure message" do
480
+ mock(create).line "foo"
481
+ mock(create).line
482
+
483
+ stub_ask('Subdomain', anything) { hosts.first }
484
+ stub_ask('Domain', anything) { domains.first }
485
+
486
+ stub(create).invoke
487
+
488
+ subject
489
+ end
490
+ end
491
+ end
492
+
493
+ describe '#create_services' do
494
+ let(:app) { fake(:app) }
495
+ subject { create.create_services(app) }
496
+
497
+ context 'when forcing' do
498
+ let(:inputs) { {:force => true} }
499
+
500
+ it "does not ask to create any services" do
501
+ dont_allow_ask("Create services for application?", anything)
502
+ subject
503
+ end
504
+
505
+ it "does not create any services" do
506
+ dont_allow(create).invoke(:create_service, anything)
507
+ subject
508
+ end
509
+ end
510
+
511
+ context 'when not forcing' do
512
+ let(:inputs) { { :force => false } }
513
+
514
+ it 'does not create the service if asked not to' do
515
+ mock_ask("Create services for application?", anything) { false }
516
+ dont_allow(create).invoke(:create_service, anything)
517
+
518
+ subject
519
+ end
520
+
521
+ it 'asks again to create a service' do
522
+ mock_ask("Create services for application?", anything) { true }
523
+ mock(create).invoke(:create_service, { :app => app }, :plan => :interact).ordered
524
+
525
+ mock_ask("Create another service?", :default => false) { true }
526
+ mock(create).invoke(:create_service, { :app => app }, :plan => :interact).ordered
527
+
528
+ mock_ask("Create another service?", :default => false) { true }
529
+ mock(create).invoke(:create_service, { :app => app }, :plan => :interact).ordered
530
+
531
+ mock_ask("Create another service?", :default => false) { false }
532
+ dont_allow(create).invoke(:create_service, anything).ordered
533
+
534
+ subject
535
+ end
536
+ end
537
+ end
538
+
539
+ describe '#bind_services' do
540
+ let(:app) { fake(:app) }
541
+
542
+ subject { create.bind_services(app) }
543
+
544
+ context 'when forcing' do
545
+ let(:global) { { :force => true, :color => false, :quiet => true } }
546
+
547
+ it "does not ask to bind any services" do
548
+ dont_allow_ask("Bind other services to application?", anything)
549
+ subject
550
+ end
551
+
552
+ it "does not bind any services" do
553
+ dont_allow(create).invoke(:bind_service, anything)
554
+ subject
555
+ end
556
+ end
557
+
558
+ context 'when not forcing' do
559
+ it 'does not bind the service if asked not to' do
560
+ mock_ask("Bind other services to application?", anything) { false }
561
+ dont_allow(create).invoke(:bind_service, anything)
562
+
563
+ subject
564
+ end
565
+
566
+ it 'asks again to bind a service' do
567
+ bind_times = 3
568
+ call_count = 0
569
+
570
+ mock_ask("Bind other services to application?", anything) { true }
571
+
572
+ mock(create).invoke(:bind_service, :app => app).times(bind_times) do
573
+ call_count += 1
574
+ stub(app).services { service_instances.first(call_count) }
575
+ end
576
+
577
+ mock_ask("Bind another service?", anything).times(bind_times) do
578
+ call_count < bind_times
579
+ end
580
+
581
+ subject
582
+ end
583
+
584
+ it 'stops asking if there are no more services to bind' do
585
+ bind_times = service_instances.size
586
+ call_count = 0
587
+
588
+ mock_ask("Bind other services to application?", anything) { true }
589
+
590
+ mock(create).invoke(:bind_service, :app => app).times(bind_times) do
591
+ call_count += 1
592
+ stub(app).services { service_instances.first(call_count) }
593
+ end
594
+
595
+ mock_ask("Bind another service?", anything).times(bind_times - 1) { true }
596
+
597
+ subject
598
+ end
599
+
600
+ context 'when there are no services' do
601
+ let(:service_instances) { [] }
602
+
603
+ it 'does not ask to bind anything' do
604
+ dont_allow_ask
605
+ subject
606
+ end
607
+ end
608
+ end
609
+ end
610
+
611
+ describe '#start_app' do
612
+ let(:app) { fake(:app) }
613
+ subject { create.start_app(app) }
614
+
615
+ context 'when the start flag is provided' do
616
+ let(:inputs) { {:start => true} }
617
+
618
+ it 'invokes the start command' do
619
+ mock(create).invoke(:start, :app => app)
620
+ subject
621
+ end
622
+ end
623
+
624
+ context 'when the start flag is not provided' do
625
+ let(:inputs) { {:start => false} }
626
+
627
+ it 'invokes the start command' do
628
+ dont_allow(create).invoke(:start, anything)
629
+ subject
630
+ end
631
+ end
632
+ end
633
+
634
+ describe '#memory_choices' do
635
+ let(:info) { {} }
636
+
637
+ before do
638
+ stub(client).info { info }
639
+ end
640
+
641
+ context "when the user has usage information" do
642
+ let(:info) do
643
+ { :usage => { :memory => 512 },
644
+ :limits => { :memory => 2048 }
645
+ }
646
+ end
647
+
648
+ it "asks for the memory with the ceiling taking the memory usage into account" do
649
+ expect(subject.memory_choices).to eq(%w[64M 128M 256M 512M 1G])
650
+ end
651
+ end
652
+
653
+ context "when the user does not have usage information" do
654
+ let(:info) { {:limits => { :memory => 2048 } } }
655
+
656
+ it "asks for the memory with the ceiling as their overall limit" do
657
+ expect(subject.memory_choices).to eq(%w[64M 128M 256M 512M 1G 2G])
658
+ end
659
+ end
660
+ end
661
+ end