artofmission-heroku 1.6.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.
- data/README.md +66 -0
- data/Rakefile +107 -0
- data/bin/heroku +15 -0
- data/lib/heroku.rb +5 -0
- data/lib/heroku/client.rb +487 -0
- data/lib/heroku/command.rb +96 -0
- data/lib/heroku/commands/account.rb +13 -0
- data/lib/heroku/commands/addons.rb +109 -0
- data/lib/heroku/commands/app.rb +239 -0
- data/lib/heroku/commands/auth.rb +137 -0
- data/lib/heroku/commands/base.rb +133 -0
- data/lib/heroku/commands/bundles.rb +51 -0
- data/lib/heroku/commands/config.rb +55 -0
- data/lib/heroku/commands/db.rb +129 -0
- data/lib/heroku/commands/domains.rb +31 -0
- data/lib/heroku/commands/help.rb +148 -0
- data/lib/heroku/commands/keys.rb +49 -0
- data/lib/heroku/commands/logs.rb +11 -0
- data/lib/heroku/commands/maintenance.rb +13 -0
- data/lib/heroku/commands/plugins.rb +25 -0
- data/lib/heroku/commands/ps.rb +37 -0
- data/lib/heroku/commands/service.rb +23 -0
- data/lib/heroku/commands/sharing.rb +29 -0
- data/lib/heroku/commands/ssl.rb +33 -0
- data/lib/heroku/commands/version.rb +7 -0
- data/lib/heroku/helpers.rb +23 -0
- data/lib/heroku/plugin.rb +65 -0
- data/spec/base.rb +23 -0
- data/spec/client_spec.rb +366 -0
- data/spec/command_spec.rb +15 -0
- data/spec/commands/addons_spec.rb +47 -0
- data/spec/commands/app_spec.rb +175 -0
- data/spec/commands/auth_spec.rb +104 -0
- data/spec/commands/base_spec.rb +114 -0
- data/spec/commands/bundles_spec.rb +48 -0
- data/spec/commands/config_spec.rb +45 -0
- data/spec/commands/db_spec.rb +53 -0
- data/spec/commands/domains_spec.rb +31 -0
- data/spec/commands/keys_spec.rb +60 -0
- data/spec/commands/logs_spec.rb +21 -0
- data/spec/commands/maintenance_spec.rb +21 -0
- data/spec/commands/plugins_spec.rb +26 -0
- data/spec/commands/ps_spec.rb +16 -0
- data/spec/commands/sharing_spec.rb +32 -0
- data/spec/commands/ssl_spec.rb +25 -0
- data/spec/plugin_spec.rb +64 -0
- metadata +150 -0
data/spec/base.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/../lib/heroku'
|
6
|
+
require 'command'
|
7
|
+
require 'commands/base'
|
8
|
+
Dir["#{File.dirname(__FILE__)}/../lib/heroku/commands/*"].each { |c| require c }
|
9
|
+
|
10
|
+
def prepare_command(klass)
|
11
|
+
command = klass.new(['--app', 'myapp'])
|
12
|
+
command.stub!(:args).and_return([])
|
13
|
+
command.stub!(:display)
|
14
|
+
command.stub!(:heroku).and_return(mock('heroku client', :host => 'heroku.com'))
|
15
|
+
command.stub!(:extract_app).and_return('myapp')
|
16
|
+
command
|
17
|
+
end
|
18
|
+
|
19
|
+
module SandboxHelper
|
20
|
+
def bash(cmd)
|
21
|
+
FileUtils.cd(@sandbox) { |d| return `#{cmd}` }
|
22
|
+
end
|
23
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,366 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/base'
|
2
|
+
|
3
|
+
describe Heroku::Client do
|
4
|
+
before do
|
5
|
+
@client = Heroku::Client.new(nil, nil)
|
6
|
+
@resource = mock('heroku rest resource')
|
7
|
+
@client.stub!(:extract_warning)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "list -> get a list of this user's apps" do
|
11
|
+
@client.should_receive(:resource).with('/apps').and_return(@resource)
|
12
|
+
@resource.should_receive(:get).and_return <<EOXML
|
13
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
14
|
+
<apps type="array">
|
15
|
+
<app><name>myapp1</name><owner>test@heroku.com</owner></app>
|
16
|
+
<app><name>myapp2</name><owner>test@heroku.com</owner></app>
|
17
|
+
</apps>
|
18
|
+
EOXML
|
19
|
+
@client.list.should == [
|
20
|
+
["myapp1", "test@heroku.com"],
|
21
|
+
["myapp2", "test@heroku.com"]
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "info -> get app attributes" do
|
26
|
+
@client.should_receive(:resource).with('/apps/myapp').and_return(@resource)
|
27
|
+
@resource.should_receive(:get).and_return <<EOXML
|
28
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
29
|
+
<app>
|
30
|
+
<blessed type='boolean'>true</blessed>
|
31
|
+
<created-at type='datetime'>2008-07-08T17:21:50-07:00</created-at>
|
32
|
+
<id type='integer'>49134</id>
|
33
|
+
<name>testgems</name>
|
34
|
+
<production type='boolean'>true</production>
|
35
|
+
<share-public type='boolean'>true</share-public>
|
36
|
+
<domain_name/>
|
37
|
+
</app>
|
38
|
+
EOXML
|
39
|
+
@client.stub!(:list_collaborators).and_return([:jon, :mike])
|
40
|
+
@client.stub!(:installed_addons).and_return([:addon1])
|
41
|
+
@client.info('myapp').should == { :blessed => 'true', :created_at => '2008-07-08T17:21:50-07:00', :id => '49134', :name => 'testgems', :production => 'true', :share_public => 'true', :domain_name => nil, :collaborators => [:jon, :mike], :addons => [:addon1] }
|
42
|
+
end
|
43
|
+
|
44
|
+
it "create -> create a new blank app" do
|
45
|
+
@client.should_receive(:resource).with('/apps').and_return(@resource)
|
46
|
+
@resource.should_receive(:post).and_return <<EOXML
|
47
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
48
|
+
<app><name>untitled-123</name></app>
|
49
|
+
EOXML
|
50
|
+
@client.create.should == "untitled-123"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "create(name) -> create a new blank app with a specified name" do
|
54
|
+
@client.should_receive(:resource).with('/apps').and_return(@resource)
|
55
|
+
@resource.should_receive(:post).with({ :app => { :name => 'newapp' } }, @client.heroku_headers).and_return <<EOXML
|
56
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
57
|
+
<app><name>newapp</name></app>
|
58
|
+
EOXML
|
59
|
+
@client.create("newapp").should == "newapp"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "update(name, attributes) -> updates existing apps" do
|
63
|
+
@client.should_receive(:resource).with('/apps/myapp').and_return(@resource)
|
64
|
+
@resource.should_receive(:put).with({ :app => { :mode => 'production', :public => true } }, anything)
|
65
|
+
@client.update("myapp", :mode => 'production', :public => true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "destroy(name) -> destroy the named app" do
|
69
|
+
@client.should_receive(:resource).with('/apps/destroyme').and_return(@resource)
|
70
|
+
@resource.should_receive(:delete)
|
71
|
+
@client.destroy("destroyme")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "rake(app_name, cmd) -> run a rake command on the app" do
|
75
|
+
@client.should_receive(:resource).with('/apps/myapp/services').and_return(@resource)
|
76
|
+
@resource.should_receive(:post).with('rake db:migrate', @client.heroku_headers.merge(:content_type => 'text/plain'))
|
77
|
+
@client.rake('myapp', 'db:migrate')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "console(app_name, cmd) -> run a console command on the app" do
|
81
|
+
@client.should_receive(:resource).with('/apps/myapp/console').and_return(@resource)
|
82
|
+
@resource.should_receive(:post).with('2+2', @client.heroku_headers)
|
83
|
+
@client.console('myapp', '2+2')
|
84
|
+
end
|
85
|
+
|
86
|
+
it "console(app_name) { |c| } -> opens a console session, yields one accessor and closes it after the block" do
|
87
|
+
@resources = %w( open run close ).inject({}) { |h, r| h[r] = mock("resource for console #{r}"); h }
|
88
|
+
@client.should_receive(:resource).with('/apps/myapp/consoles').and_return(@resources['open'])
|
89
|
+
@client.should_receive(:resource).with('/apps/myapp/consoles/42/command').and_return(@resources['run'])
|
90
|
+
@client.should_receive(:resource).with('/apps/myapp/consoles/42').and_return(@resources['close'])
|
91
|
+
@resources['open'].should_receive(:post).and_return(42)
|
92
|
+
@resources['run'].should_receive(:post).with("1+1", anything).and_return('2')
|
93
|
+
@resources['close'].should_receive(:delete)
|
94
|
+
|
95
|
+
@client.console('myapp') do |c|
|
96
|
+
c.run("1+1").should == '=> 2'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it "restart(app_name) -> restarts the app servers" do
|
101
|
+
@client.should_receive(:resource).with('/apps/myapp/server').and_return(@resource)
|
102
|
+
@resource.should_receive(:delete).with(anything)
|
103
|
+
@client.restart('myapp')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "logs(app_name) -> returns recent output of the app logs" do
|
107
|
+
@client.should_receive(:resource).with('/apps/myapp/logs').and_return(@resource)
|
108
|
+
@resource.should_receive(:get).and_return('log')
|
109
|
+
@client.logs('myapp').should == 'log'
|
110
|
+
end
|
111
|
+
|
112
|
+
it "cron_logs(app_name) -> returns recent output of the app logs" do
|
113
|
+
@client.should_receive(:resource).with('/apps/myapp/cron_logs').and_return(@resource)
|
114
|
+
@resource.should_receive(:get).and_return('cron log')
|
115
|
+
@client.cron_logs('myapp').should == 'cron log'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "set_dynos(app_name, qty) -> scales the app" do
|
119
|
+
@client.should_receive(:resource).with('/apps/myapp/dynos').and_return(@resource)
|
120
|
+
@resource.should_receive(:put).with({ :dynos => 3 }, anything)
|
121
|
+
@client.set_dynos('myapp', 3)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "rake catches 502s and shows the app crashlog" do
|
125
|
+
e = RestClient::RequestFailed.new
|
126
|
+
e.stub!(:http_code).and_return(502)
|
127
|
+
e.stub!(:http_body).and_return('the crashlog')
|
128
|
+
@client.should_receive(:post).and_raise(e)
|
129
|
+
lambda { @client.rake('myapp', '') }.should raise_error(Heroku::Client::AppCrashed)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "rake passes other status codes (i.e., 500) as standard restclient exceptions" do
|
133
|
+
e = RestClient::RequestFailed.new
|
134
|
+
e.stub!(:http_code).and_return(500)
|
135
|
+
e.stub!(:http_body).and_return('not a crashlog')
|
136
|
+
@client.should_receive(:post).and_raise(e)
|
137
|
+
lambda { @client.rake('myapp', '') }.should raise_error(RestClient::RequestFailed)
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "bundles" do
|
141
|
+
it "gives a temporary URL where the bundle can be downloaded" do
|
142
|
+
@client.should_receive(:get).with("/apps/myapp/bundles/latest", {:accept=>"application/json"}).and_return("{\"name\":\"bundle1\",\"temporary_url\":\"https:\\/\\/s3.amazonaws.com\\/herokubundles\\/123.tar.gz\"}")
|
143
|
+
@client.bundle_url('myapp').should == 'https://s3.amazonaws.com/herokubundles/123.tar.gz'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "collaborators" do
|
148
|
+
it "list(app_name) -> list app collaborators" do
|
149
|
+
@client.should_receive(:resource).with('/apps/myapp/collaborators').and_return(@resource)
|
150
|
+
@resource.should_receive(:get).and_return <<EOXML
|
151
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
152
|
+
<collaborators type="array">
|
153
|
+
<collaborator><email>joe@example.com</email></collaborator>
|
154
|
+
<collaborator><email>jon@example.com</email></collaborator>
|
155
|
+
</collaborators>
|
156
|
+
EOXML
|
157
|
+
@client.list_collaborators('myapp').should == [
|
158
|
+
{ :email => 'joe@example.com' },
|
159
|
+
{ :email => 'jon@example.com' }
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "add_collaborator(app_name, email) -> adds collaborator to app" do
|
164
|
+
@client.should_receive(:resource).with('/apps/myapp/collaborators').and_return(@resource)
|
165
|
+
@resource.should_receive(:post).with({ 'collaborator[email]' => 'joe@example.com'}, anything)
|
166
|
+
@client.add_collaborator('myapp', 'joe@example.com')
|
167
|
+
end
|
168
|
+
|
169
|
+
it "remove_collaborator(app_name, email) -> removes collaborator from app" do
|
170
|
+
@client.should_receive(:resource).with('/apps/myapp/collaborators/joe%40example%2Ecom').and_return(@resource)
|
171
|
+
@resource.should_receive(:delete)
|
172
|
+
@client.remove_collaborator('myapp', 'joe@example.com')
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "domain names" do
|
177
|
+
it "list(app_name) -> list app domain names" do
|
178
|
+
@client.should_receive(:resource).with('/apps/myapp/domains').and_return(@resource)
|
179
|
+
@resource.should_receive(:get).and_return <<EOXML
|
180
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
181
|
+
<domain-names type="array">
|
182
|
+
<domain-name><domain>example1.com</domain></domain-name>
|
183
|
+
<domain-name><domain>example2.com</domain></domain-name>
|
184
|
+
</domain-names>
|
185
|
+
EOXML
|
186
|
+
@client.list_domains('myapp').should == [{:domain => 'example1.com'}, {:domain => 'example2.com'}]
|
187
|
+
end
|
188
|
+
|
189
|
+
it "add_domain(app_name, domain) -> adds domain name to app" do
|
190
|
+
@client.should_receive(:resource).with('/apps/myapp/domains').and_return(@resource)
|
191
|
+
@resource.should_receive(:post).with('example.com', anything)
|
192
|
+
@client.add_domain('myapp', 'example.com')
|
193
|
+
end
|
194
|
+
|
195
|
+
it "remove_domain(app_name, domain) -> removes domain name from app" do
|
196
|
+
@client.should_receive(:resource).with('/apps/myapp/domains/example.com').and_return(@resource)
|
197
|
+
@resource.should_receive(:delete)
|
198
|
+
@client.remove_domain('myapp', 'example.com')
|
199
|
+
end
|
200
|
+
|
201
|
+
it "remove_domains(app_name) -> removes all domain names from app" do
|
202
|
+
@client.should_receive(:resource).with('/apps/myapp/domains').and_return(@resource)
|
203
|
+
@resource.should_receive(:delete)
|
204
|
+
@client.remove_domains('myapp')
|
205
|
+
end
|
206
|
+
|
207
|
+
it "add_ssl(app_name, pem, key) -> adds a ssl cert to the domain" do
|
208
|
+
@client.should_receive(:resource).with('/apps/myapp/ssl').and_return(@resource)
|
209
|
+
@resource.should_receive(:post).with({ :pem => 'pem', :key => 'key' }, anything).and_return('{}')
|
210
|
+
@client.add_ssl('myapp', 'pem', 'key')
|
211
|
+
end
|
212
|
+
|
213
|
+
it "remove_ssl(app_name, domain) -> removes the ssl cert for the domain" do
|
214
|
+
@client.should_receive(:resource).with('/apps/myapp/domains/example.com/ssl').and_return(@resource)
|
215
|
+
@resource.should_receive(:delete)
|
216
|
+
@client.remove_ssl('myapp', 'example.com')
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "ssh keys" do
|
221
|
+
it "fetches a list of the user's current keys" do
|
222
|
+
@client.should_receive(:resource).with('/user/keys').and_return(@resource)
|
223
|
+
@resource.should_receive(:get).and_return <<EOXML
|
224
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
225
|
+
<keys type="array">
|
226
|
+
<key>
|
227
|
+
<contents>ssh-dss thekey== joe@workstation</contents>
|
228
|
+
</key>
|
229
|
+
</keys>
|
230
|
+
EOXML
|
231
|
+
@client.keys.should == [ "ssh-dss thekey== joe@workstation" ]
|
232
|
+
end
|
233
|
+
|
234
|
+
it "add_key(key) -> add an ssh key (e.g., the contents of id_rsa.pub) to the user" do
|
235
|
+
@client.should_receive(:resource).with('/user/keys').and_return(@resource)
|
236
|
+
@client.stub!(:heroku_headers).and_return({})
|
237
|
+
@resource.should_receive(:post).with('a key', 'Content-Type' => 'text/ssh-authkey')
|
238
|
+
@client.add_key('a key')
|
239
|
+
end
|
240
|
+
|
241
|
+
it "remove_key(key) -> remove an ssh key by name (user@box)" do
|
242
|
+
@client.should_receive(:resource).with('/user/keys/joe%40workstation').and_return(@resource)
|
243
|
+
@resource.should_receive(:delete)
|
244
|
+
@client.remove_key('joe@workstation')
|
245
|
+
end
|
246
|
+
|
247
|
+
it "remove_all_keys -> removes all ssh keys for the user" do
|
248
|
+
@client.should_receive(:resource).with('/user/keys').and_return(@resource)
|
249
|
+
@resource.should_receive(:delete)
|
250
|
+
@client.remove_all_keys
|
251
|
+
end
|
252
|
+
|
253
|
+
it "database_session(app_name) -> creates a taps database session" do
|
254
|
+
@client.should_receive(:resource).with('/apps/myapp/database/session').and_return(@resource)
|
255
|
+
@resource.should_receive(:post).with('', anything)
|
256
|
+
@client.database_session('myapp')
|
257
|
+
end
|
258
|
+
|
259
|
+
it "database_reset(app_name) -> reset an app's database" do
|
260
|
+
@client.should_receive(:resource).with('/apps/myapp/database/reset').and_return(@resource)
|
261
|
+
@resource.should_receive(:post).with('', anything)
|
262
|
+
@client.database_reset('myapp')
|
263
|
+
end
|
264
|
+
|
265
|
+
it "maintenance(app_name, :on) -> sets maintenance mode for an app" do
|
266
|
+
@client.should_receive(:resource).with('/apps/myapp/server/maintenance').and_return(@resource)
|
267
|
+
@resource.should_receive(:post).with({:maintenance_mode => '1'}, anything)
|
268
|
+
@client.maintenance('myapp', :on)
|
269
|
+
end
|
270
|
+
|
271
|
+
it "maintenance(app_name, :off) -> turns off maintenance mode for an app" do
|
272
|
+
@client.should_receive(:resource).with('/apps/myapp/server/maintenance').and_return(@resource)
|
273
|
+
@resource.should_receive(:post).with({:maintenance_mode => '0'}, anything)
|
274
|
+
@client.maintenance('myapp', :off)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "config vars" do
|
279
|
+
it "config_vars(app_name) -> json hash of config vars for the app" do
|
280
|
+
@client.should_receive(:resource).with('/apps/myapp/config_vars').and_return(@resource)
|
281
|
+
@resource.should_receive(:get).and_return '{"A":"one", "B":"two"}'
|
282
|
+
@client.config_vars('myapp').should == { 'A' => 'one', 'B' => 'two'}
|
283
|
+
end
|
284
|
+
|
285
|
+
it "add_config_vars(app_name, vars)" do
|
286
|
+
@client.should_receive(:resource).with('/apps/myapp/config_vars').and_return(@resource)
|
287
|
+
@resource.should_receive(:put).with('{"x":"y"}', anything)
|
288
|
+
@client.add_config_vars('myapp', {:x => 'y'})
|
289
|
+
end
|
290
|
+
|
291
|
+
it "remove_config_var(app_name, key)" do
|
292
|
+
@client.should_receive(:resource).with('/apps/myapp/config_vars/mykey').and_return(@resource)
|
293
|
+
@resource.should_receive(:delete)
|
294
|
+
@client.remove_config_var('myapp', 'mykey')
|
295
|
+
end
|
296
|
+
|
297
|
+
it "clear_config_vars(app_name) -> resets all config vars for this app" do
|
298
|
+
@client.should_receive(:resource).with('/apps/myapp/config_vars').and_return(@resource)
|
299
|
+
@resource.should_receive(:delete)
|
300
|
+
@client.clear_config_vars('myapp')
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe "addons" do
|
305
|
+
it "addons -> array with addons available for installation" do
|
306
|
+
@client.should_receive(:resource).with('/addons').and_return(@resource)
|
307
|
+
@resource.should_receive(:get).and_return '[{"name":"addon1"}, {"name":"addon2"}]'
|
308
|
+
@client.addons.should == [{'name' => 'addon1'}, {'name' => 'addon2'}]
|
309
|
+
end
|
310
|
+
|
311
|
+
it "installed_addons(app_name) -> array of installed addons" do
|
312
|
+
@client.should_receive(:resource).with('/apps/myapp/addons').and_return(@resource)
|
313
|
+
@resource.should_receive(:get).and_return '[{"name":"addon1"}]'
|
314
|
+
@client.installed_addons('myapp').should == [{'name' => 'addon1'}]
|
315
|
+
end
|
316
|
+
|
317
|
+
it "install_addon(app_name, addon_name)" do
|
318
|
+
@client.should_receive(:resource).with('/apps/myapp/addons/addon1').and_return(@resource)
|
319
|
+
@resource.should_receive(:post)
|
320
|
+
@client.install_addon('myapp', 'addon1')
|
321
|
+
end
|
322
|
+
|
323
|
+
it "uninstall_addon(app_name, addon_name)" do
|
324
|
+
@client.should_receive(:resource).with('/apps/myapp/addons/addon1').and_return(@resource)
|
325
|
+
@resource.should_receive(:delete)
|
326
|
+
@client.uninstall_addon('myapp', 'addon1')
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "internal" do
|
331
|
+
before do
|
332
|
+
@client = Heroku::Client.new(nil, nil)
|
333
|
+
end
|
334
|
+
|
335
|
+
it "creates a RestClient resource for making calls" do
|
336
|
+
@client.stub!(:host).and_return('heroku.com')
|
337
|
+
@client.stub!(:user).and_return('joe@example.com')
|
338
|
+
@client.stub!(:password).and_return('secret')
|
339
|
+
|
340
|
+
res = @client.resource('/xyz')
|
341
|
+
|
342
|
+
res.url.should == 'https://api.heroku.com/xyz'
|
343
|
+
res.user.should == 'joe@example.com'
|
344
|
+
res.password.should == 'secret'
|
345
|
+
end
|
346
|
+
|
347
|
+
it "runs a callback when the API sets a warning header" do
|
348
|
+
response = mock('rest client response', :headers => { :x_heroku_warning => 'Warning' })
|
349
|
+
@client.should_receive(:resource).with('test').and_return(@resource)
|
350
|
+
@resource.should_receive(:get).and_return(response)
|
351
|
+
@client.on_warning { |msg| @callback = msg }
|
352
|
+
@client.get('test')
|
353
|
+
@callback.should == 'Warning'
|
354
|
+
end
|
355
|
+
|
356
|
+
it "doesn't run the callback twice for the same warning" do
|
357
|
+
response = mock('rest client response', :headers => { :x_heroku_warning => 'Warning' })
|
358
|
+
@client.stub!(:resource).and_return(@resource)
|
359
|
+
@resource.stub!(:get).and_return(response)
|
360
|
+
@client.on_warning { |msg| @callback_called ||= 0; @callback_called += 1 }
|
361
|
+
@client.get('test1')
|
362
|
+
@client.get('test2')
|
363
|
+
@callback_called.should == 1
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/base'
|
2
|
+
|
3
|
+
describe Heroku::Command do
|
4
|
+
it "extracts error messages from response when available in XML" do
|
5
|
+
Heroku::Command.extract_error('<errors><error>Invalid app name</error></errors>').should == ' ! Invalid app name'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "extracts error messages from response when available in JSON" do
|
9
|
+
Heroku::Command.extract_error("{\"error\":\"Invalid app name\"}").should == ' ! Invalid app name'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shows Internal Server Error when the response doesn't contain a XML" do
|
13
|
+
Heroku::Command.extract_error('<h1>HTTP 500</h1>').should == ' ! Internal server error'
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../base'
|
2
|
+
|
3
|
+
module Heroku::Command
|
4
|
+
describe Addons do
|
5
|
+
before do
|
6
|
+
@addons = prepare_command(Addons)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "index lists installed addons" do
|
10
|
+
@addons.heroku.should_receive(:installed_addons).with('myapp').and_return([])
|
11
|
+
@addons.index
|
12
|
+
end
|
13
|
+
|
14
|
+
it "adds an addon" do
|
15
|
+
@addons.stub!(:args).and_return(%w(my_addon))
|
16
|
+
@addons.heroku.should_receive(:install_addon).with('myapp', 'my_addon', {})
|
17
|
+
@addons.add
|
18
|
+
end
|
19
|
+
|
20
|
+
it "adds an addon with config vars" do
|
21
|
+
@addons.stub!(:args).and_return(%w(my_addon foo=baz))
|
22
|
+
@addons.heroku.should_receive(:install_addon).with('myapp', 'my_addon', { 'foo' => 'baz' })
|
23
|
+
@addons.add
|
24
|
+
end
|
25
|
+
|
26
|
+
it "asks the user to confirm billing when API responds with 402" do
|
27
|
+
@addons.stub!(:args).and_return(%w( addon1 ))
|
28
|
+
e = RestClient::RequestFailed.new
|
29
|
+
e.stub!(:http_code).and_return(402)
|
30
|
+
@addons.heroku.should_receive(:install_addon).and_raise(e)
|
31
|
+
@addons.should_receive(:confirm_billing).and_return(false)
|
32
|
+
@addons.add
|
33
|
+
end
|
34
|
+
|
35
|
+
it "removes addons" do
|
36
|
+
@addons.stub!(:args).and_return(%w( addon1 ))
|
37
|
+
@addons.heroku.should_receive(:uninstall_addon).with('myapp', 'addon1')
|
38
|
+
@addons.remove
|
39
|
+
end
|
40
|
+
|
41
|
+
it "clears addons" do
|
42
|
+
@addons.heroku.should_receive(:installed_addons).with('myapp').and_return([{ 'name' => 'addon1' }])
|
43
|
+
@addons.heroku.should_receive(:uninstall_addon).with('myapp', 'addon1')
|
44
|
+
@addons.clear
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|