azuki 0.0.1
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.
- checksums.yaml +7 -0
- data/README.md +71 -0
- data/bin/azuki +17 -0
- data/data/cacert.pem +3988 -0
- data/lib/azuki.rb +17 -0
- data/lib/azuki/auth.rb +339 -0
- data/lib/azuki/cli.rb +38 -0
- data/lib/azuki/client.rb +764 -0
- data/lib/azuki/client/azuki_postgresql.rb +141 -0
- data/lib/azuki/client/cisaurus.rb +26 -0
- data/lib/azuki/client/pgbackups.rb +113 -0
- data/lib/azuki/client/rendezvous.rb +108 -0
- data/lib/azuki/client/ssl_endpoint.rb +25 -0
- data/lib/azuki/command.rb +294 -0
- data/lib/azuki/command/account.rb +23 -0
- data/lib/azuki/command/accounts.rb +34 -0
- data/lib/azuki/command/addons.rb +305 -0
- data/lib/azuki/command/apps.rb +393 -0
- data/lib/azuki/command/auth.rb +86 -0
- data/lib/azuki/command/base.rb +230 -0
- data/lib/azuki/command/certs.rb +209 -0
- data/lib/azuki/command/config.rb +137 -0
- data/lib/azuki/command/db.rb +218 -0
- data/lib/azuki/command/domains.rb +85 -0
- data/lib/azuki/command/drains.rb +46 -0
- data/lib/azuki/command/fork.rb +164 -0
- data/lib/azuki/command/git.rb +64 -0
- data/lib/azuki/command/help.rb +179 -0
- data/lib/azuki/command/keys.rb +115 -0
- data/lib/azuki/command/labs.rb +147 -0
- data/lib/azuki/command/logs.rb +45 -0
- data/lib/azuki/command/maintenance.rb +61 -0
- data/lib/azuki/command/pg.rb +269 -0
- data/lib/azuki/command/pgbackups.rb +329 -0
- data/lib/azuki/command/plugins.rb +110 -0
- data/lib/azuki/command/ps.rb +232 -0
- data/lib/azuki/command/regions.rb +22 -0
- data/lib/azuki/command/releases.rb +124 -0
- data/lib/azuki/command/run.rb +180 -0
- data/lib/azuki/command/sharing.rb +89 -0
- data/lib/azuki/command/ssl.rb +43 -0
- data/lib/azuki/command/stack.rb +62 -0
- data/lib/azuki/command/status.rb +51 -0
- data/lib/azuki/command/update.rb +47 -0
- data/lib/azuki/command/version.rb +23 -0
- data/lib/azuki/deprecated.rb +5 -0
- data/lib/azuki/deprecated/help.rb +38 -0
- data/lib/azuki/distribution.rb +9 -0
- data/lib/azuki/excon.rb +9 -0
- data/lib/azuki/helpers.rb +517 -0
- data/lib/azuki/helpers/azuki_postgresql.rb +165 -0
- data/lib/azuki/helpers/log_displayer.rb +70 -0
- data/lib/azuki/plugin.rb +163 -0
- data/lib/azuki/updater.rb +171 -0
- data/lib/azuki/version.rb +3 -0
- data/lib/vendor/azuki/okjson.rb +598 -0
- data/spec/azuki/auth_spec.rb +256 -0
- data/spec/azuki/client/azuki_postgresql_spec.rb +71 -0
- data/spec/azuki/client/pgbackups_spec.rb +43 -0
- data/spec/azuki/client/rendezvous_spec.rb +62 -0
- data/spec/azuki/client/ssl_endpoint_spec.rb +48 -0
- data/spec/azuki/client_spec.rb +564 -0
- data/spec/azuki/command/addons_spec.rb +601 -0
- data/spec/azuki/command/apps_spec.rb +351 -0
- data/spec/azuki/command/auth_spec.rb +38 -0
- data/spec/azuki/command/base_spec.rb +109 -0
- data/spec/azuki/command/certs_spec.rb +178 -0
- data/spec/azuki/command/config_spec.rb +144 -0
- data/spec/azuki/command/db_spec.rb +110 -0
- data/spec/azuki/command/domains_spec.rb +87 -0
- data/spec/azuki/command/drains_spec.rb +34 -0
- data/spec/azuki/command/fork_spec.rb +56 -0
- data/spec/azuki/command/git_spec.rb +144 -0
- data/spec/azuki/command/help_spec.rb +93 -0
- data/spec/azuki/command/keys_spec.rb +120 -0
- data/spec/azuki/command/labs_spec.rb +100 -0
- data/spec/azuki/command/logs_spec.rb +60 -0
- data/spec/azuki/command/maintenance_spec.rb +51 -0
- data/spec/azuki/command/pg_spec.rb +236 -0
- data/spec/azuki/command/pgbackups_spec.rb +307 -0
- data/spec/azuki/command/plugins_spec.rb +104 -0
- data/spec/azuki/command/ps_spec.rb +195 -0
- data/spec/azuki/command/releases_spec.rb +130 -0
- data/spec/azuki/command/run_spec.rb +83 -0
- data/spec/azuki/command/sharing_spec.rb +59 -0
- data/spec/azuki/command/stack_spec.rb +46 -0
- data/spec/azuki/command/status_spec.rb +48 -0
- data/spec/azuki/command/version_spec.rb +16 -0
- data/spec/azuki/command_spec.rb +211 -0
- data/spec/azuki/helpers/azuki_postgresql_spec.rb +155 -0
- data/spec/azuki/helpers_spec.rb +48 -0
- data/spec/azuki/plugin_spec.rb +172 -0
- data/spec/azuki/updater_spec.rb +44 -0
- data/spec/helper/legacy_help.rb +16 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +224 -0
- data/spec/support/display_message_matcher.rb +49 -0
- data/spec/support/openssl_mock_helper.rb +8 -0
- 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
|