azuki 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +71 -0
  3. data/bin/azuki +17 -0
  4. data/data/cacert.pem +3988 -0
  5. data/lib/azuki.rb +17 -0
  6. data/lib/azuki/auth.rb +339 -0
  7. data/lib/azuki/cli.rb +38 -0
  8. data/lib/azuki/client.rb +764 -0
  9. data/lib/azuki/client/azuki_postgresql.rb +141 -0
  10. data/lib/azuki/client/cisaurus.rb +26 -0
  11. data/lib/azuki/client/pgbackups.rb +113 -0
  12. data/lib/azuki/client/rendezvous.rb +108 -0
  13. data/lib/azuki/client/ssl_endpoint.rb +25 -0
  14. data/lib/azuki/command.rb +294 -0
  15. data/lib/azuki/command/account.rb +23 -0
  16. data/lib/azuki/command/accounts.rb +34 -0
  17. data/lib/azuki/command/addons.rb +305 -0
  18. data/lib/azuki/command/apps.rb +393 -0
  19. data/lib/azuki/command/auth.rb +86 -0
  20. data/lib/azuki/command/base.rb +230 -0
  21. data/lib/azuki/command/certs.rb +209 -0
  22. data/lib/azuki/command/config.rb +137 -0
  23. data/lib/azuki/command/db.rb +218 -0
  24. data/lib/azuki/command/domains.rb +85 -0
  25. data/lib/azuki/command/drains.rb +46 -0
  26. data/lib/azuki/command/fork.rb +164 -0
  27. data/lib/azuki/command/git.rb +64 -0
  28. data/lib/azuki/command/help.rb +179 -0
  29. data/lib/azuki/command/keys.rb +115 -0
  30. data/lib/azuki/command/labs.rb +147 -0
  31. data/lib/azuki/command/logs.rb +45 -0
  32. data/lib/azuki/command/maintenance.rb +61 -0
  33. data/lib/azuki/command/pg.rb +269 -0
  34. data/lib/azuki/command/pgbackups.rb +329 -0
  35. data/lib/azuki/command/plugins.rb +110 -0
  36. data/lib/azuki/command/ps.rb +232 -0
  37. data/lib/azuki/command/regions.rb +22 -0
  38. data/lib/azuki/command/releases.rb +124 -0
  39. data/lib/azuki/command/run.rb +180 -0
  40. data/lib/azuki/command/sharing.rb +89 -0
  41. data/lib/azuki/command/ssl.rb +43 -0
  42. data/lib/azuki/command/stack.rb +62 -0
  43. data/lib/azuki/command/status.rb +51 -0
  44. data/lib/azuki/command/update.rb +47 -0
  45. data/lib/azuki/command/version.rb +23 -0
  46. data/lib/azuki/deprecated.rb +5 -0
  47. data/lib/azuki/deprecated/help.rb +38 -0
  48. data/lib/azuki/distribution.rb +9 -0
  49. data/lib/azuki/excon.rb +9 -0
  50. data/lib/azuki/helpers.rb +517 -0
  51. data/lib/azuki/helpers/azuki_postgresql.rb +165 -0
  52. data/lib/azuki/helpers/log_displayer.rb +70 -0
  53. data/lib/azuki/plugin.rb +163 -0
  54. data/lib/azuki/updater.rb +171 -0
  55. data/lib/azuki/version.rb +3 -0
  56. data/lib/vendor/azuki/okjson.rb +598 -0
  57. data/spec/azuki/auth_spec.rb +256 -0
  58. data/spec/azuki/client/azuki_postgresql_spec.rb +71 -0
  59. data/spec/azuki/client/pgbackups_spec.rb +43 -0
  60. data/spec/azuki/client/rendezvous_spec.rb +62 -0
  61. data/spec/azuki/client/ssl_endpoint_spec.rb +48 -0
  62. data/spec/azuki/client_spec.rb +564 -0
  63. data/spec/azuki/command/addons_spec.rb +601 -0
  64. data/spec/azuki/command/apps_spec.rb +351 -0
  65. data/spec/azuki/command/auth_spec.rb +38 -0
  66. data/spec/azuki/command/base_spec.rb +109 -0
  67. data/spec/azuki/command/certs_spec.rb +178 -0
  68. data/spec/azuki/command/config_spec.rb +144 -0
  69. data/spec/azuki/command/db_spec.rb +110 -0
  70. data/spec/azuki/command/domains_spec.rb +87 -0
  71. data/spec/azuki/command/drains_spec.rb +34 -0
  72. data/spec/azuki/command/fork_spec.rb +56 -0
  73. data/spec/azuki/command/git_spec.rb +144 -0
  74. data/spec/azuki/command/help_spec.rb +93 -0
  75. data/spec/azuki/command/keys_spec.rb +120 -0
  76. data/spec/azuki/command/labs_spec.rb +100 -0
  77. data/spec/azuki/command/logs_spec.rb +60 -0
  78. data/spec/azuki/command/maintenance_spec.rb +51 -0
  79. data/spec/azuki/command/pg_spec.rb +236 -0
  80. data/spec/azuki/command/pgbackups_spec.rb +307 -0
  81. data/spec/azuki/command/plugins_spec.rb +104 -0
  82. data/spec/azuki/command/ps_spec.rb +195 -0
  83. data/spec/azuki/command/releases_spec.rb +130 -0
  84. data/spec/azuki/command/run_spec.rb +83 -0
  85. data/spec/azuki/command/sharing_spec.rb +59 -0
  86. data/spec/azuki/command/stack_spec.rb +46 -0
  87. data/spec/azuki/command/status_spec.rb +48 -0
  88. data/spec/azuki/command/version_spec.rb +16 -0
  89. data/spec/azuki/command_spec.rb +211 -0
  90. data/spec/azuki/helpers/azuki_postgresql_spec.rb +155 -0
  91. data/spec/azuki/helpers_spec.rb +48 -0
  92. data/spec/azuki/plugin_spec.rb +172 -0
  93. data/spec/azuki/updater_spec.rb +44 -0
  94. data/spec/helper/legacy_help.rb +16 -0
  95. data/spec/spec.opts +1 -0
  96. data/spec/spec_helper.rb +224 -0
  97. data/spec/support/display_message_matcher.rb +49 -0
  98. data/spec/support/openssl_mock_helper.rb +8 -0
  99. metadata +211 -0
@@ -0,0 +1,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
+
@@ -0,0 +1 @@
1
+ --color
@@ -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
+