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,256 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/auth"
|
|
3
|
+
require "azuki/helpers"
|
|
4
|
+
|
|
5
|
+
module Azuki
|
|
6
|
+
describe Auth do
|
|
7
|
+
include Azuki::Helpers
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
ENV['AZUKI_API_KEY'] = nil
|
|
11
|
+
|
|
12
|
+
@cli = Azuki::Auth
|
|
13
|
+
@cli.stub!(:check)
|
|
14
|
+
@cli.stub!(:display)
|
|
15
|
+
@cli.stub!(:running_on_a_mac?).and_return(false)
|
|
16
|
+
@cli.credentials = nil
|
|
17
|
+
|
|
18
|
+
FakeFS.activate!
|
|
19
|
+
|
|
20
|
+
FakeFS::File.stub!(:stat).and_return(double('stat', :mode => "0600".to_i(8)))
|
|
21
|
+
FakeFS::FileUtils.stub!(:chmod)
|
|
22
|
+
FakeFS::File.stub!(:readlines) do |path|
|
|
23
|
+
File.read(path).split("\n").map {|line| "#{line}\n"}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
FileUtils.mkdir_p(@cli.netrc_path.split("/")[0..-2].join("/"))
|
|
27
|
+
|
|
28
|
+
File.open(@cli.netrc_path, "w") do |file|
|
|
29
|
+
file.puts("machine api.azukiapp.com\n login user\n password pass\n")
|
|
30
|
+
file.puts("machine code.azukiapp.com\n login user\n password pass\n")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
after do
|
|
35
|
+
FileUtils.rm_rf(@cli.netrc_path)
|
|
36
|
+
FakeFS.deactivate!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "legacy credentials" do
|
|
40
|
+
|
|
41
|
+
before do
|
|
42
|
+
FileUtils.rm_rf(@cli.netrc_path)
|
|
43
|
+
FileUtils.mkdir_p(File.dirname(@cli.legacy_credentials_path))
|
|
44
|
+
File.open(@cli.legacy_credentials_path, "w") do |file|
|
|
45
|
+
file.puts "legacy_user\nlegacy_pass"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should translate to netrc and cleanup" do
|
|
50
|
+
# preconditions
|
|
51
|
+
File.exist?(@cli.legacy_credentials_path).should == true
|
|
52
|
+
File.exist?(@cli.netrc_path).should == false
|
|
53
|
+
|
|
54
|
+
# transition
|
|
55
|
+
@cli.get_credentials.should == ['legacy_user', 'legacy_pass']
|
|
56
|
+
|
|
57
|
+
# postconditions
|
|
58
|
+
File.exist?(@cli.legacy_credentials_path).should == false
|
|
59
|
+
File.exist?(@cli.netrc_path).should == true
|
|
60
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should == ['legacy_user', 'legacy_pass']
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "API key is set via environment variable" do
|
|
65
|
+
before do
|
|
66
|
+
ENV['AZUKI_API_KEY'] = "secret"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "gets credentials from environment variables in preference to credentials file" do
|
|
70
|
+
@cli.read_credentials.should == ['', ENV['AZUKI_API_KEY']]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "returns a blank username" do
|
|
74
|
+
@cli.user.should be_empty
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "returns the api key as the password" do
|
|
78
|
+
@cli.password.should == ENV['AZUKI_API_KEY']
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "does not overwrite credentials file with environment variable credentials" do
|
|
82
|
+
@cli.should_not_receive(:write_credentials)
|
|
83
|
+
@cli.read_credentials
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "reauthenticating" do
|
|
87
|
+
before do
|
|
88
|
+
@cli.stub!(:ask_for_credentials).and_return(['new_user', 'new_password'])
|
|
89
|
+
@cli.stub!(:check)
|
|
90
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
|
91
|
+
@cli.reauthorize
|
|
92
|
+
end
|
|
93
|
+
it "updates saved credentials" do
|
|
94
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should == ['new_user', 'new_password']
|
|
95
|
+
end
|
|
96
|
+
it "returns environment variable credentials" do
|
|
97
|
+
@cli.read_credentials.should == ['', ENV['AZUKI_API_KEY']]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context "logout" do
|
|
102
|
+
before do
|
|
103
|
+
@cli.logout
|
|
104
|
+
end
|
|
105
|
+
it "should delete saved credentials" do
|
|
106
|
+
File.exists?(@cli.legacy_credentials_path).should be_false
|
|
107
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should be_nil
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "#base_host" do
|
|
113
|
+
it "returns the host without the first part" do
|
|
114
|
+
@cli.base_host("http://foo.bar.com").should == "bar.com"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "works with localhost" do
|
|
118
|
+
@cli.base_host("http://localhost:3000").should == "localhost"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "asks for credentials when the file doesn't exist" do
|
|
123
|
+
@cli.delete_credentials
|
|
124
|
+
@cli.should_receive(:ask_for_credentials).and_return(["u", "p"])
|
|
125
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
|
126
|
+
@cli.user.should == 'u'
|
|
127
|
+
@cli.password.should == 'p'
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "writes credentials and uploads authkey when credentials are saved" do
|
|
131
|
+
@cli.stub!(:credentials)
|
|
132
|
+
@cli.stub!(:check)
|
|
133
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
|
134
|
+
@cli.should_receive(:write_credentials)
|
|
135
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
|
136
|
+
@cli.ask_for_and_save_credentials
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "save_credentials deletes the credentials when the upload authkey is unauthorized" do
|
|
140
|
+
@cli.stub!(:write_credentials)
|
|
141
|
+
@cli.stub!(:retry_login?).and_return(false)
|
|
142
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
|
143
|
+
@cli.stub!(:check) { raise Azuki::API::Errors::Unauthorized.new("Login Failed", Excon::Response.new) }
|
|
144
|
+
@cli.should_receive(:delete_credentials)
|
|
145
|
+
lambda { @cli.ask_for_and_save_credentials }.should raise_error(SystemExit)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "asks for login again when not authorized, for three times" do
|
|
149
|
+
@cli.stub!(:read_credentials)
|
|
150
|
+
@cli.stub!(:write_credentials)
|
|
151
|
+
@cli.stub!(:delete_credentials)
|
|
152
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
|
153
|
+
@cli.stub!(:check) { raise Azuki::API::Errors::Unauthorized.new("Login Failed", Excon::Response.new) }
|
|
154
|
+
@cli.should_receive(:ask_for_credentials).exactly(3).times
|
|
155
|
+
lambda { @cli.ask_for_and_save_credentials }.should raise_error(SystemExit)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "deletes the credentials file" do
|
|
159
|
+
FileUtils.mkdir_p(File.dirname(@cli.legacy_credentials_path))
|
|
160
|
+
File.open(@cli.legacy_credentials_path, "w") do |file|
|
|
161
|
+
file.puts "legacy_user\nlegacy_pass"
|
|
162
|
+
end
|
|
163
|
+
FileUtils.should_receive(:rm_f).with(@cli.legacy_credentials_path)
|
|
164
|
+
@cli.delete_credentials
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "writes the login information to the credentials file for the 'azuki login' command" do
|
|
168
|
+
@cli.stub!(:ask_for_credentials).and_return(['one', 'two'])
|
|
169
|
+
@cli.stub!(:check)
|
|
170
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
|
171
|
+
@cli.reauthorize
|
|
172
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should == (['one', 'two'])
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "migrates long api keys to short api keys" do
|
|
176
|
+
@cli.delete_credentials
|
|
177
|
+
api_key = "7e262de8cac430d8a250793ce8d5b334ae56b4ff15767385121145198a2b4d2e195905ef8bf7cfc5"
|
|
178
|
+
@cli.netrc["api.#{@cli.host}"] = ["user", api_key]
|
|
179
|
+
|
|
180
|
+
@cli.get_credentials.should == ["user", api_key[0,40]]
|
|
181
|
+
%w{api code}.each do |section|
|
|
182
|
+
Netrc.read(@cli.netrc_path)["#{section}.#{@cli.host}"].should == ["user", api_key[0,40]]
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe "automatic key uploading" do
|
|
187
|
+
before(:each) do
|
|
188
|
+
FileUtils.mkdir_p("#{@cli.home_directory}/.ssh")
|
|
189
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe "an account with existing keys" do
|
|
193
|
+
before :each do
|
|
194
|
+
@api = mock(Object)
|
|
195
|
+
@response = mock(Object)
|
|
196
|
+
@response.should_receive(:body).and_return(['existingkeys'])
|
|
197
|
+
@api.should_receive(:get_keys).and_return(@response)
|
|
198
|
+
@cli.should_receive(:api).and_return(@api)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "should not do anything if the account already has keys" do
|
|
202
|
+
@cli.should_not_receive(:associate_key)
|
|
203
|
+
@cli.check_for_associated_ssh_key
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe "an account with no keys" do
|
|
208
|
+
before :each do
|
|
209
|
+
@api = mock(Object)
|
|
210
|
+
@response = mock(Object)
|
|
211
|
+
@response.should_receive(:body).and_return([])
|
|
212
|
+
@api.should_receive(:get_keys).and_return(@response)
|
|
213
|
+
@cli.should_receive(:api).and_return(@api)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
describe "with zero public keys" do
|
|
217
|
+
it "should ask to generate a key" do
|
|
218
|
+
@cli.should_receive(:ask).and_return("y")
|
|
219
|
+
@cli.should_receive(:generate_ssh_key).with("id_rsa")
|
|
220
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
|
221
|
+
@cli.check_for_associated_ssh_key
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe "with one public key" do
|
|
226
|
+
before(:each) { FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa.pub") }
|
|
227
|
+
after(:each) { FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa.pub") }
|
|
228
|
+
|
|
229
|
+
it "should upload the key" do
|
|
230
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
|
231
|
+
@cli.check_for_associated_ssh_key
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe "with many public keys" do
|
|
236
|
+
before(:each) do
|
|
237
|
+
FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
|
238
|
+
FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
after(:each) do
|
|
242
|
+
FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
|
243
|
+
FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "should ask which key to upload" do
|
|
247
|
+
File.open("#{@cli.home_directory}/.ssh/id_rsa.pub", "w") { |f| f.puts }
|
|
248
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
|
249
|
+
@cli.should_receive(:ask).and_return("2")
|
|
250
|
+
@cli.check_for_associated_ssh_key
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/client/azuki_postgresql"
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
describe Azuki::Client::AzukiPostgresql do
|
|
6
|
+
include Azuki::Helpers
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
Azuki::Auth.stub :user => 'user@example.com', :password => 'apitoken'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:attachment) { double('attachment', :resource_name => 'something-something-42', :starter_plan? => false) }
|
|
13
|
+
let(:client) { Azuki::Client::AzukiPostgresql.new(attachment) }
|
|
14
|
+
|
|
15
|
+
describe 'api choosing' do
|
|
16
|
+
it "sends an ingress request to the client for production plans" do
|
|
17
|
+
attachment.stub! :starter_plan? => false
|
|
18
|
+
host = 'postgres-api.azukiapp.com'
|
|
19
|
+
url = "https://user@example.com:apitoken@#{host}/client/v11/databases/#{attachment.resource_name}/ingress"
|
|
20
|
+
|
|
21
|
+
stub_request(:put, url).to_return(
|
|
22
|
+
:body => json_encode({"message" => "ok"}),
|
|
23
|
+
:status => 200
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
client.ingress
|
|
27
|
+
|
|
28
|
+
a_request(:put, url).should have_been_made.once
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "sends an ingress request to the client for production plans" do
|
|
32
|
+
attachment.stub! :starter_plan? => true
|
|
33
|
+
host = 'postgres-starter-api.azukiapp.com'
|
|
34
|
+
url = "https://user@example.com:apitoken@#{host}/client/v11/databases/#{attachment.resource_name}/ingress"
|
|
35
|
+
|
|
36
|
+
stub_request(:put, url).to_return(
|
|
37
|
+
:body => json_encode({"message" => "ok"}),
|
|
38
|
+
:status => 200
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
client.ingress
|
|
42
|
+
|
|
43
|
+
a_request(:put, url).should have_been_made.once
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#get_database' do
|
|
48
|
+
let(:url) { "https://user@example.com:apitoken@postgres-api.azukiapp.com/client/v11/databases/#{attachment.resource_name}" }
|
|
49
|
+
|
|
50
|
+
it 'works without the extended option' do
|
|
51
|
+
stub_request(:get, url).to_return :body => '{}'
|
|
52
|
+
client.get_database
|
|
53
|
+
a_request(:get, url).should have_been_made.once
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'works with the extended option' do
|
|
57
|
+
url2 = url + '?extended=true'
|
|
58
|
+
stub_request(:get, url2).to_return :body => '{}'
|
|
59
|
+
client.get_database(true)
|
|
60
|
+
a_request(:get, url2).should have_been_made.once
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "retries on error, then raises" do
|
|
64
|
+
stub_request(:get, url).to_return(:body => "error", :status => 500)
|
|
65
|
+
client.stub(:sleep)
|
|
66
|
+
lambda { client.get_database }.should raise_error RestClient::InternalServerError
|
|
67
|
+
a_request(:get, url).should have_been_made.times(4)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/client/pgbackups"
|
|
3
|
+
require "azuki/helpers"
|
|
4
|
+
|
|
5
|
+
describe Azuki::Client::Pgbackups do
|
|
6
|
+
|
|
7
|
+
include Azuki::Helpers
|
|
8
|
+
|
|
9
|
+
let(:path) { "http://id:password@pgbackups.azukiapp.com" }
|
|
10
|
+
let(:client) { Azuki::Client::Pgbackups.new path+'/api' }
|
|
11
|
+
let(:transfer_path) { path + '/client/transfers' }
|
|
12
|
+
|
|
13
|
+
describe "api" do
|
|
14
|
+
let(:version) { Azuki::Client.version }
|
|
15
|
+
|
|
16
|
+
it 'still has a azuki gem version' do
|
|
17
|
+
version.should be
|
|
18
|
+
version.split(/\./).first.to_i.should >= 2
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'includes the azuki gem version' do
|
|
22
|
+
stub_request(:get, transfer_path)
|
|
23
|
+
client.get_transfers
|
|
24
|
+
a_request(:get, transfer_path).with(
|
|
25
|
+
:headers => {'X-Azuki-Gem-Version' => version}
|
|
26
|
+
).should have_been_made.once
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "create transfers" do
|
|
31
|
+
it "sends a request to the client" do
|
|
32
|
+
stub_request(:post, transfer_path).to_return(
|
|
33
|
+
:body => json_encode({"message" => "success"}),
|
|
34
|
+
:status => 200
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
client.create_transfer("postgres://from", "postgres://to", "FROMNAME", "TO_NAME")
|
|
38
|
+
|
|
39
|
+
a_request(:post, transfer_path).should have_been_made.once
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require "spec_helper"
|
|
3
|
+
require "azuki/client/rendezvous"
|
|
4
|
+
require "support/openssl_mock_helper"
|
|
5
|
+
|
|
6
|
+
describe Azuki::Client, "rendezvous" do
|
|
7
|
+
before do
|
|
8
|
+
@rendezvous = Azuki::Client::Rendezvous.new({
|
|
9
|
+
:rendezvous_url => "https://azuki.local:1234/secret",
|
|
10
|
+
:output => $stdout
|
|
11
|
+
})
|
|
12
|
+
end
|
|
13
|
+
context "fixup" do
|
|
14
|
+
it "null" do
|
|
15
|
+
@rendezvous.send(:fixup, nil).should be_nil
|
|
16
|
+
end
|
|
17
|
+
it "an empty string" do
|
|
18
|
+
@rendezvous.send(:fixup, "").should eq ""
|
|
19
|
+
end
|
|
20
|
+
it "hash" do
|
|
21
|
+
@rendezvous.send(:fixup, { :x => :y }).should eq({ :x => :y })
|
|
22
|
+
end
|
|
23
|
+
it "default English UTF-8 data" do
|
|
24
|
+
@rendezvous.send(:fixup, "azuki").should eq "azuki"
|
|
25
|
+
end
|
|
26
|
+
it "default Japanese UTF-8 encoded data" do
|
|
27
|
+
@rendezvous.send(:fixup, "愛しています").should eq "愛しています"
|
|
28
|
+
end
|
|
29
|
+
if RUBY_VERSION >= "1.9"
|
|
30
|
+
it "ISO-8859-1 force-encoded data" do
|
|
31
|
+
@rendezvous.send(:fixup, "Хероку".force_encoding("ISO-8859-1")).should eq "Хероку".force_encoding("UTF-8")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
context "with mock ssl" do
|
|
36
|
+
before :each do
|
|
37
|
+
mock_openssl
|
|
38
|
+
@ssl_socket_mock.should_receive(:puts).with("secret")
|
|
39
|
+
@ssl_socket_mock.should_receive(:readline).and_return(nil)
|
|
40
|
+
end
|
|
41
|
+
it "should connect to host:post" do
|
|
42
|
+
TCPSocket.should_receive(:open).with("azuki.local", 1234).and_return(@tcp_socket_mock)
|
|
43
|
+
IO.stub(:select).and_return(nil)
|
|
44
|
+
@ssl_socket_mock.stub(:write)
|
|
45
|
+
@ssl_socket_mock.stub(:flush) { raise Timeout::Error }
|
|
46
|
+
lambda { @rendezvous.start }.should raise_error(Timeout::Error)
|
|
47
|
+
end
|
|
48
|
+
it "should callback on_connect" do
|
|
49
|
+
@rendezvous.on_connect do
|
|
50
|
+
raise "on_connect"
|
|
51
|
+
end
|
|
52
|
+
TCPSocket.should_receive(:open).and_return(@tcp_socket_mock)
|
|
53
|
+
lambda { @rendezvous.start }.should raise_error("on_connect")
|
|
54
|
+
end
|
|
55
|
+
it "should fixup received data" do
|
|
56
|
+
TCPSocket.should_receive(:open).and_return(@tcp_socket_mock)
|
|
57
|
+
@ssl_socket_mock.should_receive(:readpartial).and_return("The quick brown fox jumps over the lazy dog")
|
|
58
|
+
@rendezvous.stub(:fixup) { |data| raise "received: #{data}" }
|
|
59
|
+
lambda { @rendezvous.start }.should raise_error("received: The quick brown fox jumps over the lazy dog")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "azuki/client/ssl_endpoint"
|
|
3
|
+
|
|
4
|
+
describe Azuki::Client, "ssl endpoints" do
|
|
5
|
+
before do
|
|
6
|
+
@client = Azuki::Client.new(nil, nil)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "adds an ssl endpoint" do
|
|
10
|
+
stub_request(:post, "https://api.azukiapp.com/apps/example/ssl-endpoints").
|
|
11
|
+
with(:body => { :accept => "json", :pem => "pem content", :key => "key content" }).
|
|
12
|
+
to_return(:body => %{ {"cname": "tokyo-1050" } })
|
|
13
|
+
@client.ssl_endpoint_add("example", "pem content", "key content").should == { "cname" => "tokyo-1050" }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "gets info on an ssl endpoint" do
|
|
17
|
+
stub_request(:get, "https://api.azukiapp.com/apps/example/ssl-endpoints/tokyo-1050").
|
|
18
|
+
to_return(:body => %{ {"cname": "tokyo-1050" } })
|
|
19
|
+
@client.ssl_endpoint_info("example", "tokyo-1050").should == { "cname" => "tokyo-1050" }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "lists ssl endpoints for an app" do
|
|
23
|
+
stub_request(:get, "https://api.azukiapp.com/apps/example/ssl-endpoints").
|
|
24
|
+
to_return(:body => %{ [{"cname": "tokyo-1050" }, {"cname": "tokyo-1051" }] })
|
|
25
|
+
@client.ssl_endpoint_list("example").should == [
|
|
26
|
+
{ "cname" => "tokyo-1050" },
|
|
27
|
+
{ "cname" => "tokyo-1051" },
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "removes an ssl endpoint" do
|
|
32
|
+
stub_request(:delete, "https://api.azukiapp.com/apps/example/ssl-endpoints/tokyo-1050")
|
|
33
|
+
@client.ssl_endpoint_remove("example", "tokyo-1050")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "rolls back an ssl endpoint" do
|
|
37
|
+
stub_request(:post, "https://api.azukiapp.com/apps/example/ssl-endpoints/tokyo-1050/rollback").
|
|
38
|
+
to_return(:body => %{ {"cname": "tokyo-1050" } })
|
|
39
|
+
@client.ssl_endpoint_rollback("example", "tokyo-1050").should == { "cname" => "tokyo-1050" }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "updates an ssl endpoint" do
|
|
43
|
+
stub_request(:put, "https://api.azukiapp.com/apps/example/ssl-endpoints/tokyo-1050").
|
|
44
|
+
with(:body => { :accept => "json", :pem => "pem content", :key => "key content" }).
|
|
45
|
+
to_return(:body => %{ {"cname": "tokyo-1050" } })
|
|
46
|
+
@client.ssl_endpoint_update("example", "tokyo-1050", "pem content", "key content").should == { "cname" => "tokyo-1050" }
|
|
47
|
+
end
|
|
48
|
+
end
|