static 1.0.1 → 1.0.3

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,3 @@
1
+ module VMCManifests
2
+ VERSION = "0.6.2".freeze
3
+ end
@@ -0,0 +1,176 @@
1
+ require "spec_helper"
2
+
3
+ require "manifests-vmc-plugin/loader"
4
+
5
+
6
+ describe VMCManifests::Normalizer do
7
+ let(:manifest) { {} }
8
+ let(:loader) { VMCManifests::Loader.new(nil, nil) }
9
+
10
+ describe '#normalize!' do
11
+ subject do
12
+ loader.normalize!(manifest)
13
+ manifest
14
+ end
15
+
16
+ context 'with a manifest where the applications have no path set' do
17
+ let(:manifest) { { "applications" => { "." => { "name" => "foo" } } } }
18
+
19
+ it "sets the path to their tag, assuming it's a path" do
20
+ expect(subject).to eq(
21
+ :applications => [{ :name => "foo", :path => "." }])
22
+ end
23
+ end
24
+
25
+ context 'with a manifest where the url is nil' do
26
+ let(:manifest) { { "applications" => { "." => { "url" => nil } } } }
27
+
28
+ it "sets it to none" do
29
+ expect(subject).to eq(
30
+ :applications => [{ :path => ".", :url => "none" }]
31
+ )
32
+ end
33
+ end
34
+
35
+ context 'with a manifest with a subdomain attribute' do
36
+ let(:manifest) { { "applications" => { "." => { "subdomain" => "use-this-for-host" } } } }
37
+
38
+ it "sets the subdomain key to be host" do
39
+ expect(subject).to eq(
40
+ :applications => [{ :path => ".", :host => "use-this-for-host" }]
41
+ )
42
+ end
43
+
44
+ context "when the host attribute is also set" do
45
+ let(:manifest) { { "applications" => { "." => { "subdomain" => "dont-use-this-for-host", "host" => "canonical-attribute" } } } }
46
+
47
+ it 'does not overwrite an explicit host attribute' do
48
+ expect(subject).to eq(
49
+ :applications => [{ :path => ".", :host => "canonical-attribute" }]
50
+ )
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'with a manifest with toplevel attributes' do
56
+ context 'and properties' do
57
+ let(:manifest) {
58
+ { "name" => "foo", "properties" => { "fizz" => "buzz" } }
59
+ }
60
+
61
+ it 'keeps the properties at the toplevel' do
62
+ expect(subject).to eq(
63
+ :applications => [{ :name => "foo", :path => "." }],
64
+ :properties => { :fizz => "buzz" })
65
+ end
66
+ end
67
+
68
+ context 'and no applications' do
69
+ context 'and no path' do
70
+ let(:manifest) { { "name" => "foo" } }
71
+
72
+ it 'adds it as an application with path .' do
73
+ expect(subject).to eq(
74
+ :applications => [{ :name => "foo", :path => "." }])
75
+ end
76
+ end
77
+
78
+ context 'and a path' do
79
+ let(:manifest) { { "name" => "foo", "path" => "./foo" } }
80
+
81
+ it 'adds it as an application with the proper tag and path' do
82
+ expect(subject).to eq(
83
+ :applications => [{ :name => "foo", :path => "./foo" }])
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'and applications' do
89
+ let(:manifest) {
90
+ { "runtime" => "ruby19",
91
+ "applications" => {
92
+ "./foo" => { "name" => "foo" },
93
+ "./bar" => { "name" => "bar" },
94
+ "./baz" => { "name" => "baz", "runtime" => "ruby18" }
95
+ }
96
+ }
97
+ }
98
+
99
+ it "merges the toplevel attributes into the applications" do
100
+ expect(subject[:applications]).to match_array [
101
+ { :name => "foo", :path => "./foo", :runtime => "ruby19" },
102
+ { :name => "bar", :path => "./bar", :runtime => "ruby19" },
103
+ { :name => "baz", :path => "./baz", :runtime => "ruby18" }
104
+ ]
105
+ end
106
+ end
107
+ end
108
+
109
+ context 'with a manifest where applications is a hash' do
110
+ let(:manifest) { { "applications" => { "foo" => { "name" => "foo" } } } }
111
+
112
+ it 'converts the array to a hash, with the path as the key' do
113
+ expect(subject).to eq(
114
+ :applications => [{ :name => "foo", :path => "foo" }])
115
+ end
116
+
117
+ context "and the applications had dependencies" do
118
+ let(:manifest) do
119
+ { "applications" => {
120
+ "bar" => { "name" => "bar", "depends-on" => "foo" },
121
+ "foo" => { "name" => "foo" }
122
+ }
123
+ }
124
+ end
125
+
126
+ it "converts using dependency order" do
127
+ expect(subject).to eq(
128
+ :applications => [{ :name => "foo", :path => "foo" }, { :name => "bar", :path => "bar" }])
129
+ end
130
+
131
+ context "and there's a circular dependency" do
132
+ let(:manifest) do
133
+ { "applications" => {
134
+ "bar" => { "name" => "bar", "depends-on" => "foo" },
135
+ "foo" => { "name" => "foo", "depends-on" => "bar" }
136
+ }
137
+ }
138
+ end
139
+
140
+ it "doesn't blow up" do
141
+ expect(subject).to be_true
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ describe '#normalize_app!' do
149
+ subject do
150
+ loader.send(:normalize_app!, manifest)
151
+ manifest
152
+ end
153
+
154
+ context 'with framework as a hash' do
155
+ let(:manifest) {
156
+ { "name" => "foo",
157
+ "framework" => { "name" => "ruby19", "mem" => "64M" }
158
+ }
159
+ }
160
+
161
+ it 'sets the framework to just the name' do
162
+ expect(subject).to eq(
163
+ "name" => "foo",
164
+ "framework" => "ruby19")
165
+ end
166
+ end
167
+
168
+ context 'with mem instead of memory' do
169
+ let(:manifest) { { "name" => "foo", "mem" => "128M" } }
170
+
171
+ it 'renames mem to memory' do
172
+ expect(subject).to eq("name" => "foo", "memory" => "128M")
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,365 @@
1
+ require "spec_helper"
2
+
3
+ require "manifests-vmc-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
+ # vmc 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(VMC::UserError, /Could not find .+ in the manifest./)
242
+ end
243
+ end
244
+ end
245
+
246
+ # vmc 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(VMC::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