turbot 0.0.2
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 +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
|