manifests-cf-plugin 0.7.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.
@@ -0,0 +1,365 @@
1
+ require "spec_helper"
2
+
3
+ require "manifests-cf-plugin/plugin"
4
+
5
+
6
+ describe ManifestsPlugin do
7
+ let(:manifest) { {} }
8
+ let(:manifest_file) { nil }
9
+ let(:inputs_hash) { {} }
10
+ let(:given_hash) { {} }
11
+ let(:global_hash) { { :quiet => true } }
12
+ let(:command) { nil }
13
+ let(:inputs) { Mothership::Inputs.new(Mothership.commands[:push], nil, inputs_hash, given_hash, global_hash) }
14
+ let(:plugin) { ManifestsPlugin.new(command, inputs) }
15
+
16
+ let(:client) { fake_client }
17
+
18
+ before do
19
+ stub(plugin).manifest { manifest }
20
+ stub(plugin).manifest_file { manifest_file } if manifest_file
21
+ stub(plugin).client { client }
22
+ end
23
+
24
+ describe "#wrap_with_optional_name" do
25
+ let(:name_made_optional) { true }
26
+ let(:wrapped) { mock! }
27
+
28
+ subject { plugin.send(:wrap_with_optional_name, name_made_optional, wrapped, inputs) }
29
+
30
+ context "when --all is given" do
31
+ let(:inputs_hash) { { :all => true } }
32
+
33
+ it "skips all manifest-related logic, and invokes the command" do
34
+ mock(wrapped).call
35
+ dont_allow(plugin).show_manifest_usage
36
+ subject
37
+ end
38
+ end
39
+
40
+ context "when there is no manifest" do
41
+ let(:manifest) { nil }
42
+
43
+ context "and an app is given" do
44
+ let(:given_hash) { { :app => "foo" } }
45
+
46
+ it "passes through to the command" do
47
+ mock(wrapped).call
48
+ dont_allow(plugin).show_manifest_usage
49
+ subject
50
+ end
51
+ end
52
+
53
+ context "and an app is NOT given" do
54
+ let(:inputs_hash) { {} }
55
+
56
+ context "and we made it optional" do
57
+ it "fails manually" do
58
+ mock(plugin).no_apps
59
+ subject
60
+ end
61
+ end
62
+
63
+ context "and we did NOT make it optional" do
64
+ let(:name_made_optional) { false }
65
+
66
+ it "passes through to the command" do
67
+ mock(wrapped).call
68
+ dont_allow(plugin).show_manifest_usage
69
+ subject
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ context "when there is a manifest" do
76
+ let(:manifest_file) { "/abc/manifest.yml" }
77
+
78
+ before do
79
+ stub(plugin).show_manifest_usage
80
+ end
81
+
82
+ context "when no apps are given" do
83
+ context "and the user's working directory matches a particular app in the manifest" do
84
+ let(:manifest) { { :applications => [{ :name => "foo", :path => "/abc/foo" }] } }
85
+
86
+ it "calls the command for only that app" do
87
+ mock(wrapped).call(anything) do |inputs|
88
+ expect(inputs.given[:app]).to eq "foo"
89
+ end
90
+
91
+ stub(Dir).pwd { "/abc/foo" }
92
+
93
+ subject
94
+ end
95
+ end
96
+
97
+ context "and the user's working directory isn't in the manifest" do
98
+ let(:manifest) { { :applications => [{ :name => "foo" }, { :name => "bar" }] } }
99
+
100
+ it "calls the command for all apps in the manifest" do
101
+ uncalled_apps = ["foo", "bar"]
102
+ mock(wrapped).call(anything).twice do |inputs|
103
+ uncalled_apps.delete inputs.given[:app]
104
+ end
105
+
106
+ subject
107
+
108
+ expect(uncalled_apps).to be_empty
109
+ end
110
+ end
111
+ end
112
+
113
+ context "when any of the given apps are not in the manifest" do
114
+ let(:manifest) { { :applications => [{ :name => "a" }, { :name => "b" }] } }
115
+
116
+ context "and --apps is given" do
117
+ let(:given_hash) { { :apps => ["x", "a"] } }
118
+
119
+ it "passes through to the original command" do
120
+ mock(plugin).show_manifest_usage
121
+
122
+ uncalled_apps = ["a", "x"]
123
+ mock(wrapped).call(anything).twice do |inputs|
124
+ uncalled_apps.delete inputs.given[:app]
125
+ end
126
+
127
+ subject
128
+
129
+ expect(uncalled_apps).to be_empty
130
+ subject
131
+ end
132
+ end
133
+ end
134
+
135
+ context "when none of the given apps are in the manifest" do
136
+ let(:manifest) { { :applications => [{ :name => "a" }, { :name => "b" }] } }
137
+
138
+ context "and --apps is given" do
139
+ let(:given_hash) { { :apps => ["x", "y"] } }
140
+
141
+ it "passes through to the original command" do
142
+ dont_allow(plugin).show_manifest_usage
143
+ mock(wrapped).call
144
+ subject
145
+ end
146
+ end
147
+ end
148
+
149
+ context "when an app name that's in the manifest is given" do
150
+ let(:manifest) { { :applications => [{ :name => "foo" }] } }
151
+ let(:given_hash) { { :app => "foo" } }
152
+
153
+ it "calls the command with that app" do
154
+ mock(wrapped).call(anything) do |inputs|
155
+ expect(inputs.given[:app]).to eq "foo"
156
+ end
157
+
158
+ subject
159
+ end
160
+ end
161
+
162
+ context "when a path to an app that's in the manifest is given" do
163
+ let(:manifest) { { :applications => [{ :name => "foo", :path => "/abc/foo" }] } }
164
+ let(:given_hash) { { :app => "/abc/foo" } }
165
+
166
+ it "calls the command with that app" do
167
+ mock(wrapped).call(anything) do |inputs|
168
+ expect(inputs.given[:app]).to eq "foo"
169
+ end
170
+
171
+ subject
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ describe "#wrap_push" do
178
+ let(:wrapped) { mock! }
179
+ let(:command) { Mothership.commands[:push] }
180
+
181
+ subject { plugin.send(:wrap_push, wrapped, inputs) }
182
+
183
+ before do
184
+ stub(plugin).show_manifest_usage
185
+ end
186
+
187
+ context "with a manifest" do
188
+ let(:manifest_file) { "/abc/manifest.yml" }
189
+
190
+ let(:manifest) do
191
+ { :applications => [
192
+ { :name => "a",
193
+ :path => "/abc/a",
194
+ :instances => "200",
195
+ :memory => "128M"
196
+ }
197
+ ]
198
+ }
199
+ end
200
+
201
+ # cf push foo
202
+ context "and a name is given" do
203
+ context "and the name is present in the manifest" do
204
+ let(:given_hash) { { :name => "a" } }
205
+
206
+ context "and the app exists" do
207
+ let(:app) { fake :app, :name => "a" }
208
+ let(:client) { fake_client :apps => [app] }
209
+
210
+ context "and --reset was given" do
211
+ let(:inputs_hash) { { :reset => true } }
212
+ let(:given_hash) { { :name => "a", :instances => "100" } }
213
+
214
+ it "rebases their inputs on the manifest's values" do
215
+ mock(wrapped).call(anything) do |inputs|
216
+ expect(inputs.given).to eq(
217
+ :name => "a", :path => "/abc/a", :instances => "100", :memory => "128M")
218
+ end
219
+
220
+ subject
221
+ end
222
+ end
223
+ end
224
+
225
+ context "and the app does NOT exist" do
226
+ it "pushes a new app with the inputs from the manifest" do
227
+ mock(wrapped).call(anything) do |inputs|
228
+ expect(inputs.given).to eq(
229
+ :name => "a", :path => "/abc/a", :instances => "200", :memory => "128M")
230
+ end
231
+
232
+ subject
233
+ end
234
+ end
235
+ end
236
+
237
+ context "and the name is NOT present in the manifest" do
238
+ let(:given_hash) { { :name => "x" } }
239
+
240
+ it "fails, saying that name was not found in the manifest" do
241
+ expect { subject }.to raise_error(CF::UserError, /Could not find .+ in the manifest./)
242
+ end
243
+ end
244
+ end
245
+
246
+ # cf push ./abc
247
+ context "and a path is given" do
248
+ context "and there are apps matching that path in the manifest" do
249
+ let(:manifest) do
250
+ { :applications => [
251
+ { :name => "a",
252
+ :path => "/abc/a",
253
+ :instances => "200",
254
+ :memory => "128M"
255
+ },
256
+ { :name => "b",
257
+ :path => "/abc/a",
258
+ :instances => "200",
259
+ :memory => "128M"
260
+ }
261
+ ]
262
+ }
263
+ end
264
+
265
+ let(:given_hash) { { :name => "/abc/a" } }
266
+
267
+ it "pushes the found apps" do
268
+ pushed_apps = []
269
+ mock(wrapped).call(anything).twice do |inputs|
270
+ pushed_apps << inputs[:name]
271
+ end
272
+
273
+ subject
274
+
275
+ expect(pushed_apps).to eq(["a", "b"])
276
+ end
277
+ end
278
+
279
+ context "and there are NOT apps matching that path in the manifest" do
280
+ let(:given_hash) { { :name => "/abc/x" } }
281
+
282
+ it "fails, saying that the path was not found in the manifest" do
283
+ expect { subject }.to raise_error(CF::UserError, /Path .+ is not present in manifest/)
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ context "without a manifest" do
290
+ let(:app) { mock! }
291
+ let(:manifest) { nil }
292
+
293
+ it "asks to save the manifest when uploading the application" do
294
+ mock_ask("Save configuration?", :default => false)
295
+ stub(wrapped).call { plugin.filter(:push_app, app) }
296
+ subject
297
+ end
298
+ end
299
+ end
300
+
301
+ describe "#push_input_for" do
302
+ context "with an existing app" do
303
+ before do
304
+ stub(plugin).from_manifest { "PATH" }
305
+ app.changes.clear
306
+ end
307
+
308
+ let(:client) { fake_client(:apps => [app]) }
309
+ let(:manifest_memory) { "256M" }
310
+ let(:app) { fake :app, :name => "a", :memory => 256 }
311
+ let(:manifest) { { :name => "a", :memory => manifest_memory } }
312
+
313
+ subject { plugin.send(:push_input_for, manifest, inputs) }
314
+
315
+ context "with --reset" do
316
+ let(:inputs_hash) { { :reset => true } }
317
+
318
+ context "with changes" do
319
+ let(:manifest_memory) { "128M" }
320
+
321
+ it "applies the changes" do
322
+ subject[:memory].should == "128M"
323
+ end
324
+
325
+ it "does not ask to set --reset" do
326
+ dont_allow(plugin).warn_reset_changes
327
+ subject
328
+ end
329
+ end
330
+
331
+ context "without changes" do
332
+ it "does not ask to set --reset" do
333
+ dont_allow(plugin).warn_reset_changes
334
+ subject
335
+ end
336
+ end
337
+ end
338
+
339
+ context "without --reset" do
340
+ let(:inputs_hash) { {} }
341
+
342
+ context "with changes" do
343
+ let(:manifest_memory) { "128M" }
344
+
345
+ it "asks user to provide --reset" do
346
+ mock(plugin).warn_reset_changes
347
+ subject
348
+ end
349
+
350
+ it "does not apply changes" do
351
+ stub(plugin).warn_reset_changes
352
+ subject[:memory].should == nil
353
+ end
354
+ end
355
+
356
+ context "without changes" do
357
+ it "does not ask to set --reset" do
358
+ dont_allow(plugin).warn_reset_changes
359
+ subject
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
@@ -0,0 +1,321 @@
1
+ require 'spec_helper'
2
+ require 'manifests-cf-plugin'
3
+
4
+ describe CFManifests do
5
+ let(:inputs_hash) { {} }
6
+ let(:given_hash) { {} }
7
+ let(:global_hash) { {} }
8
+ let(:inputs) { Mothership::Inputs.new(nil, nil, inputs_hash, given_hash, global_hash) }
9
+
10
+ let(:cmd) do
11
+ manifest = CF::App::Push.new(nil, inputs)
12
+ manifest.extend CFManifests
13
+ stub(manifest).client { client }
14
+ manifest
15
+ end
16
+
17
+ let(:target_base) { "some-cloud.com" }
18
+
19
+ let(:foo) { fake(:app, :name => "foo") }
20
+ let(:bar) { fake(:app, :name => "bar") }
21
+ let(:baz) { fake(:app, :name => "baz") }
22
+ let(:xxx) { fake(:app, :name => "xxx") }
23
+ let(:yyy) { fake(:app, :name => "yyy") }
24
+
25
+ let(:client) do
26
+ fake_client :apps => [foo, bar, baz, xxx, yyy]
27
+ end
28
+
29
+ let(:manifest_file) { "/abc/manifest.yml" }
30
+
31
+ before do
32
+ stub(cmd).target_base { target_base }
33
+ stub(cmd).v2? { true }
34
+
35
+ stub(cmd).manifest { manifest }
36
+ stub(cmd).manifest_file { manifest_file }
37
+ end
38
+
39
+ describe '#find_apps' do
40
+ subject { cmd.find_apps(nil) }
41
+
42
+ context 'when there is no manifest file' do
43
+ before { stub(cmd).manifest { nil } }
44
+ it { should eq [] }
45
+ end
46
+ end
47
+
48
+ describe '#create_manifest_for' do
49
+ let(:app) {
50
+ fake :app,
51
+ :framework => fake(:framework),
52
+ :runtime => fake(:runtime),
53
+ :memory => 2048,
54
+ :total_instances => 2,
55
+ :command => "ruby main.rb",
56
+ :buildpack => "git://example.com/foo.git",
57
+ :routes => [
58
+ fake(:route,
59
+ :host => "some-app-name",
60
+ :domain => fake(:domain, :name => target_base))
61
+ ],
62
+ :service_bindings => [
63
+ fake(
64
+ :service_binding,
65
+ :service_instance =>
66
+ fake(
67
+ :service_instance,
68
+ :name => "service-1",
69
+ :service_plan =>
70
+ fake(
71
+ :service_plan,
72
+ :name => "P200",
73
+ :service => fake(:service))))
74
+ ]
75
+ }
76
+
77
+ subject { cmd.create_manifest_for(app, "some-path") }
78
+
79
+ its(["name"]) { should eq app.name }
80
+ its(["framework"]) { should eq app.framework.name }
81
+ its(["runtime"]) { should eq app.runtime.name }
82
+ its(["memory"]) { should eq "2G" }
83
+ its(["instances"]) { should eq 2 }
84
+ its(["path"]) { should eq "some-path" }
85
+ its(["url"]) { should eq "some-app-name.${target-base}" }
86
+ its(["command"]) { should eq "ruby main.rb" }
87
+ its(["buildpack"]) { should eq "git://example.com/foo.git" }
88
+
89
+ it "contains the service information" do
90
+ expect(subject["services"]).to be_a Hash
91
+
92
+ services = subject["services"]
93
+ app.service_bindings.each do |b|
94
+ service = b.service_instance
95
+
96
+ expect(services).to include service.name
97
+
98
+ info = services[service.name]
99
+
100
+ plan = service.service_plan
101
+ offering = plan.service
102
+
103
+ { "plan" => plan.name,
104
+ "label" => offering.label,
105
+ "provider" => offering.provider,
106
+ "version" => offering.version
107
+ }.each do |attr, val|
108
+ expect(info).to include attr
109
+ expect(info[attr]).to eq val
110
+ end
111
+ end
112
+ end
113
+
114
+ context 'when there is no url' do
115
+ let(:app) {
116
+ fake :app,
117
+ :framework => fake(:framework),
118
+ :runtime => fake(:runtime),
119
+ :memory => 2048,
120
+ :total_instances => 2
121
+ }
122
+
123
+ its(["url"]) { should eq "none" }
124
+ end
125
+
126
+ context 'when there is no command' do
127
+ let(:app) {
128
+ fake :app,
129
+ :framework => fake(:framework),
130
+ :runtime => fake(:runtime),
131
+ :memory => 2048,
132
+ :total_instances => 2
133
+ }
134
+
135
+ it { should_not include "command" }
136
+ end
137
+
138
+ context 'when there are no service bindings' do
139
+ let(:app) {
140
+ fake :app,
141
+ :framework => fake(:framework),
142
+ :runtime => fake(:runtime),
143
+ :memory => 2048,
144
+ :total_instances => 2
145
+ }
146
+
147
+ it { should_not include "services" }
148
+ end
149
+ end
150
+
151
+ describe "#setup_services" do
152
+ let(:service_bindings) { [] }
153
+ let(:app) { fake :app, :service_bindings => service_bindings }
154
+
155
+ before do
156
+ dont_allow_ask(anything, anything)
157
+ end
158
+
159
+ context "when services are defined in the manifest" do
160
+ let(:info) {
161
+ { :services => { "service-1" => { :label => "mysql", :plan => "100" } } }
162
+ }
163
+
164
+ let(:service_1) { fake(:service_instance, :name => "service-1") }
165
+
166
+ let(:plan_100) { fake :service_plan, :name => "100" }
167
+
168
+ let(:mysql) {
169
+ fake(
170
+ :service,
171
+ :label => "mysql",
172
+ :provider => "core",
173
+ :service_plans => [plan_100])
174
+ }
175
+
176
+ let(:service_instances) { [] }
177
+
178
+ let(:client) {
179
+ fake_client :services => [mysql], :service_instances => service_instances
180
+ }
181
+
182
+ context "and the services exist" do
183
+ let(:service_instances) { [service_1] }
184
+
185
+ context "and are already bound" do
186
+ let(:service_bindings) { [fake(:service_binding, :service_instance => service_1)] }
187
+
188
+ it "does neither create nor bind the service again" do
189
+ dont_allow(cmd).invoke :create_service, anything
190
+ dont_allow(cmd).invoke :bind_service, anything
191
+ cmd.send(:setup_services, app, info)
192
+ end
193
+ end
194
+
195
+ context "but are not bound" do
196
+ it "does not create the services" do
197
+ dont_allow(cmd).invoke :create_service, anything
198
+ stub(cmd).invoke :bind_service, anything
199
+ cmd.send(:setup_services, app, info)
200
+ end
201
+
202
+ it "binds the service" do
203
+ mock(cmd).invoke :bind_service, :app => app, :service => service_1
204
+ cmd.send(:setup_services, app, info)
205
+ end
206
+ end
207
+ end
208
+
209
+ context "and the services do not exist" do
210
+ it "creates the services" do
211
+ mock(cmd).invoke :create_service, :app => app,
212
+ :name => service_1.name, :offering => mysql, :plan => plan_100
213
+ dont_allow(cmd).invoke :bind_service, anything
214
+ cmd.send(:setup_services, app, info)
215
+ end
216
+ end
217
+ end
218
+
219
+ context "when there are no services defined" do
220
+ let(:info) { {} }
221
+
222
+ it "does not ask anything" do
223
+ cmd.send(:setup_services, app, info)
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "#apps_in_manifest" do
229
+ let(:foo_hash) { { :name => "foo", :path => "/abc/foo" } }
230
+ let(:bar_hash) { { :name => "bar", :path => "/abc/bar" } }
231
+ let(:baz_hash) { { :name => "baz", :path => "/abc/baz" } }
232
+
233
+ let(:manifest) { { :applications => [foo_hash, bar_hash, baz_hash] } }
234
+
235
+ subject { cmd.apps_in_manifest(inputs) }
236
+
237
+ context "when no apps are passed" do
238
+ let(:given_hash) { {} }
239
+
240
+ its(:first) { should eq [] }
241
+ its(:last) { should eq [] }
242
+ end
243
+
244
+ context "when app names are passed" do
245
+ context "and all of them are in the manifest" do
246
+ let(:given_hash) { { :apps => ["foo", "bar"] } }
247
+
248
+ its(:first) { should eq [foo_hash, bar_hash] }
249
+ its(:last) { should eq [] }
250
+ end
251
+
252
+ context "and one of them is in the manifest" do
253
+ let(:given_hash) { { :apps => ["foo", "xxx"] } }
254
+
255
+ its(:first) { should eq [foo_hash] }
256
+ its(:last) { should eq ["xxx"] }
257
+ end
258
+
259
+ context "and none of them are in the manifest" do
260
+ let(:given_hash) { { :apps => ["xxx", "yyy"] } }
261
+
262
+ its(:first) { should eq [] }
263
+ its(:last) { should eq ["xxx", "yyy"] }
264
+ end
265
+ end
266
+
267
+ context "when apps are passed as paths" do
268
+ context "and the paths are in the manifest" do
269
+ let(:given_hash) { { :apps => ["/abc/foo"] } }
270
+
271
+ its(:first) { should eq [foo_hash] }
272
+ its(:last) { should eq [] }
273
+ end
274
+
275
+ context "and any path is not in the manifest" do
276
+ let(:given_hash) { { :apps => ["/abc/xxx"] } }
277
+
278
+ it "fails with a manifest-specific method (i.e. path not in manifest)" do
279
+ expect { subject }.to raise_error(CF::UserError, /Path .+ is not present in manifest/)
280
+ end
281
+ end
282
+ end
283
+ end
284
+
285
+ describe "#all_apps" do
286
+ let(:applications) do
287
+ [
288
+ {:name => "foo", :path => "/abc"},
289
+ {:name => "bar", :path => "/abc"},
290
+ {:name => "baz", :path => "/abc/baz"}
291
+ ]
292
+ end
293
+
294
+ let(:manifest) do
295
+ { :applications => applications }
296
+ end
297
+
298
+ subject { cmd.all_apps }
299
+
300
+ it "returns all of the apps described in the manifest, as hashes" do
301
+ expect(subject).to eq applications
302
+ end
303
+ end
304
+
305
+ describe "#current_apps" do
306
+ let(:manifest) do
307
+ {:applications => [
308
+ {:name => "foo", :path => "/abc"},
309
+ {:name => "bar", :path => "/abc"},
310
+ {:name => "baz", :path => "/abc/baz"}
311
+ ]}
312
+ end
313
+
314
+ subject { cmd.current_apps }
315
+
316
+ it "returns the applications with the cwd as their path" do
317
+ stub(Dir).pwd { "/abc" }
318
+ expect(subject).to eq [{ :name => "foo", :path => "/abc"}, { :name => "bar", :path => "/abc" }]
319
+ end
320
+ end
321
+ end