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.
- data/LICENSE +1277 -30
- data/Rakefile +12 -1
- data/bin/cf +0 -3
- data/lib/cf.rb +6 -0
- data/lib/cf/cli.rb +389 -190
- data/lib/cf/cli/app/app.rb +45 -0
- data/lib/cf/cli/app/apps.rb +99 -0
- data/lib/cf/cli/app/base.rb +90 -0
- data/lib/cf/cli/app/crashes.rb +42 -0
- data/lib/cf/cli/app/delete.rb +95 -0
- data/lib/cf/cli/app/deprecated.rb +11 -0
- data/lib/cf/cli/app/env.rb +78 -0
- data/lib/cf/cli/app/files.rb +137 -0
- data/lib/cf/cli/app/health.rb +26 -0
- data/lib/cf/cli/app/instances.rb +53 -0
- data/lib/cf/cli/app/logs.rb +76 -0
- data/lib/cf/cli/app/push.rb +105 -0
- data/lib/cf/cli/app/push/create.rb +149 -0
- data/lib/cf/cli/app/push/interactions.rb +94 -0
- data/lib/cf/cli/app/push/sync.rb +64 -0
- data/lib/cf/cli/app/rename.rb +35 -0
- data/lib/cf/cli/app/restart.rb +20 -0
- data/lib/cf/cli/app/scale.rb +69 -0
- data/lib/cf/cli/app/start.rb +143 -0
- data/lib/cf/cli/app/stats.rb +67 -0
- data/lib/cf/cli/app/stop.rb +27 -0
- data/lib/cf/cli/domain/base.rb +8 -0
- data/lib/cf/cli/domain/domains.rb +40 -0
- data/lib/cf/cli/domain/map.rb +55 -0
- data/lib/cf/cli/domain/unmap.rb +56 -0
- data/lib/cf/cli/help.rb +15 -0
- data/lib/cf/cli/interactive.rb +105 -0
- data/lib/cf/cli/organization/base.rb +12 -0
- data/lib/cf/cli/organization/create.rb +32 -0
- data/lib/cf/cli/organization/delete.rb +73 -0
- data/lib/cf/cli/organization/org.rb +45 -0
- data/lib/cf/cli/organization/orgs.rb +35 -0
- data/lib/cf/cli/organization/rename.rb +36 -0
- data/lib/cf/cli/route/base.rb +8 -0
- data/lib/cf/cli/route/map.rb +70 -0
- data/lib/cf/cli/route/routes.rb +26 -0
- data/lib/cf/cli/route/unmap.rb +62 -0
- data/lib/cf/cli/service/base.rb +8 -0
- data/lib/cf/cli/service/bind.rb +44 -0
- data/lib/cf/cli/service/create.rb +107 -0
- data/lib/cf/cli/service/delete.rb +82 -0
- data/lib/cf/cli/service/rename.rb +35 -0
- data/lib/cf/cli/service/service.rb +40 -0
- data/lib/cf/cli/service/services.rb +99 -0
- data/lib/cf/cli/service/unbind.rb +38 -0
- data/lib/cf/cli/space/base.rb +19 -0
- data/lib/cf/cli/space/create.rb +63 -0
- data/lib/cf/cli/space/delete.rb +95 -0
- data/lib/cf/cli/space/rename.rb +39 -0
- data/lib/cf/cli/space/space.rb +64 -0
- data/lib/cf/cli/space/spaces.rb +55 -0
- data/lib/cf/cli/space/switch.rb +16 -0
- data/lib/cf/cli/start/base.rb +93 -0
- data/lib/cf/cli/start/colors.rb +13 -0
- data/lib/cf/cli/start/info.rb +124 -0
- data/lib/cf/cli/start/login.rb +94 -0
- data/lib/cf/cli/start/logout.rb +17 -0
- data/lib/cf/cli/start/target.rb +69 -0
- data/lib/cf/cli/start/target_interactions.rb +37 -0
- data/lib/cf/cli/start/targets.rb +16 -0
- data/lib/cf/cli/user/base.rb +29 -0
- data/lib/cf/cli/user/create.rb +39 -0
- data/lib/cf/cli/user/passwd.rb +43 -0
- data/lib/cf/cli/user/register.rb +42 -0
- data/lib/cf/cli/user/users.rb +32 -0
- data/lib/cf/constants.rb +10 -7
- data/lib/cf/detect.rb +113 -48
- data/lib/cf/errors.rb +17 -0
- data/lib/cf/plugin.rb +28 -12
- data/lib/cf/spacing.rb +89 -0
- data/lib/cf/spec_helper.rb +1 -0
- data/lib/cf/test_support.rb +6 -0
- data/lib/cf/version.rb +1 -1
- data/spec/assets/hello-sinatra/Gemfile +3 -0
- data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
- data/spec/assets/hello-sinatra/config.ru +3 -0
- data/spec/assets/hello-sinatra/fat-cat-makes-app-larger.png +0 -0
- data/spec/assets/hello-sinatra/main.rb +6 -0
- data/spec/assets/specker_runner/specker_runner_input.rb +6 -0
- data/spec/assets/specker_runner/specker_runner_pause.rb +5 -0
- data/spec/cf/cli/app/base_spec.rb +17 -0
- data/spec/cf/cli/app/delete_spec.rb +188 -0
- data/spec/cf/cli/app/instances_spec.rb +65 -0
- data/spec/cf/cli/app/push/create_spec.rb +661 -0
- data/spec/cf/cli/app/push_spec.rb +369 -0
- data/spec/cf/cli/app/rename_spec.rb +104 -0
- data/spec/cf/cli/app/scale_spec.rb +75 -0
- data/spec/cf/cli/app/start_spec.rb +208 -0
- data/spec/cf/cli/app/stats_spec.rb +68 -0
- data/spec/cf/cli/domain/map_spec.rb +130 -0
- data/spec/cf/cli/domain/unmap_spec.rb +69 -0
- data/spec/cf/cli/organization/orgs_spec.rb +108 -0
- data/spec/cf/cli/organization/rename_spec.rb +113 -0
- data/spec/cf/cli/route/map_spec.rb +121 -0
- data/spec/cf/cli/route/unmap_spec.rb +155 -0
- data/spec/cf/cli/service/bind_spec.rb +25 -0
- data/spec/cf/cli/service/delete_spec.rb +22 -0
- data/spec/cf/cli/service/rename_spec.rb +105 -0
- data/spec/cf/cli/service/service_spec.rb +23 -0
- data/spec/cf/cli/service/unbind_spec.rb +25 -0
- data/spec/cf/cli/space/create_spec.rb +93 -0
- data/spec/cf/cli/space/rename_spec.rb +102 -0
- data/spec/cf/cli/space/spaces_spec.rb +104 -0
- data/spec/cf/cli/space/switch_space_spec.rb +55 -0
- data/spec/cf/cli/start/info_spec.rb +160 -0
- data/spec/cf/cli/start/login_spec.rb +142 -0
- data/spec/cf/cli/start/logout_spec.rb +50 -0
- data/spec/cf/cli/start/target_spec.rb +123 -0
- data/spec/cf/cli/user/create_spec.rb +54 -0
- data/spec/cf/cli/user/passwd_spec.rb +102 -0
- data/spec/cf/cli/user/register_spec.rb +140 -0
- data/spec/cf/cli_spec.rb +442 -0
- data/spec/cf/detect_spec.rb +54 -0
- data/spec/console_app_specker/console_app_specker_matchers_spec.rb +173 -0
- data/spec/console_app_specker/specker_runner_spec.rb +167 -0
- data/spec/features/account_lifecycle_spec.rb +85 -0
- data/spec/features/login_spec.rb +66 -0
- data/spec/features/push_flow_spec.rb +125 -0
- data/spec/features/switching_targets_spec.rb +32 -0
- data/spec/spec_helper.rb +72 -0
- data/spec/support/command_helper.rb +81 -0
- data/spec/support/config_helper.rb +15 -0
- data/spec/support/console_app_specker_matchers.rb +86 -0
- data/spec/support/fake_home_dir.rb +55 -0
- data/spec/support/interact_helper.rb +29 -0
- data/spec/support/shared_examples/errors.rb +40 -0
- data/spec/support/shared_examples/input.rb +14 -0
- data/spec/support/specker_runner.rb +80 -0
- data/spec/support/tracking_expector.rb +71 -0
- metadata +427 -66
- data/lib/cf/cli/app.rb +0 -595
- data/lib/cf/cli/command.rb +0 -444
- data/lib/cf/cli/dots.rb +0 -133
- data/lib/cf/cli/service.rb +0 -112
- 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
|