cf 5.2.1.rc4 → 5.2.1.rc5
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/lib/admin/plugin.rb +1 -0
- data/lib/admin/service_broker/update.rb +52 -0
- data/lib/cf/cli.rb +8 -2
- data/lib/cf/cli/app/env.rb +41 -20
- data/lib/cf/cli/app/push.rb +10 -9
- data/lib/cf/cli/app/start.rb +13 -5
- data/lib/cf/cli/app/stats.rb +0 -1
- data/lib/cf/cli/start/target_prettifier.rb +22 -5
- data/lib/cf/version.rb +1 -1
- data/spec/admin/service_broker/update_spec.rb +43 -0
- data/spec/assets/hello-sinatra/manifest.yml +17 -0
- data/spec/cf/cli/app/env_spec.rb +261 -0
- data/spec/cf/cli/app/push_spec.rb +107 -63
- data/spec/cf/cli/app/start_spec.rb +12 -10
- data/spec/cf/cli_spec.rb +4 -17
- data/spec/features/push_flow_spec.rb +17 -1
- data/spec/features/service_brokers_spec.rb +14 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/cli_helper.rb +22 -0
- data/spec/support/mock_commands/mock_restart.rb +16 -0
- data/spec/support/mock_commands/mock_start.rb +17 -0
- metadata +14 -21
- data/spec/cf/object_extensions_spec.rb +0 -24
@@ -6,7 +6,7 @@ module CF
|
|
6
6
|
let(:global) { {:color => false, :quiet => true} }
|
7
7
|
let(:inputs) { {} }
|
8
8
|
let(:given) { {} }
|
9
|
-
let(:path) { "somepath" }
|
9
|
+
let(:path) { "/somepath" }
|
10
10
|
let(:client) { build(:client) }
|
11
11
|
let(:push) { CF::App::Push.new(Mothership.commands[:push]) }
|
12
12
|
|
@@ -18,37 +18,28 @@ module CF
|
|
18
18
|
describe "metadata" do
|
19
19
|
let(:command) { Mothership.commands[:push] }
|
20
20
|
|
21
|
-
describe "
|
21
|
+
describe "has the correct information" do
|
22
22
|
subject { command }
|
23
23
|
its(:description) { should eq "Push an application, syncing changes if it exists" }
|
24
24
|
it { expect(Mothership::Help.group(:apps, :manage)).to include(subject) }
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
describe "arguments" do
|
30
|
-
subject { command.arguments }
|
31
|
-
it "has the correct argument order" do
|
32
|
-
should eq([{:type => :optional, :value => nil, :name => :name}])
|
33
|
-
end
|
34
|
-
end
|
27
|
+
it_behaves_like "inputs must have descriptions"
|
35
28
|
end
|
36
29
|
|
37
|
-
describe "#
|
30
|
+
describe "#push" do
|
38
31
|
let(:app) { build(:app, :client => client, :name => "app-name-1") }
|
39
32
|
|
40
33
|
before do
|
41
34
|
app.stub(:upload)
|
42
35
|
app.changes = {}
|
43
36
|
push.stub(:warn)
|
37
|
+
client.stub(:app_by_name).and_return(app)
|
44
38
|
end
|
45
39
|
|
46
|
-
|
47
|
-
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
48
|
-
push.sync_app(app, path)
|
49
|
-
end
|
40
|
+
let(:inputs) { {} }
|
50
41
|
|
51
|
-
|
42
|
+
shared_examples_for "an input" do |*args|
|
52
43
|
context "when the new input is the same as the old" do
|
53
44
|
type, input = args
|
54
45
|
input ||= type
|
@@ -58,19 +49,36 @@ module CF
|
|
58
49
|
it "does not update the app's #{type}" do
|
59
50
|
push.should_not_receive(:line)
|
60
51
|
app.should_not_receive(:update!)
|
61
|
-
expect
|
52
|
+
expect do
|
53
|
+
push.input = Mothership::Inputs.new(Mothership.commands[:push], push, inputs, {}, global)
|
54
|
+
push.push
|
55
|
+
end.not_to change { app.send(type) }
|
62
56
|
end
|
63
57
|
end
|
64
58
|
end
|
65
59
|
|
66
60
|
it "triggers the :push_app filter" do
|
67
61
|
push.should_receive(:filter).with(:push_app, app) { app }
|
68
|
-
|
62
|
+
push.input = Mothership::Inputs.new(Mothership.commands[:push], push, inputs, {}, global)
|
63
|
+
push.push
|
69
64
|
end
|
70
65
|
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
describe 'uploading the app from the correct path' do
|
67
|
+
context 'when the user does not specify a path' do
|
68
|
+
it 'uploads the app' do
|
69
|
+
app.should_receive(:upload).with(File.expand_path('.'))
|
70
|
+
push.input = Mothership::Inputs.new(Mothership.commands[:push], push, {}, {}, global)
|
71
|
+
push.push
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when the user specifies a path' do
|
76
|
+
it 'uploads the app' do
|
77
|
+
app.should_receive(:upload).with(path)
|
78
|
+
push.input = Mothership::Inputs.new(Mothership.commands[:push], push, {:path => path}, {}, global)
|
79
|
+
push.push
|
80
|
+
end
|
81
|
+
end
|
74
82
|
end
|
75
83
|
|
76
84
|
context "when the app is stopped" do
|
@@ -80,21 +88,24 @@ module CF
|
|
80
88
|
|
81
89
|
it "warns the user" do
|
82
90
|
push.should_receive(:warn).with("\n#{app.name} is currently stopped, start it with 'cf start'")
|
83
|
-
|
91
|
+
push.input = Mothership::Inputs.new(nil, push, {:path => path}, {}, global)
|
92
|
+
push.push
|
84
93
|
end
|
85
94
|
end
|
86
95
|
|
87
|
-
context "when no inputs are given" do
|
88
|
-
let(:inputs) { {} }
|
96
|
+
context "when no inputs other than path are given" do
|
97
|
+
let(:inputs) { {:path => ""} }
|
89
98
|
|
90
99
|
it "should not update the app" do
|
91
100
|
app.should_not_receive(:update!)
|
92
|
-
|
101
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
102
|
+
push.push
|
93
103
|
end
|
94
104
|
|
95
105
|
it "should not set memory on the app" do
|
96
106
|
app.should_not_receive(:memory=)
|
97
|
-
|
107
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
108
|
+
push.push
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
@@ -102,93 +113,116 @@ module CF
|
|
102
113
|
let(:old) { 1024 }
|
103
114
|
let(:new) { "2G" }
|
104
115
|
let(:app) { build(:app, :memory => old) }
|
105
|
-
let(:inputs) { {:memory => new} }
|
116
|
+
let(:inputs) { {:path => path, :memory => new} }
|
106
117
|
|
107
118
|
it "updates the app memory, converting to megabytes" do
|
108
119
|
push.stub(:line)
|
109
120
|
app.should_receive(:update!)
|
110
|
-
expect {
|
121
|
+
expect { push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
122
|
+
push.push }.to change { app.memory }.from(old).to(2048)
|
111
123
|
end
|
112
124
|
|
113
125
|
it "outputs the changed memory in human readable sizes" do
|
114
126
|
push.should_receive(:line).with("Changes:")
|
115
127
|
push.should_receive(:line).with("memory: 1G -> 2G")
|
116
128
|
app.stub(:update!)
|
117
|
-
|
129
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
130
|
+
push.push
|
118
131
|
end
|
119
132
|
|
120
|
-
|
133
|
+
it_behaves_like "an input", :memory
|
121
134
|
end
|
122
135
|
|
123
136
|
context "when instances is given" do
|
124
137
|
let(:old) { 1 }
|
125
138
|
let(:new) { 2 }
|
126
139
|
let(:app) { build(:app, :total_instances => old) }
|
127
|
-
let(:inputs) { {:instances => new} }
|
140
|
+
let(:inputs) { {:path => path, :instances => new} }
|
128
141
|
|
129
142
|
it "updates the app instances" do
|
130
143
|
push.stub(:line)
|
131
144
|
app.stub(:update!)
|
132
|
-
expect
|
145
|
+
expect do
|
146
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
147
|
+
push.push
|
148
|
+
end.to change { app.total_instances }.from(old).to(new)
|
133
149
|
end
|
134
150
|
|
135
151
|
it "outputs the changed instances" do
|
136
152
|
push.should_receive(:line).with("Changes:")
|
137
153
|
push.should_receive(:line).with("total_instances: 1 -> 2")
|
138
154
|
app.stub(:update!)
|
139
|
-
|
155
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
156
|
+
push.push
|
140
157
|
end
|
141
158
|
|
142
|
-
|
159
|
+
it_behaves_like "an input", :total_instances, :instances
|
143
160
|
end
|
144
161
|
|
145
162
|
context "when command is given" do
|
146
163
|
let(:old) { "./start" }
|
147
164
|
let(:new) { "./start foo " }
|
148
165
|
let(:app) { build(:app, :command => old) }
|
149
|
-
let(:inputs) { {:command => new} }
|
166
|
+
let(:inputs) { {:path => path, :command => new} }
|
150
167
|
|
151
168
|
it "updates the app command" do
|
152
169
|
push.stub(:line)
|
153
170
|
app.should_receive(:update!)
|
154
|
-
expect
|
171
|
+
expect do
|
172
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
173
|
+
push.push
|
174
|
+
end.to change { app.command }.from("./start").to("./start foo ")
|
155
175
|
end
|
156
176
|
|
157
177
|
it "outputs the changed command in single quotes" do
|
158
178
|
push.should_receive(:line).with("Changes:")
|
159
179
|
push.should_receive(:line).with("command: './start' -> './start foo '")
|
160
180
|
app.stub(:update!)
|
161
|
-
|
181
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
182
|
+
push.push
|
162
183
|
end
|
163
184
|
|
164
|
-
|
185
|
+
it_behaves_like "an input", :command
|
165
186
|
end
|
166
187
|
|
167
188
|
context "when restart is given" do
|
168
|
-
let(:inputs) { {:restart => true, :memory => 4096} }
|
189
|
+
let(:inputs) { {:path => path, :restart => true, :memory => 4096} }
|
190
|
+
|
191
|
+
let(:mock_restart_command) do
|
192
|
+
MockRestartCommand.new
|
193
|
+
end
|
169
194
|
|
170
195
|
before do
|
171
196
|
CF::App::Base.any_instance.stub(:human_mb).and_return(0)
|
197
|
+
Restart.stub(:new).and_return(mock_restart_command)
|
172
198
|
end
|
173
199
|
|
174
200
|
context "when the app is already started" do
|
175
201
|
let(:app) { build(:app, :state => "STARTED") }
|
176
202
|
|
177
|
-
it "
|
203
|
+
it "restarts the app after updating" do
|
178
204
|
push.stub(:line)
|
179
|
-
app.should_receive(:update!)
|
180
|
-
|
181
|
-
|
205
|
+
app.should_receive(:update!) do
|
206
|
+
expect(mock_restart_command.restarted_apps).to be_empty
|
207
|
+
end
|
208
|
+
|
209
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
210
|
+
push.push
|
211
|
+
|
212
|
+
expect(mock_restart_command.restarted_apps).to eq [app]
|
182
213
|
end
|
183
214
|
|
184
215
|
context "but there are no changes" do
|
185
|
-
let(:inputs) { {:restart => true} }
|
216
|
+
let(:inputs) { {:path => path, :restart => true} }
|
186
217
|
|
187
|
-
it "
|
218
|
+
it "restarts the app without updating" do
|
188
219
|
push.stub(:line)
|
189
220
|
app.should_not_receive(:update!)
|
190
|
-
|
191
|
-
|
221
|
+
|
222
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
223
|
+
push.push
|
224
|
+
|
225
|
+
mock_restart_command.restarted_apps.should == [app]
|
192
226
|
end
|
193
227
|
end
|
194
228
|
end
|
@@ -196,11 +230,14 @@ module CF
|
|
196
230
|
context "when the app is not already started" do
|
197
231
|
let(:app) { build(:app, :state => "STOPPED") }
|
198
232
|
|
199
|
-
it "
|
233
|
+
it "updates the app without restarting" do
|
200
234
|
push.stub(:line)
|
201
235
|
app.should_receive(:update!)
|
202
|
-
|
203
|
-
|
236
|
+
|
237
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
238
|
+
push.push
|
239
|
+
|
240
|
+
expect(mock_restart_command.restarted_apps).to be_empty
|
204
241
|
end
|
205
242
|
end
|
206
243
|
end
|
@@ -208,7 +245,7 @@ module CF
|
|
208
245
|
context "when buildpack is given" do
|
209
246
|
let(:old) { nil }
|
210
247
|
let(:app) { build(:app, :buildpack => old) }
|
211
|
-
let(:inputs) { {:buildpack => new} }
|
248
|
+
let(:inputs) { {:path => path, :buildpack => new} }
|
212
249
|
|
213
250
|
context "and it's an invalid URL" do
|
214
251
|
let(:new) { "git@github.com:foo/bar.git" }
|
@@ -216,15 +253,18 @@ module CF
|
|
216
253
|
before do
|
217
254
|
app.stub(:update!) do
|
218
255
|
raise CFoundry::MessageParseError.new(
|
219
|
-
|
220
|
-
|
256
|
+
"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/",
|
257
|
+
1001)
|
221
258
|
end
|
222
259
|
end
|
223
260
|
|
224
261
|
it "fails and prints a pretty message" do
|
225
262
|
push.stub(:line)
|
226
|
-
expect
|
227
|
-
|
263
|
+
expect do
|
264
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
265
|
+
push.push
|
266
|
+
end.to raise_error(
|
267
|
+
CF::UserError, "Buildpack must be a public git repository URI.")
|
228
268
|
end
|
229
269
|
end
|
230
270
|
|
@@ -234,17 +274,21 @@ module CF
|
|
234
274
|
it "updates the app's buildpack" do
|
235
275
|
push.stub(:line)
|
236
276
|
app.should_receive(:update!)
|
237
|
-
expect
|
277
|
+
expect do
|
278
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
279
|
+
push.push
|
280
|
+
end.to change { app.buildpack }.from(old).to(new)
|
238
281
|
end
|
239
282
|
|
240
283
|
it "outputs the changed buildpack with single quotes" do
|
241
284
|
push.should_receive(:line).with("Changes:")
|
242
285
|
push.should_receive(:line).with("buildpack: '' -> '#{new}'")
|
243
286
|
app.stub(:update!)
|
244
|
-
|
287
|
+
push.input = Mothership::Inputs.new(nil, push, inputs, {}, global)
|
288
|
+
push.push
|
245
289
|
end
|
246
290
|
|
247
|
-
|
291
|
+
it_behaves_like "an input", :buildpack
|
248
292
|
end
|
249
293
|
end
|
250
294
|
end
|
@@ -254,11 +298,11 @@ module CF
|
|
254
298
|
let(:host) { "" }
|
255
299
|
let(:domain) { build(:domain) }
|
256
300
|
let(:inputs) do
|
257
|
-
{
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
301
|
+
{:name => "some-app",
|
302
|
+
:instances => 2,
|
303
|
+
:memory => 1024,
|
304
|
+
:host => host,
|
305
|
+
:domain => domain
|
262
306
|
}
|
263
307
|
end
|
264
308
|
let(:global) { {:quiet => true, :color => false, :force => true} }
|
@@ -66,7 +66,7 @@ module CF
|
|
66
66
|
before do
|
67
67
|
app.stub(:instances) do
|
68
68
|
[CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "DOWN"),
|
69
|
-
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "
|
69
|
+
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "DOWN")
|
70
70
|
]
|
71
71
|
end
|
72
72
|
|
@@ -75,10 +75,10 @@ module CF
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
context "when
|
78
|
+
context "when one instance becomes running" do
|
79
79
|
let(:final_instances) do
|
80
80
|
[CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "RUNNING"),
|
81
|
-
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "
|
81
|
+
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "DOWN")
|
82
82
|
]
|
83
83
|
end
|
84
84
|
|
@@ -86,7 +86,7 @@ module CF
|
|
86
86
|
execute_start_app
|
87
87
|
expect(output).to say("Checking status of app '#{app.name}'...")
|
88
88
|
expect(output).to say("1 running, 1 down")
|
89
|
-
expect(output).to say("
|
89
|
+
expect(output).to say("Push successful!")
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -122,17 +122,19 @@ module CF
|
|
122
122
|
end
|
123
123
|
|
124
124
|
context "when any instance becomes flapping" do
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
before do
|
126
|
+
app.stub(:instances) do
|
127
|
+
[
|
128
|
+
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "FLAPPING"),
|
129
|
+
CFoundry::V2::App::Instance.new(nil, nil, nil, :state => "DOWN"),
|
130
|
+
]
|
131
|
+
end
|
129
132
|
end
|
130
133
|
|
131
134
|
it "says app failed to start" do
|
132
135
|
execute_start_app
|
133
136
|
expect(output).to say("Checking status of app '#{app.name}'...")
|
134
|
-
expect(output).to say("1
|
135
|
-
expect(output).to say("1 starting, 1 flapping")
|
137
|
+
expect(output).to say("1 crashing, 1 down")
|
136
138
|
expect(error_output).to say("Push unsuccessful.")
|
137
139
|
end
|
138
140
|
end
|
data/spec/cf/cli_spec.rb
CHANGED
@@ -58,11 +58,6 @@ module CF
|
|
58
58
|
subject
|
59
59
|
end
|
60
60
|
|
61
|
-
it "does mention ~/.cf/crash" do
|
62
|
-
subject
|
63
|
-
expect(stderr.string).to include CF::CRASH_FILE
|
64
|
-
end
|
65
|
-
|
66
61
|
it "logs the error" do
|
67
62
|
context.should_receive(:log_error).with(anything)
|
68
63
|
subject
|
@@ -145,16 +140,13 @@ module CF
|
|
145
140
|
end
|
146
141
|
|
147
142
|
context "with an arbitrary exception" do
|
148
|
-
let(:
|
149
|
-
|
150
|
-
it "logs the error" do
|
151
|
-
context.should_receive(:log_error).with(anything)
|
152
|
-
subject
|
153
|
-
end
|
143
|
+
let(:error) { RuntimeError.new("ahhhh it's all broken!!!!") }
|
144
|
+
let(:action) { proc { raise error } }
|
154
145
|
|
155
146
|
it "prints the message" do
|
156
147
|
subject
|
157
|
-
expect(stderr.string).to include "RuntimeError:
|
148
|
+
expect(stderr.string).to include "RuntimeError: ahhhh it's all broken!!!!"
|
149
|
+
expect(stderr.string).to include "spec/cf/cli_spec.rb" #to check that we're printing the backtrace
|
158
150
|
end
|
159
151
|
|
160
152
|
it "sets the exit code to 1" do
|
@@ -162,11 +154,6 @@ module CF
|
|
162
154
|
subject
|
163
155
|
end
|
164
156
|
|
165
|
-
it "tells the user to check ~/.cf/crash" do
|
166
|
-
subject
|
167
|
-
expect(stderr.string).to include CF::CRASH_FILE
|
168
|
-
end
|
169
|
-
|
170
157
|
context "when we are debugging" do
|
171
158
|
let(:inputs) { {:debug => true} }
|
172
159
|
|