turbot 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +36 -0
- data/bin/turbot +17 -0
- data/data/cacert.pem +3988 -0
- data/lib/turbot/auth.rb +315 -0
- data/lib/turbot/cli.rb +38 -0
- data/lib/turbot/client/cisaurus.rb +25 -0
- data/lib/turbot/client/pgbackups.rb +113 -0
- data/lib/turbot/client/rendezvous.rb +111 -0
- data/lib/turbot/client/ssl_endpoint.rb +25 -0
- data/lib/turbot/client/turbot_postgresql.rb +148 -0
- data/lib/turbot/client.rb +757 -0
- data/lib/turbot/command/auth.rb +85 -0
- data/lib/turbot/command/base.rb +192 -0
- data/lib/turbot/command/bots.rb +326 -0
- data/lib/turbot/command/config.rb +123 -0
- data/lib/turbot/command/help.rb +179 -0
- data/lib/turbot/command/keys.rb +115 -0
- data/lib/turbot/command/logs.rb +34 -0
- data/lib/turbot/command/ssl.rb +43 -0
- data/lib/turbot/command/status.rb +51 -0
- data/lib/turbot/command/update.rb +47 -0
- data/lib/turbot/command/version.rb +23 -0
- data/lib/turbot/command.rb +304 -0
- data/lib/turbot/deprecated/help.rb +38 -0
- data/lib/turbot/deprecated.rb +5 -0
- data/lib/turbot/distribution.rb +9 -0
- data/lib/turbot/errors.rb +28 -0
- data/lib/turbot/excon.rb +11 -0
- data/lib/turbot/helpers/log_displayer.rb +70 -0
- data/lib/turbot/helpers/pg_dump_restore.rb +115 -0
- data/lib/turbot/helpers/turbot_postgresql.rb +213 -0
- data/lib/turbot/helpers.rb +521 -0
- data/lib/turbot/plugin.rb +165 -0
- data/lib/turbot/updater.rb +171 -0
- data/lib/turbot/version.rb +3 -0
- data/lib/turbot.rb +19 -0
- data/lib/vendor/turbot/okjson.rb +598 -0
- data/spec/helper/legacy_help.rb +16 -0
- data/spec/helper/pg_dump_restore_spec.rb +67 -0
- data/spec/schemas/dummy_schema.json +12 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +220 -0
- data/spec/support/display_message_matcher.rb +49 -0
- data/spec/support/dummy_api.rb +120 -0
- data/spec/support/openssl_mock_helper.rb +8 -0
- data/spec/support/organizations_mock_helper.rb +11 -0
- data/spec/turbot/auth_spec.rb +214 -0
- data/spec/turbot/client/pgbackups_spec.rb +43 -0
- data/spec/turbot/client/rendezvous_spec.rb +62 -0
- data/spec/turbot/client/ssl_endpoint_spec.rb +48 -0
- data/spec/turbot/client/turbot_postgresql_spec.rb +71 -0
- data/spec/turbot/client_spec.rb +548 -0
- data/spec/turbot/command/auth_spec.rb +38 -0
- data/spec/turbot/command/base_spec.rb +66 -0
- data/spec/turbot/command/bots_spec.rb +54 -0
- data/spec/turbot/command/config_spec.rb +143 -0
- data/spec/turbot/command/help_spec.rb +90 -0
- data/spec/turbot/command/keys_spec.rb +117 -0
- data/spec/turbot/command/logs_spec.rb +60 -0
- data/spec/turbot/command/status_spec.rb +48 -0
- data/spec/turbot/command/version_spec.rb +16 -0
- data/spec/turbot/command_spec.rb +131 -0
- data/spec/turbot/helpers/turbot_postgresql_spec.rb +181 -0
- data/spec/turbot/helpers_spec.rb +48 -0
- data/spec/turbot/plugin_spec.rb +172 -0
- data/spec/turbot/updater_spec.rb +44 -0
- data/templates/manifest.json +7 -0
- data/templates/scraper.py +5 -0
- data/templates/scraper.rb +6 -0
- metadata +199 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,220 @@
|
|
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 "turbot-api"
|
11
|
+
require "rest_client"
|
12
|
+
|
13
|
+
require "turbot/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
|
+
Turbot::API.new(:api_key => "pass", :mock => true)
|
26
|
+
end
|
27
|
+
|
28
|
+
def org_api
|
29
|
+
Turbot::Client::Organizations.api(:mock => true)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stub_api_request(method, path)
|
33
|
+
stub_request(method, "https://api.turbot.com#{path}")
|
34
|
+
end
|
35
|
+
|
36
|
+
def prepare_command(klass)
|
37
|
+
command = klass.new
|
38
|
+
command.stub!(:bot).and_return("example")
|
39
|
+
command.stub!(:ask).and_return("")
|
40
|
+
command.stub!(:display)
|
41
|
+
command.stub!(:hputs)
|
42
|
+
command.stub!(:hprint)
|
43
|
+
command.stub!(:turbot).and_return(mock('turbot client', :host => 'turbot.com'))
|
44
|
+
command
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute(command_line)
|
48
|
+
extend RR::Adapters::RRMethods
|
49
|
+
|
50
|
+
args = command_line.split(" ")
|
51
|
+
command = args.shift
|
52
|
+
|
53
|
+
Turbot::Command.load
|
54
|
+
object, method = Turbot::Command.prepare_run(command, args)
|
55
|
+
|
56
|
+
any_instance_of(Turbot::Command::Base) do |base|
|
57
|
+
stub(base).bot.returns("example")
|
58
|
+
end
|
59
|
+
|
60
|
+
stub(Turbot::Auth).get_credentials.returns(['email@example.com', 'apikey01'])
|
61
|
+
stub(Turbot::Auth).api_key.returns('apikey01')
|
62
|
+
|
63
|
+
original_stdin, original_stderr, original_stdout = $stdin, $stderr, $stdout
|
64
|
+
|
65
|
+
$stdin = captured_stdin = StringIO.new
|
66
|
+
$stderr = captured_stderr = StringIO.new
|
67
|
+
$stdout = captured_stdout = StringIO.new
|
68
|
+
class << captured_stdout
|
69
|
+
def tty?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
object.send(method)
|
76
|
+
rescue SystemExit
|
77
|
+
ensure
|
78
|
+
$stdin, $stderr, $stdout = original_stdin, original_stderr, original_stdout
|
79
|
+
Turbot::Command.current_command = nil
|
80
|
+
end
|
81
|
+
|
82
|
+
[captured_stderr.string, captured_stdout.string]
|
83
|
+
end
|
84
|
+
|
85
|
+
def any_instance_of(klass, &block)
|
86
|
+
extend RR::Adapters::RRMethods
|
87
|
+
any_instance_of(klass, &block)
|
88
|
+
end
|
89
|
+
|
90
|
+
def run(command_line)
|
91
|
+
capture_stdout do
|
92
|
+
begin
|
93
|
+
Turbot::CLI.start(*command_line.split(" "))
|
94
|
+
rescue SystemExit
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
alias turbot run
|
100
|
+
|
101
|
+
def capture_stderr(&block)
|
102
|
+
original_stderr = $stderr
|
103
|
+
$stderr = captured_stderr = StringIO.new
|
104
|
+
begin
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
$stderr = original_stderr
|
108
|
+
end
|
109
|
+
captured_stderr.string
|
110
|
+
end
|
111
|
+
|
112
|
+
def capture_stdout(&block)
|
113
|
+
original_stdout = $stdout
|
114
|
+
$stdout = captured_stdout = StringIO.new
|
115
|
+
begin
|
116
|
+
yield
|
117
|
+
ensure
|
118
|
+
$stdout = original_stdout
|
119
|
+
end
|
120
|
+
captured_stdout.string
|
121
|
+
end
|
122
|
+
|
123
|
+
def fail_command(message)
|
124
|
+
raise_error(Turbot::Command::CommandFailed, message)
|
125
|
+
end
|
126
|
+
|
127
|
+
def stub_core
|
128
|
+
@stubbed_core ||= begin
|
129
|
+
stubbed_core = nil
|
130
|
+
any_instance_of(Turbot::Client) do |core|
|
131
|
+
stubbed_core = stub(core)
|
132
|
+
end
|
133
|
+
stub(Turbot::Auth).user.returns("email@example.com")
|
134
|
+
stub(Turbot::Auth).password.returns("pass")
|
135
|
+
stub(Turbot::Client).auth.returns("apikey01")
|
136
|
+
stubbed_core
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def stub_pg
|
141
|
+
@stubbed_pg ||= begin
|
142
|
+
stubbed_pg = nil
|
143
|
+
any_instance_of(Turbot::Client::TurbotPostgresql) do |pg|
|
144
|
+
stubbed_pg = stub(pg)
|
145
|
+
end
|
146
|
+
stubbed_pg
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def stub_pgbackups
|
151
|
+
@stubbed_pgbackups ||= begin
|
152
|
+
stubbed_pgbackups = nil
|
153
|
+
any_instance_of(Turbot::Client::Pgbackups) do |pgbackups|
|
154
|
+
stubbed_pgbackups = stub(pgbackups)
|
155
|
+
end
|
156
|
+
stubbed_pgbackups
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def stub_rendezvous
|
161
|
+
@stubbed_rendezvous ||= begin
|
162
|
+
stubbed_rendezvous = nil
|
163
|
+
any_instance_of(Turbot::Client::Rendezvous) do |rendezvous|
|
164
|
+
stubbed_rendezvous = stub(rendezvous)
|
165
|
+
end
|
166
|
+
stubbed_rendezvous
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def stub_cisaurus
|
171
|
+
@stub_cisaurus ||= begin
|
172
|
+
stub_cisaurus = nil
|
173
|
+
any_instance_of(Turbot::Client::Cisaurus) do |cisaurus|
|
174
|
+
stub_cisaurus = stub(cisaurus)
|
175
|
+
end
|
176
|
+
stub_cisaurus
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def with_blank_git_repository(&block)
|
181
|
+
sandbox = File.join(Dir.tmpdir, "turbot", Process.pid.to_s)
|
182
|
+
FileUtils.mkdir_p(sandbox)
|
183
|
+
|
184
|
+
old_dir = Dir.pwd
|
185
|
+
Dir.chdir(sandbox)
|
186
|
+
|
187
|
+
`git init`
|
188
|
+
block.call
|
189
|
+
|
190
|
+
FileUtils.rm_rf(sandbox)
|
191
|
+
ensure
|
192
|
+
Dir.chdir(old_dir)
|
193
|
+
end
|
194
|
+
|
195
|
+
module SandboxHelper
|
196
|
+
def bash(cmd)
|
197
|
+
`#{cmd}`
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
require "turbot/helpers"
|
202
|
+
module Turbot::Helpers
|
203
|
+
@home_directory = Dir.mktmpdir
|
204
|
+
undef_method :home_directory
|
205
|
+
def home_directory
|
206
|
+
@home_directory
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
require "support/display_message_matcher"
|
211
|
+
require "support/organizations_mock_helper"
|
212
|
+
require "support/dummy_api"
|
213
|
+
|
214
|
+
RSpec.configure do |config|
|
215
|
+
config.color_enabled = true
|
216
|
+
config.include DisplayMessageMatcher
|
217
|
+
config.order = 'rand'
|
218
|
+
config.before { Turbot::Helpers.error_with_failure = false }
|
219
|
+
config.after { RR.reset }
|
220
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module DisplayMessageMatcher
|
2
|
+
|
3
|
+
def display_message(command, message)
|
4
|
+
DisplayMessageMatcher::DisplayMessage.new command, message
|
5
|
+
end
|
6
|
+
|
7
|
+
class DisplayMessage
|
8
|
+
def initialize(command, message)
|
9
|
+
@command = command
|
10
|
+
@message = message
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(given_proc)
|
14
|
+
displayed_expected_message = false
|
15
|
+
@given_messages = []
|
16
|
+
|
17
|
+
@command.should_receive(:display).
|
18
|
+
any_number_of_times do |message, newline|
|
19
|
+
@given_messages << message
|
20
|
+
displayed_expected_message = displayed_expected_message ||
|
21
|
+
message == @message
|
22
|
+
end
|
23
|
+
|
24
|
+
given_proc.call
|
25
|
+
|
26
|
+
displayed_expected_message
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message
|
30
|
+
"expected #{ @command } to display the message #{ @message.inspect } but #{ given_messages }"
|
31
|
+
end
|
32
|
+
|
33
|
+
def negative_failure_message
|
34
|
+
"expected #{ @command } to not display the message #{ @message.inspect } but it was displayed"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def given_messages
|
40
|
+
if @given_messages.empty?
|
41
|
+
'no messages were displayed'
|
42
|
+
else
|
43
|
+
formatted_given_messages = @given_messages.map(&:inspect).join ', '
|
44
|
+
"the follow messages were displayed: #{ formatted_given_messages }"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Turbot
|
4
|
+
class API
|
5
|
+
def initialize(params)
|
6
|
+
@headers = params[:headers]
|
7
|
+
@host = params[:host]
|
8
|
+
@port = params[:port]
|
9
|
+
@username = params[:username]
|
10
|
+
@password = params[:password]
|
11
|
+
@scheme = params[:scheme]
|
12
|
+
@ssl_verify_peer = params[:ssl_verify_peer]
|
13
|
+
@api_key = params[:api_key] || get_api_key(@username, @password)
|
14
|
+
authenticate
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate
|
19
|
+
# Try to authenticate at this stage - something like
|
20
|
+
#user_pass = ":#{@api_key}"
|
21
|
+
#options[:headers] = HEADERS.merge({
|
22
|
+
# 'Authorization' => "Basic #{Base64.encode64(user_pass).gsub("\n", '')}",
|
23
|
+
# }).merge(options[:headers])
|
24
|
+
|
25
|
+
# @connection = Excon.new("http://missions.opencorporates.com/login", options)
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_user
|
30
|
+
# raise if not authenticated
|
31
|
+
# @connection.code < 400
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_api_key(user, password)
|
35
|
+
# get the api key, raise exception if credentials broken
|
36
|
+
# this is a hash of the username and password plus salt
|
37
|
+
return "some-api-key"
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_keys
|
41
|
+
# return an array of ssh keys
|
42
|
+
read_db("keys")
|
43
|
+
end
|
44
|
+
|
45
|
+
def post_key(key)
|
46
|
+
# receive ssh key and associate with account
|
47
|
+
append_db("keys", {"contents" => key})
|
48
|
+
end
|
49
|
+
|
50
|
+
def delete_key(key)
|
51
|
+
keys = read_db("keys")
|
52
|
+
keys.delete(key)
|
53
|
+
write_db("keys", keys)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_keys
|
57
|
+
write_db("keys", [])
|
58
|
+
end
|
59
|
+
|
60
|
+
def post_bot(data)
|
61
|
+
# XXX need to implement this to make the config command pass...
|
62
|
+
# save an "bot" - we'll replace this with the bot stuff chris did
|
63
|
+
db = read_db("bot")
|
64
|
+
db[data["name"]] = data
|
65
|
+
write_db("bot", db)
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete_bot(bot)
|
69
|
+
db = read_db("bot")
|
70
|
+
db.delete(bot)
|
71
|
+
write_db("bot", db)
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_bots
|
75
|
+
read_db("bot", [])
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_bot(bot)
|
79
|
+
db = read_db("bot_data", [])
|
80
|
+
db[bot]
|
81
|
+
end
|
82
|
+
|
83
|
+
def put_config_vars(bot, vars)
|
84
|
+
# Set vars for bot specified
|
85
|
+
config = read_db("config")
|
86
|
+
config[bot] = vars
|
87
|
+
write_db("config", config)
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_config_vars(bot)
|
91
|
+
read_db("config", [])[bot]
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete_config_var(bot, key)
|
95
|
+
db = read_db("config", [])
|
96
|
+
keys = db[bot]
|
97
|
+
keys.delete(key)
|
98
|
+
db[bot] = keys
|
99
|
+
write_db("config", db)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def write_db(name, data)
|
105
|
+
open("/tmp/#{name}", "w") do |f|
|
106
|
+
f.write(JSON.dump(data))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_db(name, default={})
|
111
|
+
JSON.parse(open("/tmp/#{name}", "r").read) rescue {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def append_db(name, data)
|
115
|
+
db = read_db(name, [])
|
116
|
+
db << data
|
117
|
+
write_db(name, db)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
def mock_openssl
|
2
|
+
@ctx_mock = mock "SSLContext", :key= => nil, :cert= => nil, :ssl_version= => nil
|
3
|
+
@tcp_socket_mock = mock "TCPSocket", :close => true
|
4
|
+
@ssl_socket_mock = mock "SSLSocket", :sync= => true, :connect => true, :close => true, :to_io => $stdin
|
5
|
+
|
6
|
+
OpenSSL::SSL::SSLSocket.stub(:new).and_return(@ssl_socket_mock)
|
7
|
+
OpenSSL::SSL::SSLContext.stub(:new).and_return(@ctx_mock)
|
8
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/auth"
|
3
|
+
require "turbot/helpers"
|
4
|
+
|
5
|
+
module Turbot
|
6
|
+
describe Auth do
|
7
|
+
include Turbot::Helpers
|
8
|
+
|
9
|
+
before do
|
10
|
+
ENV['TURBOT_API_KEY'] = nil
|
11
|
+
|
12
|
+
@cli = Turbot::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.turbot.com\n login user\n password pass\n")
|
30
|
+
file.puts("machine code.turbot.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
|
+
|
40
|
+
context "API key is set via environment variable" do
|
41
|
+
before do
|
42
|
+
ENV['TURBOT_API_KEY'] = "secret"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "gets credentials from environment variables in preference to credentials file" do
|
46
|
+
@cli.read_credentials.should == ['', ENV['TURBOT_API_KEY']]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns a blank username" do
|
50
|
+
@cli.user.should be_empty
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns the api key as the password" do
|
54
|
+
@cli.password.should == ENV['TURBOT_API_KEY']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not overwrite credentials file with environment variable credentials" do
|
58
|
+
@cli.should_not_receive(:write_credentials)
|
59
|
+
@cli.read_credentials
|
60
|
+
end
|
61
|
+
|
62
|
+
context "reauthenticating" do
|
63
|
+
before do
|
64
|
+
@cli.stub!(:ask_for_credentials).and_return(['new_user', 'new_password'])
|
65
|
+
@cli.stub!(:check)
|
66
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
67
|
+
@cli.reauthorize
|
68
|
+
end
|
69
|
+
it "updates saved credentials" do
|
70
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should == ['new_user', 'new_password']
|
71
|
+
end
|
72
|
+
it "returns environment variable credentials" do
|
73
|
+
@cli.read_credentials.should == ['', ENV['TURBOT_API_KEY']]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#base_host" do
|
80
|
+
it "returns the host without the first part" do
|
81
|
+
@cli.base_host("http://foo.bar.com").should == "bar.com"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "works with localhost" do
|
85
|
+
@cli.base_host("http://localhost:3000").should == "localhost"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "asks for credentials when the file doesn't exist" do
|
90
|
+
@cli.delete_credentials
|
91
|
+
@cli.should_receive(:ask_for_credentials).and_return(["u", "p"])
|
92
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
93
|
+
@cli.user.should == 'u'
|
94
|
+
@cli.password.should == 'p'
|
95
|
+
end
|
96
|
+
|
97
|
+
it "writes credentials and uploads authkey when credentials are saved" do
|
98
|
+
@cli.stub!(:credentials)
|
99
|
+
@cli.stub!(:check)
|
100
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
101
|
+
@cli.should_receive(:write_credentials)
|
102
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
103
|
+
@cli.ask_for_and_save_credentials
|
104
|
+
end
|
105
|
+
|
106
|
+
it "save_credentials deletes the credentials when the upload authkey is unauthorized" do
|
107
|
+
@cli.stub!(:write_credentials)
|
108
|
+
@cli.stub!(:retry_login?).and_return(false)
|
109
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
110
|
+
@cli.stub!(:check) { raise Turbot::API::Errors::Unauthorized.new("Login Failed", Excon::Response.new) }
|
111
|
+
@cli.should_receive(:delete_credentials)
|
112
|
+
lambda { @cli.ask_for_and_save_credentials }.should raise_error(SystemExit)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "asks for login again when not authorized, for three times" do
|
116
|
+
@cli.stub!(:read_credentials)
|
117
|
+
@cli.stub!(:write_credentials)
|
118
|
+
@cli.stub!(:delete_credentials)
|
119
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
120
|
+
@cli.stub!(:check) { raise Turbot::API::Errors::Unauthorized.new("Login Failed", Excon::Response.new) }
|
121
|
+
@cli.should_receive(:ask_for_credentials).exactly(3).times
|
122
|
+
lambda { @cli.ask_for_and_save_credentials }.should raise_error(SystemExit)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "writes the login information to the credentials file for the 'turbot login' command" do
|
126
|
+
@cli.stub!(:ask_for_credentials).and_return(['one', 'two'])
|
127
|
+
@cli.stub!(:check)
|
128
|
+
@cli.should_receive(:check_for_associated_ssh_key)
|
129
|
+
@cli.reauthorize
|
130
|
+
Netrc.read(@cli.netrc_path)["api.#{@cli.host}"].should == (['one', 'two'])
|
131
|
+
end
|
132
|
+
|
133
|
+
it "migrates long api keys to short api keys" do
|
134
|
+
@cli.delete_credentials
|
135
|
+
api_key = "7e262de8cac430d8a250793ce8d5b334ae56b4ff15767385121145198a2b4d2e195905ef8bf7cfc5"
|
136
|
+
@cli.netrc["api.#{@cli.host}"] = ["user", api_key]
|
137
|
+
|
138
|
+
@cli.get_credentials.should == ["user", api_key[0,40]]
|
139
|
+
%w{api code}.each do |section|
|
140
|
+
Netrc.read(@cli.netrc_path)["#{section}.#{@cli.host}"].should == ["user", api_key[0,40]]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "automatic key uploading" do
|
145
|
+
before(:each) do
|
146
|
+
FileUtils.mkdir_p("#{@cli.home_directory}/.ssh")
|
147
|
+
@cli.stub!(:ask_for_credentials).and_return("username", "apikey")
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "an account with existing keys" do
|
151
|
+
before :each do
|
152
|
+
@api = mock(Object)
|
153
|
+
@response = mock(Object)
|
154
|
+
@response.should_receive(:body).and_return(['existingkeys'])
|
155
|
+
@api.should_receive(:get_ssh_keys).and_return(@response)
|
156
|
+
@cli.should_receive(:api).and_return(@api)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not do anything if the account already has keys" do
|
160
|
+
@cli.should_not_receive(:associate_key)
|
161
|
+
@cli.check_for_associated_ssh_key
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "an account with no keys" do
|
166
|
+
before :each do
|
167
|
+
@api = mock(Object)
|
168
|
+
@response = mock(Object)
|
169
|
+
@response.should_receive(:body).and_return([])
|
170
|
+
@api.should_receive(:get_ssh_keys).and_return(@response)
|
171
|
+
@cli.should_receive(:api).and_return(@api)
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "with zero public keys" do
|
175
|
+
it "should ask to generate a key" do
|
176
|
+
@cli.should_receive(:ask).and_return("y")
|
177
|
+
@cli.should_receive(:generate_ssh_key).with("id_rsa")
|
178
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
179
|
+
@cli.check_for_associated_ssh_key
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "with one public key" do
|
184
|
+
before(:each) { FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa.pub") }
|
185
|
+
after(:each) { FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa.pub") }
|
186
|
+
|
187
|
+
it "should upload the key" do
|
188
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
189
|
+
@cli.check_for_associated_ssh_key
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "with many public keys" do
|
194
|
+
before(:each) do
|
195
|
+
FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
196
|
+
FileUtils.touch("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
197
|
+
end
|
198
|
+
|
199
|
+
after(:each) do
|
200
|
+
FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa.pub")
|
201
|
+
FileUtils.rm("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should ask which key to upload" do
|
205
|
+
File.open("#{@cli.home_directory}/.ssh/id_rsa.pub", "w") { |f| f.puts }
|
206
|
+
@cli.should_receive(:associate_key).with("#{@cli.home_directory}/.ssh/id_rsa2.pub")
|
207
|
+
@cli.should_receive(:ask).and_return("2")
|
208
|
+
@cli.check_for_associated_ssh_key
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/client/pgbackups"
|
3
|
+
require "turbot/helpers"
|
4
|
+
|
5
|
+
describe Turbot::Client::Pgbackups do
|
6
|
+
|
7
|
+
include Turbot::Helpers
|
8
|
+
|
9
|
+
let(:path) { "http://id:password@pgbackups.turbot.com" }
|
10
|
+
let(:client) { Turbot::Client::Pgbackups.new path+'/api' }
|
11
|
+
let(:transfer_path) { path + '/client/transfers' }
|
12
|
+
|
13
|
+
describe "api" do
|
14
|
+
let(:version) { Turbot::Client.version }
|
15
|
+
|
16
|
+
it 'still has a turbot gem version' do
|
17
|
+
version.should be
|
18
|
+
version.split(/\./).first.to_i.should >= 0
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'includes the turbot gem version' do
|
22
|
+
stub_request(:get, transfer_path)
|
23
|
+
client.get_transfers
|
24
|
+
a_request(:get, transfer_path).with(
|
25
|
+
:headers => {'X-Turbot-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
|