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
@@ -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
|