azuki 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +71 -0
  3. data/bin/azuki +17 -0
  4. data/data/cacert.pem +3988 -0
  5. data/lib/azuki.rb +17 -0
  6. data/lib/azuki/auth.rb +339 -0
  7. data/lib/azuki/cli.rb +38 -0
  8. data/lib/azuki/client.rb +764 -0
  9. data/lib/azuki/client/azuki_postgresql.rb +141 -0
  10. data/lib/azuki/client/cisaurus.rb +26 -0
  11. data/lib/azuki/client/pgbackups.rb +113 -0
  12. data/lib/azuki/client/rendezvous.rb +108 -0
  13. data/lib/azuki/client/ssl_endpoint.rb +25 -0
  14. data/lib/azuki/command.rb +294 -0
  15. data/lib/azuki/command/account.rb +23 -0
  16. data/lib/azuki/command/accounts.rb +34 -0
  17. data/lib/azuki/command/addons.rb +305 -0
  18. data/lib/azuki/command/apps.rb +393 -0
  19. data/lib/azuki/command/auth.rb +86 -0
  20. data/lib/azuki/command/base.rb +230 -0
  21. data/lib/azuki/command/certs.rb +209 -0
  22. data/lib/azuki/command/config.rb +137 -0
  23. data/lib/azuki/command/db.rb +218 -0
  24. data/lib/azuki/command/domains.rb +85 -0
  25. data/lib/azuki/command/drains.rb +46 -0
  26. data/lib/azuki/command/fork.rb +164 -0
  27. data/lib/azuki/command/git.rb +64 -0
  28. data/lib/azuki/command/help.rb +179 -0
  29. data/lib/azuki/command/keys.rb +115 -0
  30. data/lib/azuki/command/labs.rb +147 -0
  31. data/lib/azuki/command/logs.rb +45 -0
  32. data/lib/azuki/command/maintenance.rb +61 -0
  33. data/lib/azuki/command/pg.rb +269 -0
  34. data/lib/azuki/command/pgbackups.rb +329 -0
  35. data/lib/azuki/command/plugins.rb +110 -0
  36. data/lib/azuki/command/ps.rb +232 -0
  37. data/lib/azuki/command/regions.rb +22 -0
  38. data/lib/azuki/command/releases.rb +124 -0
  39. data/lib/azuki/command/run.rb +180 -0
  40. data/lib/azuki/command/sharing.rb +89 -0
  41. data/lib/azuki/command/ssl.rb +43 -0
  42. data/lib/azuki/command/stack.rb +62 -0
  43. data/lib/azuki/command/status.rb +51 -0
  44. data/lib/azuki/command/update.rb +47 -0
  45. data/lib/azuki/command/version.rb +23 -0
  46. data/lib/azuki/deprecated.rb +5 -0
  47. data/lib/azuki/deprecated/help.rb +38 -0
  48. data/lib/azuki/distribution.rb +9 -0
  49. data/lib/azuki/excon.rb +9 -0
  50. data/lib/azuki/helpers.rb +517 -0
  51. data/lib/azuki/helpers/azuki_postgresql.rb +165 -0
  52. data/lib/azuki/helpers/log_displayer.rb +70 -0
  53. data/lib/azuki/plugin.rb +163 -0
  54. data/lib/azuki/updater.rb +171 -0
  55. data/lib/azuki/version.rb +3 -0
  56. data/lib/vendor/azuki/okjson.rb +598 -0
  57. data/spec/azuki/auth_spec.rb +256 -0
  58. data/spec/azuki/client/azuki_postgresql_spec.rb +71 -0
  59. data/spec/azuki/client/pgbackups_spec.rb +43 -0
  60. data/spec/azuki/client/rendezvous_spec.rb +62 -0
  61. data/spec/azuki/client/ssl_endpoint_spec.rb +48 -0
  62. data/spec/azuki/client_spec.rb +564 -0
  63. data/spec/azuki/command/addons_spec.rb +601 -0
  64. data/spec/azuki/command/apps_spec.rb +351 -0
  65. data/spec/azuki/command/auth_spec.rb +38 -0
  66. data/spec/azuki/command/base_spec.rb +109 -0
  67. data/spec/azuki/command/certs_spec.rb +178 -0
  68. data/spec/azuki/command/config_spec.rb +144 -0
  69. data/spec/azuki/command/db_spec.rb +110 -0
  70. data/spec/azuki/command/domains_spec.rb +87 -0
  71. data/spec/azuki/command/drains_spec.rb +34 -0
  72. data/spec/azuki/command/fork_spec.rb +56 -0
  73. data/spec/azuki/command/git_spec.rb +144 -0
  74. data/spec/azuki/command/help_spec.rb +93 -0
  75. data/spec/azuki/command/keys_spec.rb +120 -0
  76. data/spec/azuki/command/labs_spec.rb +100 -0
  77. data/spec/azuki/command/logs_spec.rb +60 -0
  78. data/spec/azuki/command/maintenance_spec.rb +51 -0
  79. data/spec/azuki/command/pg_spec.rb +236 -0
  80. data/spec/azuki/command/pgbackups_spec.rb +307 -0
  81. data/spec/azuki/command/plugins_spec.rb +104 -0
  82. data/spec/azuki/command/ps_spec.rb +195 -0
  83. data/spec/azuki/command/releases_spec.rb +130 -0
  84. data/spec/azuki/command/run_spec.rb +83 -0
  85. data/spec/azuki/command/sharing_spec.rb +59 -0
  86. data/spec/azuki/command/stack_spec.rb +46 -0
  87. data/spec/azuki/command/status_spec.rb +48 -0
  88. data/spec/azuki/command/version_spec.rb +16 -0
  89. data/spec/azuki/command_spec.rb +211 -0
  90. data/spec/azuki/helpers/azuki_postgresql_spec.rb +155 -0
  91. data/spec/azuki/helpers_spec.rb +48 -0
  92. data/spec/azuki/plugin_spec.rb +172 -0
  93. data/spec/azuki/updater_spec.rb +44 -0
  94. data/spec/helper/legacy_help.rb +16 -0
  95. data/spec/spec.opts +1 -0
  96. data/spec/spec_helper.rb +224 -0
  97. data/spec/support/display_message_matcher.rb +49 -0
  98. data/spec/support/openssl_mock_helper.rb +8 -0
  99. metadata +211 -0
@@ -0,0 +1,601 @@
1
+ require "spec_helper"
2
+ require "azuki/command/addons"
3
+
4
+ module Azuki::Command
5
+ describe Addons do
6
+ before do
7
+ @addons = prepare_command(Addons)
8
+ stub_core.release("example", "current").returns( "name" => "v99" )
9
+ end
10
+
11
+ describe "index" do
12
+
13
+ before(:each) do
14
+ stub_core
15
+ api.post_app("name" => "example", "stack" => "cedar")
16
+ end
17
+
18
+ after(:each) do
19
+ api.delete_app("example")
20
+ end
21
+
22
+ it "should display no addons when none are configured" do
23
+ stderr, stdout = execute("addons")
24
+ stderr.should == ""
25
+ stdout.should == <<-STDOUT
26
+ example has no add-ons.
27
+ STDOUT
28
+ end
29
+
30
+ it "should list addons and attachments" do
31
+ Excon.stub(
32
+ {
33
+ :expects => 200,
34
+ :method => :get,
35
+ :path => %r{^/apps/example/addons$}
36
+ },
37
+ {
38
+ :body => Azuki::API::OkJson.encode([
39
+ { 'configured' => false, 'name' => 'deployhooks:email' },
40
+ { 'attachment_name' => 'AZUKI_POSTGRESQL_RED', 'configured' => true, 'name' => 'azuki-postgresql:ronin' },
41
+ { 'configured' => true, 'name' => 'deployhooks:http' }
42
+ ]),
43
+ :status => 200,
44
+ }
45
+ )
46
+ stderr, stdout = execute("addons")
47
+ stderr.should == ""
48
+ stdout.should == <<-STDOUT
49
+ === example Configured Add-ons
50
+ deployhooks:http
51
+ azuki-postgresql:ronin AZUKI_POSTGRESQL_RED
52
+
53
+ === example Add-ons to Configure
54
+ deployhooks:email https://api.azukiapp.com/apps/example/addons/deployhooks:email
55
+
56
+ STDOUT
57
+ Excon.stubs.shift
58
+ end
59
+
60
+ end
61
+
62
+ describe "list" do
63
+ before do
64
+ stub_core.addons.returns([
65
+ { "name" => "cloudcounter:basic", "state" => "alpha" },
66
+ { "name" => "cloudcounter:pro", "state" => "public" },
67
+ { "name" => "cloudcounter:gold", "state" => "public" },
68
+ { "name" => "cloudcounter:old", "state" => "disabled" },
69
+ { "name" => "cloudcounter:platinum", "state" => "beta" }
70
+ ])
71
+ end
72
+
73
+ it "lists available addons" do
74
+ stderr, stdout = execute("addons:list")
75
+ stderr.should == ""
76
+ stdout.should == <<-STDOUT
77
+ === alpha
78
+ cloudcounter:basic
79
+
80
+ === available
81
+ cloudcounter:gold, pro
82
+
83
+ === beta
84
+ cloudcounter:platinum
85
+
86
+ === disabled
87
+ cloudcounter:old
88
+
89
+ STDOUT
90
+ end
91
+ end
92
+
93
+ describe 'v1-style command line params' do
94
+ it "understands foo=baz" do
95
+ @addons.stub!(:args).and_return(%w(my_addon foo=baz))
96
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => 'baz' })
97
+ @addons.add
98
+ end
99
+
100
+ it "gives a deprecation notice with an example" do
101
+ stub_request(:post, %r{apps/example/addons/my_addon$}).
102
+ with(:body => {:config => {:foo => 'bar', :extra => "XXX"}}).
103
+ to_return(:body => Azuki::OkJson.encode({ 'price' => 'free' }))
104
+ Excon.stub(
105
+ {
106
+ :expects => 200,
107
+ :method => :get,
108
+ :path => %r{^/apps/example/releases/current}
109
+ },
110
+ {
111
+ :body => Azuki::API::OkJson.encode({ 'name' => 'v99' }),
112
+ :status => 200,
113
+ }
114
+ )
115
+ stderr, stdout = execute("addons:add my_addon --foo=bar extra=XXX")
116
+ stderr.should == ""
117
+ stdout.should == <<-STDOUT
118
+ Warning: non-unix style params have been deprecated, use --extra=XXX instead
119
+ Adding my_addon on example... done, v99 (free)
120
+ Use `azuki addons:docs my_addon` to view documentation.
121
+ STDOUT
122
+ Excon.stubs.shift
123
+ end
124
+ end
125
+
126
+ describe 'unix-style command line params' do
127
+ it "understands --foo=baz" do
128
+ @addons.stub!(:args).and_return(%w(my_addon --foo=baz))
129
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => 'baz' })
130
+ @addons.add
131
+ end
132
+
133
+ it "understands --foo baz" do
134
+ @addons.stub!(:args).and_return(%w(my_addon --foo baz))
135
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => 'baz' })
136
+ @addons.add
137
+ end
138
+
139
+ it "treats lone switches as true" do
140
+ @addons.stub!(:args).and_return(%w(my_addon --foo))
141
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => true })
142
+ @addons.add
143
+ end
144
+
145
+ it "converts 'true' to boolean" do
146
+ @addons.stub!(:args).and_return(%w(my_addon --foo=true))
147
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => true })
148
+ @addons.add
149
+ end
150
+
151
+ it "works with many config vars" do
152
+ @addons.stub!(:args).and_return(%w(my_addon --foo baz --bar yes --baz=foo --bab --bob=true))
153
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => 'baz', 'bar' => 'yes', 'baz' => 'foo', 'bab' => true, 'bob' => true })
154
+ @addons.add
155
+ end
156
+
157
+ it "sends the variables to the server" do
158
+ stub_request(:post, %r{apps/example/addons/my_addon$}).
159
+ with(:body => {:config => { 'foo' => 'baz', 'bar' => 'yes', 'baz' => 'foo', 'bab' => 'true', 'bob' => 'true' }})
160
+ stderr, stdout = execute("addons:add my_addon --foo baz --bar yes --baz=foo --bab --bob=true")
161
+ stderr.should == ""
162
+ end
163
+
164
+ it "raises an error for spurious arguments" do
165
+ @addons.stub!(:args).and_return(%w(my_addon spurious))
166
+ lambda { @addons.add }.should raise_error(CommandFailed)
167
+ end
168
+ end
169
+
170
+ describe "mixed options" do
171
+ it "understands foo=bar and --baz=bar on the same line" do
172
+ @addons.stub!(:args).and_return(%w(my_addon foo=baz --baz=bar bob=true --bar))
173
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', { 'foo' => 'baz', 'baz' => 'bar', 'bar' => true, 'bob' => true })
174
+ @addons.add
175
+ end
176
+
177
+ it "sends the variables to the server" do
178
+ stub_request(:post, %r{apps/example/addons/my_addon$}).
179
+ with(:body => {:config => { 'foo' => 'baz', 'baz' => 'bar', 'bar' => 'true', 'bob' => 'true' }})
180
+ stderr, stdout = execute("addons:add my_addon foo=baz --baz=bar bob=true --bar")
181
+ stderr.should == ""
182
+ stdout.should include("Warning: non-unix style params have been deprecated, use --foo=baz --bob=true instead")
183
+ end
184
+ end
185
+
186
+ describe "fork and follow switches" do
187
+ it "should only resolve for azuki-postgresql addon" do
188
+ %w{fork follow}.each do |switch|
189
+ @addons.stub!(:args).and_return("addon --#{switch} AZUKI_POSTGRESQL_RED".split)
190
+ @addons.azuki.should_receive(:install_addon).
191
+ with('example', 'addon', {switch => 'AZUKI_POSTGRESQL_RED'})
192
+ @addons.add
193
+ end
194
+ end
195
+
196
+ it "should translate --fork and --follow" do
197
+ %w{fork follow}.each do |switch|
198
+ @addons.stub!(:app_config_vars).and_return({})
199
+ @addons.stub!(:app_attachments).and_return([Azuki::Helpers::AzukiPostgresql::Attachment.new({
200
+ 'config_var' => 'AZUKI_POSTGRESQL_RED_URL',
201
+ 'resource' => {'name' => 'loudly-yelling-1232',
202
+ 'value' => 'postgres://red_url',
203
+ 'type' => 'azuki-postgresql:ronin' }})
204
+ ])
205
+ @addons.stub!(:args).and_return("azuki-postgresql --#{switch} AZUKI_POSTGRESQL_RED".split)
206
+ @addons.azuki.should_receive(:install_addon).with('example', 'azuki-postgresql', {switch => 'postgres://red_url'})
207
+ @addons.add
208
+ end
209
+ end
210
+
211
+ it "should NOT translate --fork and --follow if passed in a full postgres url even if there are no databases" do
212
+ %w{fork follow}.each do |switch|
213
+ @addons.stub!(:app_config_vars).and_return({})
214
+ @addons.stub!(:app_attachments).and_return([])
215
+ @addons.stub!(:args).and_return("azuki-postgresql --#{switch} postgres://foo:yeah@awesome.com:234/bestdb".split)
216
+ @addons.azuki.should_receive(:install_addon).with('example', 'azuki-postgresql', {switch => 'postgres://foo:yeah@awesome.com:234/bestdb'})
217
+ @addons.add
218
+ end
219
+ end
220
+ end
221
+
222
+ describe 'adding' do
223
+ before do
224
+ @addons.stub!(:args).and_return(%w(my_addon))
225
+ Excon.stub(
226
+ {
227
+ :expects => 200,
228
+ :method => :get,
229
+ :path => %r{^/apps/example/releases/current}
230
+ },
231
+ {
232
+ :body => Azuki::API::OkJson.encode({ 'name' => 'v99' }),
233
+ :status => 200,
234
+ }
235
+ )
236
+ end
237
+ after do
238
+ Excon.stubs.shift
239
+ end
240
+
241
+
242
+ it "requires an addon name" do
243
+ @addons.stub!(:args).and_return([])
244
+ lambda { @addons.add }.should raise_error(CommandFailed)
245
+ end
246
+
247
+ it "adds an addon" do
248
+ @addons.stub!(:args).and_return(%w(my_addon))
249
+ @addons.azuki.should_receive(:install_addon).with('example', 'my_addon', {})
250
+ @addons.add
251
+ end
252
+
253
+ it "adds an addon with a price" do
254
+ stub_core.install_addon("example", "my_addon", {}).returns({ "price" => "free" })
255
+ stderr, stdout = execute("addons:add my_addon")
256
+ stderr.should == ""
257
+ stdout.should =~ /\(free\)/
258
+ end
259
+
260
+ it "adds an addon with a price and message" do
261
+ stub_core.install_addon("example", "my_addon", {}).returns({ "price" => "free", "message" => "foo" })
262
+ stderr, stdout = execute("addons:add my_addon")
263
+ stderr.should == ""
264
+ stdout.should == <<-OUTPUT
265
+ Adding my_addon on example... done, v99 (free)
266
+ foo
267
+ Use `azuki addons:docs my_addon` to view documentation.
268
+ OUTPUT
269
+ end
270
+
271
+ it "adds an addon with a price and multiline message" do
272
+ stub_core.install_addon("example", "my_addon", {}).returns({ "price" => "$200/mo", "message" => "foo\nbar" })
273
+ stderr, stdout = execute("addons:add my_addon")
274
+ stderr.should == ""
275
+ stdout.should == <<-OUTPUT
276
+ Adding my_addon on example... done, v99 ($200/mo)
277
+ foo
278
+ bar
279
+ Use `azuki addons:docs my_addon` to view documentation.
280
+ OUTPUT
281
+ end
282
+
283
+ it "displays an error with unexpected options" do
284
+ Azuki::Command.should_receive(:error).with("Unexpected arguments: bar")
285
+ run("addons:add redistogo -a foo bar")
286
+ end
287
+ end
288
+
289
+ describe 'upgrading' do
290
+ before do
291
+ @addons.stub!(:args).and_return(%w(my_addon))
292
+ Excon.stub(
293
+ {
294
+ :expects => 200,
295
+ :method => :get,
296
+ :path => %r{^/apps/example/releases/current}
297
+ },
298
+ {
299
+ :body => Azuki::API::OkJson.encode({ 'name' => 'v99' }),
300
+ :status => 200,
301
+ }
302
+ )
303
+ end
304
+ after do
305
+ Excon.stubs.shift
306
+ end
307
+
308
+ it "requires an addon name" do
309
+ @addons.stub!(:args).and_return([])
310
+ lambda { @addons.upgrade }.should raise_error(CommandFailed)
311
+ end
312
+
313
+ it "upgrades an addon" do
314
+ @addons.stub!(:args).and_return(%w(my_addon))
315
+ @addons.azuki.should_receive(:upgrade_addon).with('example', 'my_addon', {})
316
+ @addons.upgrade
317
+ end
318
+
319
+ it "upgrade an addon with config vars" do
320
+ @addons.stub!(:args).and_return(%w(my_addon --foo=baz))
321
+ @addons.azuki.should_receive(:upgrade_addon).with('example', 'my_addon', { 'foo' => 'baz' })
322
+ @addons.upgrade
323
+ end
324
+
325
+ it "adds an addon with a price" do
326
+ stub_core.upgrade_addon("example", "my_addon", {}).returns({ "price" => "free" })
327
+ stderr, stdout = execute("addons:upgrade my_addon")
328
+ stderr.should == ""
329
+ stdout.should == <<-OUTPUT
330
+ Upgrading to my_addon on example... done, v99 (free)
331
+ Use `azuki addons:docs my_addon` to view documentation.
332
+ OUTPUT
333
+ end
334
+
335
+ it "adds an addon with a price and message" do
336
+ stub_core.upgrade_addon("example", "my_addon", {}).returns({ "price" => "free", "message" => "Don't Panic" })
337
+ stderr, stdout = execute("addons:upgrade my_addon")
338
+ stderr.should == ""
339
+ stdout.should == <<-OUTPUT
340
+ Upgrading to my_addon on example... done, v99 (free)
341
+ Don't Panic
342
+ Use `azuki addons:docs my_addon` to view documentation.
343
+ OUTPUT
344
+ end
345
+ end
346
+
347
+ describe 'downgrading' do
348
+ before do
349
+ @addons.stub!(:args).and_return(%w(my_addon))
350
+ Excon.stub(
351
+ {
352
+ :expects => 200,
353
+ :method => :get,
354
+ :path => %r{^/apps/example/releases/current}
355
+ },
356
+ {
357
+ :body => Azuki::API::OkJson.encode({ 'name' => 'v99' }),
358
+ :status => 200,
359
+ }
360
+ )
361
+ end
362
+ after do
363
+ Excon.stubs.shift
364
+ end
365
+
366
+ it "requires an addon name" do
367
+ @addons.stub!(:args).and_return([])
368
+ lambda { @addons.downgrade }.should raise_error(CommandFailed)
369
+ end
370
+
371
+ it "downgrades an addon" do
372
+ @addons.stub!(:args).and_return(%w(my_addon))
373
+ @addons.azuki.should_receive(:upgrade_addon).with('example', 'my_addon', {})
374
+ @addons.downgrade
375
+ end
376
+
377
+ it "downgrade an addon with config vars" do
378
+ @addons.stub!(:args).and_return(%w(my_addon --foo=baz))
379
+ @addons.azuki.should_receive(:upgrade_addon).with('example', 'my_addon', { 'foo' => 'baz' })
380
+ @addons.downgrade
381
+ end
382
+
383
+ it "downgrades an addon with a price" do
384
+ stub_core.upgrade_addon("example", "my_addon", {}).returns({ "price" => "free" })
385
+ stderr, stdout = execute("addons:downgrade my_addon")
386
+ stderr.should == ""
387
+ stdout.should == <<-OUTPUT
388
+ Downgrading to my_addon on example... done, v99 (free)
389
+ Use `azuki addons:docs my_addon` to view documentation.
390
+ OUTPUT
391
+ end
392
+
393
+ it "downgrades an addon with a price and message" do
394
+ stub_core.upgrade_addon("example", "my_addon", {}).returns({ "price" => "free", "message" => "Don't Panic" })
395
+ stderr, stdout = execute("addons:downgrade my_addon")
396
+ stderr.should == ""
397
+ stdout.should == <<-OUTPUT
398
+ Downgrading to my_addon on example... done, v99 (free)
399
+ Don't Panic
400
+ Use `azuki addons:docs my_addon` to view documentation.
401
+ OUTPUT
402
+ end
403
+ end
404
+
405
+ it "asks the user to confirm billing when API responds with 402" do
406
+ @addons.stub!(:args).and_return(%w( addon1 ))
407
+ e = RestClient::RequestFailed.new
408
+ e.stub!(:http_code).and_return(402)
409
+ e.stub!(:http_body).and_return('{"error":"test"}')
410
+ @addons.azuki.should_receive(:install_addon).and_raise(e)
411
+ @addons.should_receive(:confirm_billing).and_return(false)
412
+ STDERR.should_receive(:puts).with(" ! test")
413
+ lambda { @addons.add }.should raise_error(SystemExit)
414
+ end
415
+
416
+ it "does not remove addons with no confirm" do
417
+ @addons.stub!(:args).and_return(%w( addon1 ))
418
+ @addons.should_receive(:confirm_command).once.and_return(false)
419
+ @addons.azuki.should_not_receive(:uninstall_addon)
420
+ @addons.remove
421
+ end
422
+
423
+ it "removes addons after prompting for confirmation" do
424
+ @addons.stub!(:args).and_return(%w( addon1 ))
425
+ @addons.should_receive(:confirm_command).once.and_return(true)
426
+ @addons.azuki.should_receive(:uninstall_addon).with('example', 'addon1', :confirm => "example")
427
+ @addons.remove
428
+ end
429
+
430
+ it "removes addons with confirm option" do
431
+ Azuki::Command.stub!(:current_options).and_return(:confirm => "example")
432
+ @addons.stub!(:args).and_return(%w( addon1 ))
433
+ @addons.azuki.should_receive(:uninstall_addon).with('example', 'addon1', :confirm => "example")
434
+ @addons.remove
435
+ end
436
+
437
+ describe "opening add-on docs" do
438
+
439
+ before(:each) do
440
+ stub_core
441
+ api.post_app("name" => "example", "stack" => "cedar")
442
+ end
443
+
444
+ after(:each) do
445
+ api.delete_app("example")
446
+ end
447
+
448
+ it "displays usage when no argument is specified" do
449
+ stderr, stdout = execute('addons:docs')
450
+ stderr.should == <<-STDERR
451
+ ! Usage: azuki addons:docs ADDON
452
+ ! Must specify ADDON to open docs for.
453
+ STDERR
454
+ stdout.should == ''
455
+ end
456
+
457
+ it "opens the addon if only one matches" do
458
+ require("launchy")
459
+ Launchy.should_receive(:open).with("https://devcenter.azukiapp.com/articles/redistogo").and_return(Thread.new {})
460
+ stderr, stdout = execute('addons:docs redistogo:nano')
461
+ stderr.should == ''
462
+ stdout.should == <<-STDOUT
463
+ Opening redistogo:nano docs... done
464
+ STDOUT
465
+ end
466
+
467
+ it "complains about ambiguity" do
468
+ Excon.stub(
469
+ {
470
+ :expects => 200,
471
+ :method => :get,
472
+ :path => %r{^/addons$}
473
+ },
474
+ {
475
+ :body => Azuki::API::OkJson.encode([
476
+ { 'name' => 'qux:foo' },
477
+ { 'name' => 'quux:bar' }
478
+ ]),
479
+ :status => 200,
480
+ }
481
+ )
482
+ stderr, stdout = execute('addons:docs qu')
483
+ stderr.should == <<-STDERR
484
+ ! Ambiguous addon name: qu
485
+ ! Perhaps you meant `qux:foo` or `quux:bar`.
486
+ STDERR
487
+ stdout.should == ''
488
+ Excon.stubs.shift
489
+ end
490
+
491
+ it "complains if no such addon exists" do
492
+ stderr, stdout = execute('addons:docs unknown')
493
+ stderr.should == <<-STDERR
494
+ ! `unknown` is not a azuki add-on.
495
+ ! See `azuki addons:list` for all available addons.
496
+ STDERR
497
+ stdout.should == ''
498
+ end
499
+
500
+ it "suggests alternatives if addon has typo" do
501
+ stderr, stdout = execute('addons:docs redisgoto')
502
+ stderr.should == <<-STDERR
503
+ ! `redisgoto` is not a azuki add-on.
504
+ ! Perhaps you meant `redistogo`.
505
+ ! See `azuki addons:list` for all available addons.
506
+ STDERR
507
+ stdout.should == ''
508
+ end
509
+
510
+ it "complains if addon is not installed" do
511
+ stderr, stdout = execute('addons:open deployhooks:http')
512
+ stderr.should == <<-STDOUT
513
+ ! Addon not installed: deployhooks:http
514
+ STDOUT
515
+ stdout.should == ''
516
+ end
517
+ end
518
+ describe "opening an addon" do
519
+
520
+ before(:each) do
521
+ stub_core
522
+ api.post_app("name" => "example", "stack" => "cedar")
523
+ end
524
+
525
+ after(:each) do
526
+ api.delete_app("example")
527
+ end
528
+
529
+ it "displays usage when no argument is specified" do
530
+ stderr, stdout = execute('addons:open')
531
+ stderr.should == <<-STDERR
532
+ ! Usage: azuki addons:open ADDON
533
+ ! Must specify ADDON to open.
534
+ STDERR
535
+ stdout.should == ''
536
+ end
537
+
538
+ it "opens the addon if only one matches" do
539
+ api.post_addon('example', 'redistogo:nano')
540
+ require("launchy")
541
+ Launchy.should_receive(:open).with("https://api.#{@addons.azuki.host}/apps/example/addons/redistogo:nano").and_return(Thread.new {})
542
+ stderr, stdout = execute('addons:open redistogo:nano')
543
+ stderr.should == ''
544
+ stdout.should == <<-STDOUT
545
+ Opening redistogo:nano for example... done
546
+ STDOUT
547
+ end
548
+
549
+ it "complains about ambiguity" do
550
+ Excon.stub(
551
+ {
552
+ :expects => 200,
553
+ :method => :get,
554
+ :path => %r{^/apps/example/addons$}
555
+ },
556
+ {
557
+ :body => Azuki::API::OkJson.encode([
558
+ { 'name' => 'deployhooks:email' },
559
+ { 'name' => 'deployhooks:http' }
560
+ ]),
561
+ :status => 200,
562
+ }
563
+ )
564
+ stderr, stdout = execute('addons:open deployhooks')
565
+ stderr.should == <<-STDERR
566
+ ! Ambiguous addon name: deployhooks
567
+ ! Perhaps you meant `deployhooks:email` or `deployhooks:http`.
568
+ STDERR
569
+ stdout.should == ''
570
+ Excon.stubs.shift
571
+ end
572
+
573
+ it "complains if no such addon exists" do
574
+ stderr, stdout = execute('addons:open unknown')
575
+ stderr.should == <<-STDERR
576
+ ! `unknown` is not a azuki add-on.
577
+ ! See `azuki addons:list` for all available addons.
578
+ STDERR
579
+ stdout.should == ''
580
+ end
581
+
582
+ it "suggests alternatives if addon has typo" do
583
+ stderr, stdout = execute('addons:open redisgoto')
584
+ stderr.should == <<-STDERR
585
+ ! `redisgoto` is not a azuki add-on.
586
+ ! Perhaps you meant `redistogo`.
587
+ ! See `azuki addons:list` for all available addons.
588
+ STDERR
589
+ stdout.should == ''
590
+ end
591
+
592
+ it "complains if addon is not installed" do
593
+ stderr, stdout = execute('addons:open deployhooks:http')
594
+ stderr.should == <<-STDOUT
595
+ ! Addon not installed: deployhooks:http
596
+ STDOUT
597
+ stdout.should == ''
598
+ end
599
+ end
600
+ end
601
+ end