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,155 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/helpers/azuki_postgresql"
|
|
3
|
+
|
|
4
|
+
include Azuki::Helpers::AzukiPostgresql
|
|
5
|
+
|
|
6
|
+
describe Azuki::Helpers::AzukiPostgresql do
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
subject.forget_config!
|
|
10
|
+
subject.stub(:app_config_vars) { app_config_vars }
|
|
11
|
+
subject.stub(:app_attachments) { app_attachments }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
let(:app_config_vars) do
|
|
15
|
+
{
|
|
16
|
+
"DATABASE_URL" => "postgres://default",
|
|
17
|
+
"AZUKI_POSTGRESQL_BLACK_URL" => "postgres://black",
|
|
18
|
+
"AZUKI_POSTGRESQL_IVORY_URL" => "postgres://default",
|
|
19
|
+
"SHARED_DATABASE_URL" => "postgres://shared"
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
let(:app_attachments) {
|
|
24
|
+
[ Attachment.new({ 'config_var' => 'AZUKI_POSTGRESQL_IVORY_URL',
|
|
25
|
+
'resource' => {'name' => 'softly-mocking-123',
|
|
26
|
+
'value' => 'postgres://default',
|
|
27
|
+
'type' => 'azuki-postgresql:baku' }}),
|
|
28
|
+
Attachment.new({ 'config_var' => 'AZUKI_POSTGRESQL_BLACK_URL',
|
|
29
|
+
'resource' => {'name' => 'quickly-yelling-2421',
|
|
30
|
+
'value' => 'postgres://black',
|
|
31
|
+
'type' => 'azuki-postgresql:zilla' }})
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
context "when the DATABASE_URL has query options" do
|
|
36
|
+
let(:app_config_vars) do
|
|
37
|
+
{
|
|
38
|
+
"DATABASE_URL" => "postgres://default?pool=15",
|
|
39
|
+
"AZUKI_POSTGRESQL_BLACK_URL" => "postgres://black",
|
|
40
|
+
"AZUKI_POSTGRESQL_IVORY_URL" => "postgres://default",
|
|
41
|
+
"SHARED_DATABASE_URL" => "postgres://shared"
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "resolves DATABASE" do
|
|
46
|
+
att = subject.hpg_resolve('DATABASE')
|
|
47
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
48
|
+
att.url.should == "postgres://default"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "when the DATABASE_URL has no query options" do
|
|
53
|
+
let(:app_config_vars) do
|
|
54
|
+
{
|
|
55
|
+
"DATABASE_URL" => "postgres://default",
|
|
56
|
+
"AZUKI_POSTGRESQL_BLACK_URL" => "postgres://black",
|
|
57
|
+
"AZUKI_POSTGRESQL_IVORY_URL" => "postgres://default",
|
|
58
|
+
"SHARED_DATABASE_URL" => "postgres://shared"
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "resolves DATABASE" do
|
|
63
|
+
att = subject.hpg_resolve('DATABASE')
|
|
64
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
65
|
+
att.url.should == "postgres://default"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "resolves SHARED_DATABASE" do
|
|
70
|
+
att = subject.hpg_resolve('SHARED_DATABASE')
|
|
71
|
+
att.display_name.should == "SHARED_DATABASE"
|
|
72
|
+
att.url.should == "postgres://shared"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "resolves default using NAME" do
|
|
76
|
+
att = subject.hpg_resolve('IVORY')
|
|
77
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
78
|
+
att.url.should == "postgres://default"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "resolves non-default using NAME" do
|
|
82
|
+
att = subject.hpg_resolve('BLACK')
|
|
83
|
+
att.display_name.should == "AZUKI_POSTGRESQL_BLACK_URL"
|
|
84
|
+
att.url.should == "postgres://black"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "resolves default using NAME_URL" do
|
|
88
|
+
att = subject.hpg_resolve('IVORY_URL')
|
|
89
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
90
|
+
att.url.should == "postgres://default"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "resolves non-default using NAME_URL" do
|
|
94
|
+
att = subject.hpg_resolve('BLACK_URL')
|
|
95
|
+
att.display_name.should == "AZUKI_POSTGRESQL_BLACK_URL"
|
|
96
|
+
att.url.should == "postgres://black"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "resolves default using lowercase" do
|
|
100
|
+
att = subject.hpg_resolve('ivory')
|
|
101
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
102
|
+
att.url.should == "postgres://default"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "resolves non-default using lowercase" do
|
|
106
|
+
att = subject.hpg_resolve('black')
|
|
107
|
+
att.display_name.should == "AZUKI_POSTGRESQL_BLACK_URL"
|
|
108
|
+
att.url.should == "postgres://black"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "resolves non-default using part of name" do
|
|
112
|
+
att = subject.hpg_resolve('bla')
|
|
113
|
+
att.display_name.should == "AZUKI_POSTGRESQL_BLACK_URL"
|
|
114
|
+
att.url.should == "postgres://black"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "throws an error if it doesnt exist" do
|
|
118
|
+
subject.should_receive(:error).with("Unknown database: violet. Valid options are: DATABASE_URL, AZUKI_POSTGRESQL_BLACK_URL, AZUKI_POSTGRESQL_IVORY_URL, SHARED_DATABASE")
|
|
119
|
+
subject.hpg_resolve("violet")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
context "default" do
|
|
123
|
+
|
|
124
|
+
it "errors if there is no default" do
|
|
125
|
+
subject.should_receive(:error).with("Unknown database. Valid options are: DATABASE_URL, AZUKI_POSTGRESQL_BLACK_URL, AZUKI_POSTGRESQL_IVORY_URL, SHARED_DATABASE")
|
|
126
|
+
subject.hpg_resolve(nil)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "uses the default if nothing(nil) specified" do
|
|
130
|
+
att = subject.hpg_resolve(nil, "DATABASE_URL")
|
|
131
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
132
|
+
att.url.should == "postgres://default"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "uses the default if nothing(empty) specified" do
|
|
136
|
+
att = subject.hpg_resolve('', "DATABASE_URL")
|
|
137
|
+
att.display_name.should == "AZUKI_POSTGRESQL_IVORY_URL (DATABASE_URL)"
|
|
138
|
+
att.url.should == "postgres://default"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'throws an error if given an empty string and asked for the default and there is no default' do
|
|
142
|
+
app_config_vars.delete 'DATABASE_URL'
|
|
143
|
+
subject.should_receive(:error).with("Unknown database. Valid options are: AZUKI_POSTGRESQL_BLACK_URL, AZUKI_POSTGRESQL_IVORY_URL, SHARED_DATABASE")
|
|
144
|
+
att = subject.hpg_resolve('', "DATABASE_URL")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'throws an error if given an empty string and asked for the default and the default doesnt match' do
|
|
148
|
+
app_config_vars['DATABASE_URL'] = 'something different'
|
|
149
|
+
subject.should_receive(:error).with("Unknown database. Valid options are: AZUKI_POSTGRESQL_BLACK_URL, AZUKI_POSTGRESQL_IVORY_URL, SHARED_DATABASE")
|
|
150
|
+
att = subject.hpg_resolve('', "DATABASE_URL")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/helpers"
|
|
3
|
+
|
|
4
|
+
module Azuki
|
|
5
|
+
describe Helpers do
|
|
6
|
+
include Azuki::Helpers
|
|
7
|
+
|
|
8
|
+
context "display_object" do
|
|
9
|
+
|
|
10
|
+
it "should display Array correctly" do
|
|
11
|
+
capture_stdout do
|
|
12
|
+
display_object([1,2,3])
|
|
13
|
+
end.should == <<-OUT
|
|
14
|
+
1
|
|
15
|
+
2
|
|
16
|
+
3
|
|
17
|
+
OUT
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should display { :header => [] } list correctly" do
|
|
21
|
+
capture_stdout do
|
|
22
|
+
display_object({:first_header => [1,2,3], :last_header => [7,8,9]})
|
|
23
|
+
end.should == <<-OUT
|
|
24
|
+
=== first_header
|
|
25
|
+
1
|
|
26
|
+
2
|
|
27
|
+
3
|
|
28
|
+
|
|
29
|
+
=== last_header
|
|
30
|
+
7
|
|
31
|
+
8
|
|
32
|
+
9
|
|
33
|
+
|
|
34
|
+
OUT
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should display String properly" do
|
|
38
|
+
capture_stdout do
|
|
39
|
+
display_object('string')
|
|
40
|
+
end.should == <<-OUT
|
|
41
|
+
string
|
|
42
|
+
OUT
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/plugin"
|
|
3
|
+
|
|
4
|
+
module Azuki
|
|
5
|
+
describe Plugin do
|
|
6
|
+
include SandboxHelper
|
|
7
|
+
|
|
8
|
+
it "lives in ~/.azuki/plugins" do
|
|
9
|
+
Plugin.stub!(:home_directory).and_return('/home/user')
|
|
10
|
+
Plugin.directory.should == '/home/user/.azuki/plugins'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "extracts the name from git urls" do
|
|
14
|
+
Plugin.new('git://github.com/azuki/plugin.git').name.should == 'plugin'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "management" do
|
|
18
|
+
before(:each) do
|
|
19
|
+
@sandbox = "/tmp/azuki_plugins_spec_#{Process.pid}"
|
|
20
|
+
FileUtils.mkdir_p(@sandbox)
|
|
21
|
+
Dir.stub!(:pwd).and_return(@sandbox)
|
|
22
|
+
Plugin.stub!(:directory).and_return(@sandbox)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
after(:each) do
|
|
26
|
+
FileUtils.rm_rf(@sandbox)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "lists installed plugins" do
|
|
30
|
+
FileUtils.mkdir_p(@sandbox + '/plugin1')
|
|
31
|
+
FileUtils.mkdir_p(@sandbox + '/plugin2')
|
|
32
|
+
Plugin.list.should include 'plugin1'
|
|
33
|
+
Plugin.list.should include 'plugin2'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "installs pulling from the plugin url" do
|
|
37
|
+
plugin_folder = "/tmp/azuki_plugin"
|
|
38
|
+
FileUtils.mkdir_p(plugin_folder)
|
|
39
|
+
`cd #{plugin_folder} && git init && echo 'test' > README && git add . && git commit -m 'my plugin'`
|
|
40
|
+
Plugin.new(plugin_folder).install
|
|
41
|
+
File.directory?("#{@sandbox}/azuki_plugin").should be_true
|
|
42
|
+
File.read("#{@sandbox}/azuki_plugin/README").should == "test\n"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "reinstalls over old copies" do
|
|
46
|
+
plugin_folder = "/tmp/azuki_plugin"
|
|
47
|
+
FileUtils.mkdir_p(plugin_folder)
|
|
48
|
+
`cd #{plugin_folder} && git init && echo 'test' > README && git add . && git commit -m 'my plugin'`
|
|
49
|
+
Plugin.new(plugin_folder).install
|
|
50
|
+
Plugin.new(plugin_folder).install
|
|
51
|
+
File.directory?("#{@sandbox}/azuki_plugin").should be_true
|
|
52
|
+
File.read("#{@sandbox}/azuki_plugin/README").should == "test\n"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "update" do
|
|
56
|
+
|
|
57
|
+
before(:each) do
|
|
58
|
+
plugin_folder = "/tmp/azuki_plugin"
|
|
59
|
+
FileUtils.mkdir_p(plugin_folder)
|
|
60
|
+
`cd #{plugin_folder} && git init && echo 'test' > README && git add . && git commit -m 'my plugin'`
|
|
61
|
+
Plugin.new(plugin_folder).install
|
|
62
|
+
`cd #{plugin_folder} && echo 'updated' > README && git add . && git commit -m 'my plugin update'`
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "updates existing copies" do
|
|
66
|
+
Plugin.new('azuki_plugin').update
|
|
67
|
+
File.directory?("#{@sandbox}/azuki_plugin").should be_true
|
|
68
|
+
File.read("#{@sandbox}/azuki_plugin/README").should == "updated\n"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "warns on legacy plugins" do
|
|
72
|
+
`cd #{@sandbox}/azuki_plugin && git config --unset branch.master.remote`
|
|
73
|
+
stderr = capture_stderr do
|
|
74
|
+
begin
|
|
75
|
+
Plugin.new('azuki_plugin').update
|
|
76
|
+
rescue SystemExit
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
stderr.should == <<-STDERR
|
|
80
|
+
! azuki_plugin is a legacy plugin installation.
|
|
81
|
+
! Enable updating by reinstalling with `azuki plugins:install`.
|
|
82
|
+
STDERR
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "raises exception on symlinked plugins" do
|
|
86
|
+
`cd #{@sandbox} && ln -s azuki_plugin azuki_plugin_symlink`
|
|
87
|
+
lambda { Plugin.new('azuki_plugin_symlink').update }.should raise_error Azuki::Plugin::ErrorUpdatingSymlinkPlugin
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
it "uninstalls removing the folder" do
|
|
94
|
+
FileUtils.mkdir_p(@sandbox + '/plugin1')
|
|
95
|
+
Plugin.new('git://github.com/azuki/plugin1.git').uninstall
|
|
96
|
+
Plugin.list.should == []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "adds the lib folder in the plugin to the load path, if present" do
|
|
100
|
+
FileUtils.mkdir_p(@sandbox + '/plugin/lib')
|
|
101
|
+
File.open(@sandbox + '/plugin/lib/my_custom_plugin_file.rb', 'w') { |f| f.write "" }
|
|
102
|
+
Plugin.load!
|
|
103
|
+
lambda { require 'my_custom_plugin_file' }.should_not raise_error(LoadError)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "loads init.rb, if present" do
|
|
107
|
+
FileUtils.mkdir_p(@sandbox + '/plugin')
|
|
108
|
+
File.open(@sandbox + '/plugin/init.rb', 'w') { |f| f.write "LoadedInit = true" }
|
|
109
|
+
Plugin.load!
|
|
110
|
+
LoadedInit.should be_true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "when there are plugin load errors" do
|
|
114
|
+
before(:each) do
|
|
115
|
+
FileUtils.mkdir_p(@sandbox + '/some_plugin/lib')
|
|
116
|
+
File.open(@sandbox + '/some_plugin/init.rb', 'w') { |f| f.write "require 'some_non_existant_file'" }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should not throw an error" do
|
|
120
|
+
capture_stderr do
|
|
121
|
+
lambda { Plugin.load! }.should_not raise_error
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should fail gracefully" do
|
|
126
|
+
stderr = capture_stderr do
|
|
127
|
+
Plugin.load!
|
|
128
|
+
end
|
|
129
|
+
stderr.should include('some_non_existant_file (LoadError)')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "should still load other plugins" do
|
|
133
|
+
FileUtils.mkdir_p(@sandbox + '/some_plugin_2/lib')
|
|
134
|
+
File.open(@sandbox + '/some_plugin_2/init.rb', 'w') { |f| f.write "LoadedPlugin2 = true" }
|
|
135
|
+
stderr = capture_stderr do
|
|
136
|
+
Plugin.load!
|
|
137
|
+
end
|
|
138
|
+
stderr.should include('some_non_existant_file (LoadError)')
|
|
139
|
+
LoadedPlugin2.should be_true
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe "deprecated plugins" do
|
|
144
|
+
before(:each) do
|
|
145
|
+
FileUtils.mkdir_p(@sandbox + '/azuki-releases/lib')
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
after(:each) do
|
|
149
|
+
FileUtils.rm_rf(@sandbox + '/azuki-releases/lib')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "should show confirmation to remove deprecated plugins if in an interactive shell" do
|
|
153
|
+
old_stdin_isatty = STDIN.isatty
|
|
154
|
+
STDIN.stub!(:isatty).and_return(true)
|
|
155
|
+
Plugin.should_receive(:confirm).with("The plugin azuki-releases has been deprecated. Would you like to remove it? (y/N)").and_return(true)
|
|
156
|
+
Plugin.should_receive(:remove_plugin).with("azuki-releases")
|
|
157
|
+
Plugin.load!
|
|
158
|
+
STDIN.stub!(:isatty).and_return(old_stdin_isatty)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "should not prompt for deprecation if not in an interactive shell" do
|
|
162
|
+
old_stdin_isatty = STDIN.isatty
|
|
163
|
+
STDIN.stub!(:isatty).and_return(false)
|
|
164
|
+
Plugin.should_not_receive(:confirm)
|
|
165
|
+
Plugin.should_not_receive(:remove_plugin).with("azuki-releases")
|
|
166
|
+
Plugin.load!
|
|
167
|
+
STDIN.stub!(:isatty).and_return(old_stdin_isatty)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/updater"
|
|
3
|
+
require "azuki/version"
|
|
4
|
+
|
|
5
|
+
module Azuki
|
|
6
|
+
describe Updater do
|
|
7
|
+
|
|
8
|
+
it "calculates the latest local version" do
|
|
9
|
+
Azuki::Updater.latest_local_version.should == Azuki::VERSION
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "calculates compare_versions" do
|
|
13
|
+
Azuki::Updater.compare_versions('1.1.1', '1.1.1').should == 0
|
|
14
|
+
|
|
15
|
+
Azuki::Updater.compare_versions('2.1.1', '1.1.1').should == 1
|
|
16
|
+
Azuki::Updater.compare_versions('1.1.1', '2.1.1').should == -1
|
|
17
|
+
|
|
18
|
+
Azuki::Updater.compare_versions('1.2.1', '1.1.1').should == 1
|
|
19
|
+
Azuki::Updater.compare_versions('1.1.1', '1.2.1').should == -1
|
|
20
|
+
|
|
21
|
+
Azuki::Updater.compare_versions('1.1.2', '1.1.1').should == 1
|
|
22
|
+
Azuki::Updater.compare_versions('1.1.1', '1.1.2').should == -1
|
|
23
|
+
|
|
24
|
+
Azuki::Updater.compare_versions('2.1.1', '1.2.1').should == 1
|
|
25
|
+
Azuki::Updater.compare_versions('1.2.1', '2.1.1').should == -1
|
|
26
|
+
|
|
27
|
+
Azuki::Updater.compare_versions('2.1.1', '1.1.2').should == 1
|
|
28
|
+
Azuki::Updater.compare_versions('1.1.2', '2.1.1').should == -1
|
|
29
|
+
|
|
30
|
+
Azuki::Updater.compare_versions('1.2.4', '1.2.3').should == 1
|
|
31
|
+
Azuki::Updater.compare_versions('1.2.3', '1.2.4').should == -1
|
|
32
|
+
|
|
33
|
+
Azuki::Updater.compare_versions('1.2.1', '1.2' ).should == 1
|
|
34
|
+
Azuki::Updater.compare_versions('1.2', '1.2.1').should == -1
|
|
35
|
+
|
|
36
|
+
Azuki::Updater.compare_versions('1.1.1.pre1', '1.1.1').should == 1
|
|
37
|
+
Azuki::Updater.compare_versions('1.1.1', '1.1.1.pre1').should == -1
|
|
38
|
+
|
|
39
|
+
Azuki::Updater.compare_versions('1.1.1.pre2', '1.1.1.pre1').should == 1
|
|
40
|
+
Azuki::Updater.compare_versions('1.1.1.pre1', '1.1.1.pre2').should == -1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "azuki/command/help"
|
|
2
|
+
|
|
3
|
+
Azuki::Command::Help.group("Foo Group") do |foo|
|
|
4
|
+
foo.command "foo:bar", "do a bar to foo"
|
|
5
|
+
foo.space
|
|
6
|
+
foo.command "foo:baz", "do a baz to foo"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Azuki::Command::Foo < Azuki::Command::Base
|
|
10
|
+
def bar
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def baz
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
data/spec/spec.opts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
$stdin = File.new("/dev/null")
|
|
2
|
+
|
|
3
|
+
require "rubygems"
|
|
4
|
+
|
|
5
|
+
require "excon"
|
|
6
|
+
Excon.defaults[:mock] = true
|
|
7
|
+
|
|
8
|
+
# ensure these are around for errors
|
|
9
|
+
# as their require is generally deferred
|
|
10
|
+
require "azuki-api"
|
|
11
|
+
require "rest_client"
|
|
12
|
+
|
|
13
|
+
require "azuki/cli"
|
|
14
|
+
require "rspec"
|
|
15
|
+
require "rr"
|
|
16
|
+
require "fakefs/safe"
|
|
17
|
+
require 'tmpdir'
|
|
18
|
+
require "webmock/rspec"
|
|
19
|
+
|
|
20
|
+
include WebMock::API
|
|
21
|
+
|
|
22
|
+
WebMock::HttpLibAdapters::ExconAdapter.disable!
|
|
23
|
+
|
|
24
|
+
def api
|
|
25
|
+
Azuki::API.new(:api_key => "pass", :mock => true)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def stub_api_request(method, path)
|
|
29
|
+
stub_request(method, "https://api.azukiapp.com#{path}")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def prepare_command(klass)
|
|
33
|
+
command = klass.new
|
|
34
|
+
command.stub!(:app).and_return("example")
|
|
35
|
+
command.stub!(:ask).and_return("")
|
|
36
|
+
command.stub!(:display)
|
|
37
|
+
command.stub!(:hputs)
|
|
38
|
+
command.stub!(:hprint)
|
|
39
|
+
command.stub!(:azuki).and_return(mock('azuki client', :host => 'azukiapp.com'))
|
|
40
|
+
command
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def execute(command_line)
|
|
44
|
+
extend RR::Adapters::RRMethods
|
|
45
|
+
|
|
46
|
+
args = command_line.split(" ")
|
|
47
|
+
command = args.shift
|
|
48
|
+
|
|
49
|
+
Azuki::Command.load
|
|
50
|
+
object, method = Azuki::Command.prepare_run(command, args)
|
|
51
|
+
|
|
52
|
+
any_instance_of(Azuki::Command::Base) do |base|
|
|
53
|
+
stub(base).app.returns("example")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
stub(Azuki::Auth).get_credentials.returns(['email@example.com', 'apikey01'])
|
|
57
|
+
stub(Azuki::Auth).api_key.returns('apikey01')
|
|
58
|
+
|
|
59
|
+
original_stdin, original_stderr, original_stdout = $stdin, $stderr, $stdout
|
|
60
|
+
|
|
61
|
+
$stdin = captured_stdin = StringIO.new
|
|
62
|
+
$stderr = captured_stderr = StringIO.new
|
|
63
|
+
$stdout = captured_stdout = StringIO.new
|
|
64
|
+
class << captured_stdout
|
|
65
|
+
def tty?
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
begin
|
|
71
|
+
object.send(method)
|
|
72
|
+
rescue SystemExit
|
|
73
|
+
ensure
|
|
74
|
+
$stdin, $stderr, $stdout = original_stdin, original_stderr, original_stdout
|
|
75
|
+
Azuki::Command.current_command = nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
[captured_stderr.string, captured_stdout.string]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def any_instance_of(klass, &block)
|
|
82
|
+
extend RR::Adapters::RRMethods
|
|
83
|
+
any_instance_of(klass, &block)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def run(command_line)
|
|
87
|
+
capture_stdout do
|
|
88
|
+
begin
|
|
89
|
+
Azuki::CLI.start(*command_line.split(" "))
|
|
90
|
+
rescue SystemExit
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
alias azuki run
|
|
96
|
+
|
|
97
|
+
def capture_stderr(&block)
|
|
98
|
+
original_stderr = $stderr
|
|
99
|
+
$stderr = captured_stderr = StringIO.new
|
|
100
|
+
begin
|
|
101
|
+
yield
|
|
102
|
+
ensure
|
|
103
|
+
$stderr = original_stderr
|
|
104
|
+
end
|
|
105
|
+
captured_stderr.string
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def capture_stdout(&block)
|
|
109
|
+
original_stdout = $stdout
|
|
110
|
+
$stdout = captured_stdout = StringIO.new
|
|
111
|
+
begin
|
|
112
|
+
yield
|
|
113
|
+
ensure
|
|
114
|
+
$stdout = original_stdout
|
|
115
|
+
end
|
|
116
|
+
captured_stdout.string
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def fail_command(message)
|
|
120
|
+
raise_error(Azuki::Command::CommandFailed, message)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def stub_core
|
|
124
|
+
@stubbed_core ||= begin
|
|
125
|
+
stubbed_core = nil
|
|
126
|
+
any_instance_of(Azuki::Client) do |core|
|
|
127
|
+
stubbed_core = stub(core)
|
|
128
|
+
end
|
|
129
|
+
stub(Azuki::Auth).user.returns("email@example.com")
|
|
130
|
+
stub(Azuki::Auth).password.returns("pass")
|
|
131
|
+
stub(Azuki::Client).auth.returns("apikey01")
|
|
132
|
+
stubbed_core
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def stub_pg
|
|
137
|
+
@stubbed_pg ||= begin
|
|
138
|
+
stubbed_pg = nil
|
|
139
|
+
any_instance_of(Azuki::Client::AzukiPostgresql) do |pg|
|
|
140
|
+
stubbed_pg = stub(pg)
|
|
141
|
+
end
|
|
142
|
+
stubbed_pg
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def stub_pgbackups
|
|
147
|
+
@stubbed_pgbackups ||= begin
|
|
148
|
+
stubbed_pgbackups = nil
|
|
149
|
+
any_instance_of(Azuki::Client::Pgbackups) do |pgbackups|
|
|
150
|
+
stubbed_pgbackups = stub(pgbackups)
|
|
151
|
+
end
|
|
152
|
+
stubbed_pgbackups
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def stub_rendezvous
|
|
157
|
+
@stubbed_rendezvous ||= begin
|
|
158
|
+
stubbed_rendezvous = nil
|
|
159
|
+
any_instance_of(Azuki::Client::Rendezvous) do |rendezvous|
|
|
160
|
+
stubbed_rendezvous = stub(rendezvous)
|
|
161
|
+
end
|
|
162
|
+
stubbed_rendezvous
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def stub_cisaurus
|
|
167
|
+
@stub_cisaurus ||= begin
|
|
168
|
+
stub_cisaurus = nil
|
|
169
|
+
any_instance_of(Azuki::Client::Cisaurus) do |cisaurus|
|
|
170
|
+
stub_cisaurus = stub(cisaurus)
|
|
171
|
+
end
|
|
172
|
+
stub_cisaurus
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def with_blank_git_repository(&block)
|
|
177
|
+
sandbox = File.join(Dir.tmpdir, "azuki", Process.pid.to_s)
|
|
178
|
+
FileUtils.mkdir_p(sandbox)
|
|
179
|
+
|
|
180
|
+
old_dir = Dir.pwd
|
|
181
|
+
Dir.chdir(sandbox)
|
|
182
|
+
|
|
183
|
+
`git init`
|
|
184
|
+
block.call
|
|
185
|
+
|
|
186
|
+
FileUtils.rm_rf(sandbox)
|
|
187
|
+
ensure
|
|
188
|
+
Dir.chdir(old_dir)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def taps_available?
|
|
192
|
+
begin
|
|
193
|
+
require "taps/operation"
|
|
194
|
+
true
|
|
195
|
+
rescue LoadError
|
|
196
|
+
false
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
module SandboxHelper
|
|
201
|
+
def bash(cmd)
|
|
202
|
+
`#{cmd}`
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
require "azuki/helpers"
|
|
207
|
+
module Azuki::Helpers
|
|
208
|
+
@home_directory = Dir.mktmpdir
|
|
209
|
+
undef_method :home_directory
|
|
210
|
+
def home_directory
|
|
211
|
+
@home_directory
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
require "support/display_message_matcher"
|
|
216
|
+
|
|
217
|
+
RSpec.configure do |config|
|
|
218
|
+
config.color_enabled = true
|
|
219
|
+
config.include DisplayMessageMatcher
|
|
220
|
+
config.order = 'rand'
|
|
221
|
+
config.before { Azuki::Helpers.error_with_failure = false }
|
|
222
|
+
config.after { RR.reset }
|
|
223
|
+
end
|
|
224
|
+
|