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
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/bots"
|
3
|
+
|
4
|
+
describe Turbot::Command::Bots do
|
5
|
+
describe "validate" do
|
6
|
+
before do
|
7
|
+
Turbot::Command::Bots.any_instance.stub(:parsed_manifest).and_return('data_type' => 'dummy')
|
8
|
+
end
|
9
|
+
|
10
|
+
context "for data_type with schema" do
|
11
|
+
before do
|
12
|
+
Turbot::Command::Bots.any_instance.
|
13
|
+
stub(:get_schema).
|
14
|
+
and_return(File.expand_path('../../../schemas/dummy_schema.json', __FILE__))
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
it "says bot is valid if its output matches the schema" do
|
19
|
+
Turbot::Command::Bots.any_instance.
|
20
|
+
stub(:run_scraper_each_line).
|
21
|
+
and_yield({name: 'One'}.to_json)
|
22
|
+
|
23
|
+
stderr, stdout = execute("bots:validate")
|
24
|
+
|
25
|
+
stderr.should == ""
|
26
|
+
stdout.should include 'Validated 1 records successfully'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "says bot is invalid if its output doesn't match the schema" do
|
30
|
+
Turbot::Command::Bots.any_instance.
|
31
|
+
stub(:run_scraper_each_line).
|
32
|
+
and_yield({name: 123}.to_json)
|
33
|
+
|
34
|
+
stderr, stdout = execute("bots:validate")
|
35
|
+
|
36
|
+
stdout.should == ""
|
37
|
+
stderr.should include 'ERRORS'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "for data_type without schema" do
|
42
|
+
it "says bot is invalid" do
|
43
|
+
Turbot::Command::Bots.any_instance.
|
44
|
+
stub(:get_schema).
|
45
|
+
and_return(nil)
|
46
|
+
|
47
|
+
stderr, stdout = execute("bots:validate")
|
48
|
+
|
49
|
+
stdout.should == ""
|
50
|
+
stderr.should include 'No schema found'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/config"
|
3
|
+
|
4
|
+
module Turbot::Command
|
5
|
+
describe Config do
|
6
|
+
before(:each) do
|
7
|
+
stub_core
|
8
|
+
api.post_bot("name" => "example", "stack" => "cedar")
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
api.delete_bot("example")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "shows all configs" do
|
16
|
+
api.put_config_vars("example", { 'FOO_BAR' => 'one', 'BAZ_QUX' => 'two' })
|
17
|
+
stderr, stdout = execute("config")
|
18
|
+
stderr.should == ""
|
19
|
+
stdout.should == <<-STDOUT
|
20
|
+
=== example Config Vars
|
21
|
+
BAZ_QUX: two
|
22
|
+
FOO_BAR: one
|
23
|
+
STDOUT
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not trim long values" do
|
27
|
+
api.put_config_vars("example", { 'LONG' => 'A' * 60 })
|
28
|
+
stderr, stdout = execute("config")
|
29
|
+
stderr.should == ""
|
30
|
+
stdout.should == <<-STDOUT
|
31
|
+
=== example Config Vars
|
32
|
+
LONG: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
33
|
+
STDOUT
|
34
|
+
end
|
35
|
+
|
36
|
+
it "handles when value is nil" do
|
37
|
+
api.put_config_vars("example", { 'FOO_BAR' => 'one', 'BAZ_QUX' => nil })
|
38
|
+
stderr, stdout = execute("config")
|
39
|
+
stderr.should == ""
|
40
|
+
stdout.should == <<-STDOUT
|
41
|
+
=== example Config Vars
|
42
|
+
BAZ_QUX: \nFOO_BAR: one
|
43
|
+
STDOUT
|
44
|
+
end
|
45
|
+
|
46
|
+
it "handles when value is a boolean" do
|
47
|
+
api.put_config_vars("example", { 'FOO_BAR' => 'one', 'BAZ_QUX' => true })
|
48
|
+
stderr, stdout = execute("config")
|
49
|
+
stderr.should == ""
|
50
|
+
stdout.should == <<-STDOUT
|
51
|
+
=== example Config Vars
|
52
|
+
BAZ_QUX: true
|
53
|
+
FOO_BAR: one
|
54
|
+
STDOUT
|
55
|
+
end
|
56
|
+
|
57
|
+
it "shows configs in a shell compatible format" do
|
58
|
+
api.put_config_vars("example", { 'A' => 'one', 'B' => 'two three' })
|
59
|
+
stderr, stdout = execute("config --shell")
|
60
|
+
stderr.should == ""
|
61
|
+
stdout.should == <<-STDOUT
|
62
|
+
A=one
|
63
|
+
B=two three
|
64
|
+
STDOUT
|
65
|
+
end
|
66
|
+
|
67
|
+
it "shows a single config for get" do
|
68
|
+
api.put_config_vars("example", { 'LONG' => 'A' * 60 })
|
69
|
+
stderr, stdout = execute("config:get LONG")
|
70
|
+
stderr.should == ""
|
71
|
+
stdout.should == <<-STDOUT
|
72
|
+
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
73
|
+
STDOUT
|
74
|
+
end
|
75
|
+
|
76
|
+
context("set") do
|
77
|
+
|
78
|
+
it "sets config vars" do
|
79
|
+
stderr, stdout = execute("config:set A=1 B=2")
|
80
|
+
stderr.should == ""
|
81
|
+
stdout.should == <<-STDOUT
|
82
|
+
Setting config vars and restarting example... done
|
83
|
+
A: 1
|
84
|
+
B: 2
|
85
|
+
STDOUT
|
86
|
+
end
|
87
|
+
|
88
|
+
it "allows config vars with = in the value" do
|
89
|
+
stderr, stdout = execute("config:set A=b=c")
|
90
|
+
stderr.should == ""
|
91
|
+
stdout.should == <<-STDOUT
|
92
|
+
Setting config vars and restarting example... done
|
93
|
+
A: b=c
|
94
|
+
STDOUT
|
95
|
+
end
|
96
|
+
|
97
|
+
it "sets config vars without changing case" do
|
98
|
+
stderr, stdout = execute("config:set a=b")
|
99
|
+
stderr.should == ""
|
100
|
+
stdout.should == <<-STDOUT
|
101
|
+
Setting config vars and restarting example... done
|
102
|
+
a: b
|
103
|
+
STDOUT
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "config:unset" do
|
109
|
+
|
110
|
+
it "exits with a help notice when no keys are provides" do
|
111
|
+
stderr, stdout = execute("config:unset")
|
112
|
+
stderr.should == <<-STDERR
|
113
|
+
! Usage: turbot config:unset KEY1 [KEY2 ...]
|
114
|
+
! Must specify KEY to unset.
|
115
|
+
STDERR
|
116
|
+
stdout.should == ""
|
117
|
+
end
|
118
|
+
|
119
|
+
context "when one key is provided" do
|
120
|
+
|
121
|
+
it "unsets a single key" do
|
122
|
+
stderr, stdout = execute("config:unset A")
|
123
|
+
stderr.should == ""
|
124
|
+
stdout.should == <<-STDOUT
|
125
|
+
Unsetting A and restarting example... done
|
126
|
+
STDOUT
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when more than one key is provided" do
|
131
|
+
|
132
|
+
it "unsets all given keys" do
|
133
|
+
stderr, stdout = execute("config:unset A B")
|
134
|
+
stderr.should == ""
|
135
|
+
stdout.should == <<-STDOUT
|
136
|
+
Unsetting A and restarting example... done
|
137
|
+
Unsetting B and restarting example... done
|
138
|
+
STDOUT
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/bots"
|
3
|
+
require "turbot/command/help"
|
4
|
+
|
5
|
+
describe Turbot::Command::Help do
|
6
|
+
|
7
|
+
describe "help" do
|
8
|
+
it "should show root help with no args" do
|
9
|
+
stderr, stdout = execute("help")
|
10
|
+
stderr.should == ""
|
11
|
+
stdout.should include "Usage: turbot COMMAND [--bot APP] [command-specific-options]"
|
12
|
+
stdout.should include "bots"
|
13
|
+
stdout.should include "help"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should show command help and namespace help when ambigious" do
|
17
|
+
stderr, stdout = execute("help bots")
|
18
|
+
stderr.should == ""
|
19
|
+
stdout.should include "turbot bots"
|
20
|
+
stdout.should include "list your bots"
|
21
|
+
stdout.should include "Additional commands"
|
22
|
+
stdout.should include "bots:info"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should show only command help when not ambiguous" do
|
26
|
+
stderr, stdout = execute("help bots:info")
|
27
|
+
stderr.should == ""
|
28
|
+
stdout.should include "turbot bots:info"
|
29
|
+
stdout.should_not include "Additional commands"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should show command help with --help" do
|
33
|
+
stderr, stdout = execute("bots:info --help")
|
34
|
+
stderr.should == ""
|
35
|
+
stdout.should include "Usage: turbot bots:info"
|
36
|
+
stdout.should_not include "Additional commands"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should redirect if the command is an alias" do
|
40
|
+
stderr, stdout = execute("help list")
|
41
|
+
stderr.should == ""
|
42
|
+
stdout.should include "Alias: list redirects to bots"
|
43
|
+
stdout.should include "Usage: turbot bots"
|
44
|
+
stdout.should include "list your bots"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should show if the command does not exist" do
|
48
|
+
stderr, stdout = execute("help sudo:sandwich")
|
49
|
+
stderr.should == <<-STDERR
|
50
|
+
! sudo:sandwich is not a turbot command. See `turbot help`.
|
51
|
+
STDERR
|
52
|
+
stdout.should == ""
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should show help with naked -h" do
|
56
|
+
stderr, stdout = execute("-h")
|
57
|
+
stderr.should == ""
|
58
|
+
stdout.should include "Usage: turbot COMMAND"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should show help with naked --help" do
|
62
|
+
stderr, stdout = execute("--help")
|
63
|
+
stderr.should == ""
|
64
|
+
stdout.should include "Usage: turbot COMMAND"
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "with legacy help" do
|
68
|
+
require "helper/legacy_help"
|
69
|
+
|
70
|
+
it "displays the legacy group in the namespace list" do
|
71
|
+
stderr, stdout = execute("help")
|
72
|
+
stderr.should == ""
|
73
|
+
stdout.should include "Foo Group"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "displays group help" do
|
77
|
+
stderr, stdout = execute("help foo")
|
78
|
+
stderr.should == ""
|
79
|
+
stdout.should include "do a bar to foo"
|
80
|
+
stdout.should include "do a baz to foo"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "displays legacy command-specific help" do
|
84
|
+
stderr, stdout = execute("help foo:bar")
|
85
|
+
stderr.should == ""
|
86
|
+
stdout.should include "do a bar to foo"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/keys"
|
3
|
+
|
4
|
+
module Turbot::Command
|
5
|
+
describe Keys do
|
6
|
+
KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAp9AJD5QABmOcrkHm6SINuQkDefaR0MUrfgZ1Pxir3a4fM1fwa00dsUwbUaRuR7FEFD8n1E9WwDf8SwQTHtyZsJg09G9myNqUzkYXCmydN7oGr5IdVhRyv5ixcdiE0hj7dRnOJg2poSQ3Qi+Ka8SVJzF7nIw1YhuicHPSbNIFKi5s0D5a+nZb/E6MNGvhxoFCQX2IcNxaJMqhzy1ESwlixz45aT72mXYq0LIxTTpoTqma1HuKdRY8HxoREiivjmMQulYP+CxXFcMyV9kxTKIUZ/FXqlC6G5vSm3J4YScSatPOj9ID5HowpdlIx8F6y4p1/28r2tTl4CY40FFyoke4MQ== pedro@turbot"
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
stub_core
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
api.delete_keys
|
14
|
+
end
|
15
|
+
|
16
|
+
context("add") do
|
17
|
+
it "tries to find a key if no key filename is supplied" do
|
18
|
+
Turbot::Auth.should_receive(:ask).and_return("y")
|
19
|
+
Turbot::Auth.should_receive(:generate_ssh_key)
|
20
|
+
File.should_receive(:exists?).with('/.ssh/id_rsa.pub').and_return(true)
|
21
|
+
File.should_receive(:read).with('/.ssh/id_rsa.pub').and_return(KEY)
|
22
|
+
stderr, stdout = execute("keys:add")
|
23
|
+
stderr.should == ""
|
24
|
+
stdout.should == <<-STDOUT
|
25
|
+
Could not find an existing public key.
|
26
|
+
Would you like to generate one? [Yn] Generating new SSH public key.
|
27
|
+
Uploading SSH public key /.ssh/id_rsa.pub... done
|
28
|
+
STDOUT
|
29
|
+
end
|
30
|
+
|
31
|
+
it "adds a key from a specified keyfile path" do
|
32
|
+
File.should_receive(:exists?).with('/my/key.pub').and_return(true)
|
33
|
+
File.should_receive(:read).with('/my/key.pub').and_return(KEY)
|
34
|
+
stderr, stdout = execute("keys:add /my/key.pub")
|
35
|
+
stderr.should == ""
|
36
|
+
stdout.should == <<-STDOUT
|
37
|
+
Uploading SSH public key /my/key.pub... done
|
38
|
+
STDOUT
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context("index") do
|
44
|
+
|
45
|
+
before do
|
46
|
+
api.post_key(KEY)
|
47
|
+
end
|
48
|
+
|
49
|
+
after do
|
50
|
+
api.delete_keys
|
51
|
+
end
|
52
|
+
|
53
|
+
it "list keys, trimming the hex code for better display" do
|
54
|
+
stderr, stdout = execute("keys")
|
55
|
+
stderr.should == ""
|
56
|
+
stdout.should == <<-STDOUT
|
57
|
+
=== email@example.com Keys
|
58
|
+
ssh-rsa AAAAB3NzaC...Fyoke4MQ== pedro@turbot
|
59
|
+
|
60
|
+
STDOUT
|
61
|
+
end
|
62
|
+
|
63
|
+
it "list keys showing the whole key hex with --long" do
|
64
|
+
stderr, stdout = execute("keys --long")
|
65
|
+
stderr.should == ""
|
66
|
+
stdout.should == <<-STDOUT
|
67
|
+
=== email@example.com Keys
|
68
|
+
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAp9AJD5QABmOcrkHm6SINuQkDefaR0MUrfgZ1Pxir3a4fM1fwa00dsUwbUaRuR7FEFD8n1E9WwDf8SwQTHtyZsJg09G9myNqUzkYXCmydN7oGr5IdVhRyv5ixcdiE0hj7dRnOJg2poSQ3Qi+Ka8SVJzF7nIw1YhuicHPSbNIFKi5s0D5a+nZb/E6MNGvhxoFCQX2IcNxaJMqhzy1ESwlixz45aT72mXYq0LIxTTpoTqma1HuKdRY8HxoREiivjmMQulYP+CxXFcMyV9kxTKIUZ/FXqlC6G5vSm3J4YScSatPOj9ID5HowpdlIx8F6y4p1/28r2tTl4CY40FFyoke4MQ== pedro@turbot
|
69
|
+
|
70
|
+
STDOUT
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
context("remove") do
|
76
|
+
|
77
|
+
context("success") do
|
78
|
+
|
79
|
+
before(:each) do
|
80
|
+
api.post_key(KEY)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "succeeds" do
|
84
|
+
stderr, stdout = execute("keys:remove pedro@turbot")
|
85
|
+
stderr.should == ""
|
86
|
+
stdout.should == <<-STDOUT
|
87
|
+
Removing pedro@turbot SSH key... done
|
88
|
+
STDOUT
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
it "displays an error if no key is specified" do
|
94
|
+
stderr, stdout = execute("keys:remove")
|
95
|
+
stderr.should == <<-STDERR
|
96
|
+
! Usage: turbot keys:remove KEY
|
97
|
+
! Must specify KEY to remove.
|
98
|
+
STDERR
|
99
|
+
stdout.should == ""
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
context("clear") do
|
105
|
+
|
106
|
+
it "succeeds" do
|
107
|
+
stderr, stdout = execute("keys:clear")
|
108
|
+
stderr.should == ""
|
109
|
+
stdout.should == <<-STDOUT
|
110
|
+
Removing all SSH keys... done
|
111
|
+
STDOUT
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/logs"
|
3
|
+
|
4
|
+
describe Turbot::Command::Logs do
|
5
|
+
describe "logs" do
|
6
|
+
it "runs with no options" do
|
7
|
+
stub_core.read_logs("example", [])
|
8
|
+
execute "logs"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "runs with options" do
|
12
|
+
stub_core.read_logs("example", [
|
13
|
+
"tail=1",
|
14
|
+
"num=2",
|
15
|
+
"ps=ps.3",
|
16
|
+
"source=source.4"
|
17
|
+
])
|
18
|
+
execute "logs --tail --num 2 --ps ps.3 --source source.4"
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "with log output" do
|
22
|
+
before(:each) do
|
23
|
+
stub_core.read_logs("example", []).yields("2011-01-01T00:00:00+00:00 bot[web.1]: test")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "prettifies tty output" do
|
27
|
+
old_stdout_isatty = $stdout.isatty
|
28
|
+
stub($stdout).isatty.returns(true)
|
29
|
+
stderr, stdout = execute("logs")
|
30
|
+
stderr.should == ""
|
31
|
+
stdout.should == <<-STDOUT
|
32
|
+
\e[36m2011-01-01T00:00:00+00:00 bot[web.1]:\e[0m test
|
33
|
+
STDOUT
|
34
|
+
stub($stdout).isatty.returns(old_stdout_isatty)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not use ansi if stdout is not a tty" do
|
38
|
+
old_stdout_isatty = $stdout.isatty
|
39
|
+
stub($stdout).isatty.returns(false)
|
40
|
+
stderr, stdout = execute("logs")
|
41
|
+
stderr.should == ""
|
42
|
+
stdout.should == <<-STDOUT
|
43
|
+
2011-01-01T00:00:00+00:00 bot[web.1]: test
|
44
|
+
STDOUT
|
45
|
+
stub($stdout).isatty.returns(old_stdout_isatty)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "does not use ansi if TERM is not set" do
|
49
|
+
term = ENV.delete("TERM")
|
50
|
+
stderr, stdout = execute("logs")
|
51
|
+
stderr.should == ""
|
52
|
+
stdout.should == <<-STDOUT
|
53
|
+
2011-01-01T00:00:00+00:00 bot[web.1]: test
|
54
|
+
STDOUT
|
55
|
+
ENV["TERM"] = term
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/status"
|
3
|
+
|
4
|
+
module Turbot::Command
|
5
|
+
describe Status do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
stub_core
|
9
|
+
end
|
10
|
+
|
11
|
+
it "displays status information" do
|
12
|
+
Excon.stub(
|
13
|
+
{
|
14
|
+
:host => 'status.turbot.com',
|
15
|
+
:method => :get,
|
16
|
+
:path => '/api/v3/current-status.json'
|
17
|
+
},
|
18
|
+
{
|
19
|
+
:body => Turbot::OkJson.encode({"status"=>{"Production"=>"red", "Development"=>"red"}, "issues"=>[{"created_at"=>"2012-06-07T15:55:51Z", "id"=>372, "resolved"=>false, "title"=>"HTTP Routing Errors", "updated_at"=>"2012-06-07T16:14:37Z", "href"=>"https://status.turbot.com/api/v3/issues/372", "updates"=>[{"contents"=>"The number of applications seeing H99 errors is continuing to decrease as we continue to work toward a full resolution of the HTTP routing issues. The API is back online now as well. ", "created_at"=>"2012-06-07T17:47:26Z", "id"=>1088, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T17:47:26Z"}, {"contents"=>"Our engineers are continuing to work toward a full resolution of the HTTP routing issues. The API is currently in maintenance mode intentionally as we restore application operations. ", "created_at"=>"2012-06-07T17:16:40Z", "id"=>1086, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T17:26:55Z"}, {"contents"=>"Most applications are back online at this time. Our engineers are working on getting the remaining bots back online. ", "created_at"=>"2012-06-07T16:50:21Z", "id"=>1085, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T16:50:21Z"}, {"contents"=>"Our routing engineers have pushed out a patch to our routing tier. The platform is recovering and applications are coming back online. Our engineers are continuing to fully restore service.", "created_at"=>"2012-06-07T16:36:37Z", "id"=>1084, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T16:36:37Z"}, {"contents"=>"We have identified an issue with our routers that is causing errors on HTTP requests to applications. Engineers are working to resolve the issue.\r\n", "created_at"=>"2012-06-07T16:15:25Z", "id"=>1083, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T16:15:28Z"}, {"contents"=>"We have confirmed widespread errors on the platform. Our engineers are continuing to investigate.\r\n", "created_at"=>"2012-06-07T15:58:56Z", "id"=>1082, "incident_id"=>372, "status_dev"=>"red", "status_prod"=>"red", "update_type"=>"update", "updated_at"=>"2012-06-07T15:58:58Z"}, {"contents"=>"Our automated systems have detected potential platform errors. We are investigating.\r\n", "created_at"=>"2012-06-07T15:55:51Z", "id"=>1081, "incident_id"=>372, "status_dev"=>"yellow", "status_prod"=>"yellow", "update_type"=>"issue", "updated_at"=>"2012-06-07T15:55:55Z"}]}]}),
|
20
|
+
:status => 200
|
21
|
+
}
|
22
|
+
)
|
23
|
+
|
24
|
+
Turbot::Command::Status.any_instance.should_receive(:time_ago).and_return('2012/09/11 09:34:56 (~ 3h ago)', '2012/09/11 12:33:56 (~ 1m ago)', '2012/09/11 12:29:56 (~ 5m ago)', '2012/09/11 12:24:56 (~ 10m ago)', '2012/09/11 12:04:56 (~ 30m ago)', '2012/09/11 11:34:56 (~ 1h ago)', '2012/09/11 10:34:56 (~ 2h ago)', '2012/09/11 09:34:56 (~ 3h ago)')
|
25
|
+
|
26
|
+
stderr, stdout = execute("status")
|
27
|
+
stderr.should == ''
|
28
|
+
stdout.should == <<-STDOUT
|
29
|
+
=== Turbot Status
|
30
|
+
Development: red
|
31
|
+
Production: red
|
32
|
+
|
33
|
+
=== HTTP Routing Errors 2012/09/11 09:34:56 (~ 3h+)
|
34
|
+
2012/09/11 12:33:56 (~ 1m ago) update The number of applications seeing H99 errors is continuing to decrease as we continue to work toward a full resolution of the HTTP routing issues. The API is back online now as well.
|
35
|
+
2012/09/11 12:29:56 (~ 5m ago) update Our engineers are continuing to work toward a full resolution of the HTTP routing issues. The API is currently in maintenance mode intentionally as we restore application operations.
|
36
|
+
2012/09/11 12:24:56 (~ 10m ago) update Most applications are back online at this time. Our engineers are working on getting the remaining bots back online.
|
37
|
+
2012/09/11 12:04:56 (~ 30m ago) update Our routing engineers have pushed out a patch to our routing tier. The platform is recovering and applications are coming back online. Our engineers are continuing to fully restore service.
|
38
|
+
2012/09/11 11:34:56 (~ 1h ago) update We have identified an issue with our routers that is causing errors on HTTP requests to applications. Engineers are working to resolve the issue.
|
39
|
+
2012/09/11 10:34:56 (~ 2h ago) update We have confirmed widespread errors on the platform. Our engineers are continuing to investigate.
|
40
|
+
2012/09/11 09:34:56 (~ 3h ago) issue Our automated systems have detected potential platform errors. We are investigating.
|
41
|
+
|
42
|
+
STDOUT
|
43
|
+
|
44
|
+
Excon.stubs.shift
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command/version"
|
3
|
+
|
4
|
+
module Turbot::Command
|
5
|
+
describe Version do
|
6
|
+
|
7
|
+
it "shows version info" do
|
8
|
+
stderr, stdout = execute("version")
|
9
|
+
stderr.should == ""
|
10
|
+
stdout.should == <<-STDOUT
|
11
|
+
#{Turbot.user_agent}
|
12
|
+
STDOUT
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "turbot/command"
|
3
|
+
require 'json' #FOR WEBMOCK
|
4
|
+
|
5
|
+
class FakeResponse
|
6
|
+
|
7
|
+
attr_accessor :body, :headers
|
8
|
+
|
9
|
+
def initialize(attributes)
|
10
|
+
self.body, self.headers = attributes[:body], attributes[:headers]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
body
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Turbot::Command do
|
20
|
+
before {
|
21
|
+
Turbot::Command.load
|
22
|
+
stub_core # setup fake auth
|
23
|
+
}
|
24
|
+
|
25
|
+
describe "parsing errors" do
|
26
|
+
it "extracts error messages from response when available in XML" do
|
27
|
+
Turbot::Command.extract_error('<errors><error>Invalid bot name</error></errors>').should == 'Invalid bot name'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "extracts error messages from response when available in JSON" do
|
31
|
+
Turbot::Command.extract_error("{\"error\":\"Invalid bot name\"}").should == 'Invalid bot name'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "extracts error messages from response when available in plain text" do
|
35
|
+
response = FakeResponse.new(:body => "Invalid bot name", :headers => { :content_type => "text/plain; charset=UTF8" })
|
36
|
+
Turbot::Command.extract_error(response).should == 'Invalid bot name'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "shows Internal Server Error when the response doesn't contain a XML or JSON" do
|
40
|
+
Turbot::Command.extract_error('<h1>HTTP 500</h1>').should == "Internal server error.\nRun `turbot status` to check for known platform issues."
|
41
|
+
end
|
42
|
+
|
43
|
+
it "shows Internal Server Error when the response is not plain text" do
|
44
|
+
response = FakeResponse.new(:body => "Foobar", :headers => { :content_type => "application/xml" })
|
45
|
+
Turbot::Command.extract_error(response).should == "Internal server error.\nRun `turbot status` to check for known platform issues."
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows a block to redefine the default error" do
|
49
|
+
Turbot::Command.extract_error("Foobar") { "Ok!" }.should == 'Ok!'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "doesn't format the response if set to raw" do
|
53
|
+
Turbot::Command.extract_error("Foobar", :raw => true) { "Ok!" }.should == 'Ok!'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "handles a nil body in parse_error_xml" do
|
57
|
+
lambda { Turbot::Command.parse_error_xml(nil) }.should_not raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
it "handles a nil body in parse_error_json" do
|
61
|
+
lambda { Turbot::Command.parse_error_json(nil) }.should_not raise_error
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "correctly resolves commands" do
|
66
|
+
class Turbot::Command::Test; end
|
67
|
+
class Turbot::Command::Test::Multiple; end
|
68
|
+
|
69
|
+
require "turbot/command/help"
|
70
|
+
require "turbot/command/bots"
|
71
|
+
|
72
|
+
Turbot::Command.parse("unknown").should be_nil
|
73
|
+
Turbot::Command.parse("list").should include(:klass => Turbot::Command::Bots, :method => :index)
|
74
|
+
Turbot::Command.parse("bots").should include(:klass => Turbot::Command::Bots, :method => :index)
|
75
|
+
Turbot::Command.parse("bots:info").should include(:klass => Turbot::Command::Bots, :method => :info)
|
76
|
+
end
|
77
|
+
|
78
|
+
context "help" do
|
79
|
+
it "works as a prefix" do
|
80
|
+
turbot("help bots:info").should =~ /show detailed bot information/
|
81
|
+
end
|
82
|
+
|
83
|
+
it "works as an option" do
|
84
|
+
turbot("bots:info -h").should =~ /show detailed bot information/
|
85
|
+
turbot("bots:info --help").should =~ /show detailed bot information/
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when no commands match" do
|
90
|
+
|
91
|
+
it "displays the version if --version is used" do
|
92
|
+
turbot("--version").should == <<-STDOUT
|
93
|
+
#{Turbot.user_agent}
|
94
|
+
STDOUT
|
95
|
+
end
|
96
|
+
|
97
|
+
it "suggests similar commands if there are any" do
|
98
|
+
original_stderr, original_stdout = $stderr, $stdout
|
99
|
+
$stderr = captured_stderr = StringIO.new
|
100
|
+
$stdout = captured_stdout = StringIO.new
|
101
|
+
begin
|
102
|
+
execute("bot")
|
103
|
+
rescue SystemExit
|
104
|
+
end
|
105
|
+
captured_stderr.string.should == <<-STDERR
|
106
|
+
! `bot` is not a turbot command.
|
107
|
+
! Perhaps you meant `bots`.
|
108
|
+
! See `turbot help` for a list of available commands.
|
109
|
+
STDERR
|
110
|
+
captured_stdout.string.should == ""
|
111
|
+
$stderr, $stdout = original_stderr, original_stdout
|
112
|
+
end
|
113
|
+
|
114
|
+
it "does not suggest similar commands if there are none" do
|
115
|
+
original_stderr, original_stdout = $stderr, $stdout
|
116
|
+
$stderr = captured_stderr = StringIO.new
|
117
|
+
$stdout = captured_stdout = StringIO.new
|
118
|
+
begin
|
119
|
+
execute("sandwich")
|
120
|
+
rescue SystemExit
|
121
|
+
end
|
122
|
+
captured_stderr.string.should == <<-STDERR
|
123
|
+
! `sandwich` is not a turbot command.
|
124
|
+
! See `turbot help` for a list of available commands.
|
125
|
+
STDERR
|
126
|
+
captured_stdout.string.should == ""
|
127
|
+
$stderr, $stdout = original_stderr, original_stdout
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|