pogo 2.31.2

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