cf 0.1.5 → 0.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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