pantry 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +15 -0
- data/Guardfile +16 -0
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +18 -0
- data/Vagrantfile +86 -0
- data/bin/pantry +11 -0
- data/bin/pantry-client +38 -0
- data/bin/pantry-server +33 -0
- data/dist/client.yml +79 -0
- data/dist/server.yml +56 -0
- data/dist/upstart/pantry-client.conf +12 -0
- data/dist/upstart/pantry-server.conf +12 -0
- data/doc/message_packet.dot +19 -0
- data/doc/message_packet.dot.png +0 -0
- data/doc/network_topology.dot +42 -0
- data/doc/network_topology.dot.png +0 -0
- data/lib/celluloid_zmq_patches.rb +16 -0
- data/lib/opt_parse_plus.rb +184 -0
- data/lib/pantry.rb +197 -0
- data/lib/pantry/cli.rb +154 -0
- data/lib/pantry/client.rb +131 -0
- data/lib/pantry/client_info.rb +34 -0
- data/lib/pantry/client_registry.rb +104 -0
- data/lib/pantry/command.rb +194 -0
- data/lib/pantry/command_handler.rb +53 -0
- data/lib/pantry/command_line.rb +115 -0
- data/lib/pantry/commands/create_client.rb +30 -0
- data/lib/pantry/commands/download_directory.rb +35 -0
- data/lib/pantry/commands/echo.rb +32 -0
- data/lib/pantry/commands/edit_application.rb +60 -0
- data/lib/pantry/commands/register_client.rb +38 -0
- data/lib/pantry/commands/status.rb +78 -0
- data/lib/pantry/commands/sync_directory.rb +50 -0
- data/lib/pantry/commands/update_application.rb +45 -0
- data/lib/pantry/commands/upload_file.rb +68 -0
- data/lib/pantry/communication.rb +20 -0
- data/lib/pantry/communication/client.rb +75 -0
- data/lib/pantry/communication/client_filter.rb +117 -0
- data/lib/pantry/communication/file_service.rb +125 -0
- data/lib/pantry/communication/file_service/file_progress.rb +164 -0
- data/lib/pantry/communication/file_service/receive_file.rb +97 -0
- data/lib/pantry/communication/file_service/send_file.rb +74 -0
- data/lib/pantry/communication/publish_socket.rb +20 -0
- data/lib/pantry/communication/reading_socket.rb +89 -0
- data/lib/pantry/communication/receive_socket.rb +23 -0
- data/lib/pantry/communication/security.rb +44 -0
- data/lib/pantry/communication/security/authentication.rb +98 -0
- data/lib/pantry/communication/security/curve_key_store.rb +120 -0
- data/lib/pantry/communication/security/curve_security.rb +70 -0
- data/lib/pantry/communication/security/null_security.rb +32 -0
- data/lib/pantry/communication/send_socket.rb +19 -0
- data/lib/pantry/communication/serialize_message.rb +84 -0
- data/lib/pantry/communication/server.rb +97 -0
- data/lib/pantry/communication/subscribe_socket.rb +33 -0
- data/lib/pantry/communication/wait_list.rb +45 -0
- data/lib/pantry/communication/writing_socket.rb +46 -0
- data/lib/pantry/config.rb +182 -0
- data/lib/pantry/file_editor.rb +67 -0
- data/lib/pantry/logger.rb +78 -0
- data/lib/pantry/message.rb +134 -0
- data/lib/pantry/multi_command.rb +36 -0
- data/lib/pantry/server.rb +132 -0
- data/lib/pantry/test/acceptance.rb +83 -0
- data/lib/pantry/test/support/fake_fs.rb +31 -0
- data/lib/pantry/test/support/matchers.rb +13 -0
- data/lib/pantry/test/support/minitest.rb +13 -0
- data/lib/pantry/test/support/mock_ui.rb +23 -0
- data/lib/pantry/test/unit.rb +13 -0
- data/lib/pantry/ui.rb +68 -0
- data/lib/pantry/version.rb +3 -0
- data/pantry.gemspec +40 -0
- data/test/acceptance/cli/error_handling_test.rb +7 -0
- data/test/acceptance/cli/execute_command_on_clients_test.rb +32 -0
- data/test/acceptance/cli/request_info_from_server_test.rb +44 -0
- data/test/acceptance/communication/client_requests_info_from_server_test.rb +28 -0
- data/test/acceptance/communication/heartbeat_test.rb +19 -0
- data/test/acceptance/communication/pub_sub_communication_test.rb +53 -0
- data/test/acceptance/communication/security_test.rb +117 -0
- data/test/acceptance/communication/server_requests_info_from_client_test.rb +41 -0
- data/test/acceptance/test_helper.rb +25 -0
- data/test/fixtures/config.yml +22 -0
- data/test/fixtures/empty.yml +2 -0
- data/test/fixtures/file_to_upload +3 -0
- data/test/root_dir/.gitkeep +0 -0
- data/test/unit/cli_test.rb +173 -0
- data/test/unit/client_registry_test.rb +61 -0
- data/test/unit/client_test.rb +128 -0
- data/test/unit/command_handler_test.rb +79 -0
- data/test/unit/command_line_test.rb +5 -0
- data/test/unit/command_test.rb +206 -0
- data/test/unit/commands/create_client_test.rb +25 -0
- data/test/unit/commands/download_directory_test.rb +58 -0
- data/test/unit/commands/echo_test.rb +22 -0
- data/test/unit/commands/edit_application_test.rb +84 -0
- data/test/unit/commands/register_client_test.rb +41 -0
- data/test/unit/commands/status_test.rb +81 -0
- data/test/unit/commands/sync_directory_test.rb +75 -0
- data/test/unit/commands/update_application_test.rb +35 -0
- data/test/unit/commands/upload_file_test.rb +51 -0
- data/test/unit/communication/client_filter_test.rb +262 -0
- data/test/unit/communication/client_test.rb +99 -0
- data/test/unit/communication/file_service/receive_file_test.rb +214 -0
- data/test/unit/communication/file_service/send_file_test.rb +110 -0
- data/test/unit/communication/file_service_test.rb +56 -0
- data/test/unit/communication/publish_socket_test.rb +19 -0
- data/test/unit/communication/reading_socket_test.rb +110 -0
- data/test/unit/communication/receive_socket_test.rb +20 -0
- data/test/unit/communication/security/authentication_test.rb +97 -0
- data/test/unit/communication/security/curve_key_store_test.rb +110 -0
- data/test/unit/communication/security/curve_security_test.rb +44 -0
- data/test/unit/communication/security/null_security_test.rb +15 -0
- data/test/unit/communication/security_test.rb +49 -0
- data/test/unit/communication/send_socket_test.rb +19 -0
- data/test/unit/communication/serialize_message_test.rb +128 -0
- data/test/unit/communication/server_test.rb +106 -0
- data/test/unit/communication/subscribe_socket_test.rb +46 -0
- data/test/unit/communication/wait_list_test.rb +60 -0
- data/test/unit/communication/writing_socket_test.rb +46 -0
- data/test/unit/config_test.rb +150 -0
- data/test/unit/logger_test.rb +79 -0
- data/test/unit/message_test.rb +179 -0
- data/test/unit/multi_command_test.rb +45 -0
- data/test/unit/opt_parse_plus_test.rb +218 -0
- data/test/unit/pantry_test.rb +82 -0
- data/test/unit/server_test.rb +166 -0
- data/test/unit/test_helper.rb +25 -0
- data/test/unit/ui_test.rb +58 -0
- metadata +389 -13
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'unit/test_helper'
|
2
|
+
|
3
|
+
describe Pantry::Logger do
|
4
|
+
|
5
|
+
let(:mock_logger) {
|
6
|
+
logger = stub
|
7
|
+
logger.stubs(:level=)
|
8
|
+
logger
|
9
|
+
}
|
10
|
+
|
11
|
+
after do
|
12
|
+
# Unset global state caused by these tests
|
13
|
+
Celluloid.logger = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is accessible through top level Pantry.logger" do
|
17
|
+
logger = Pantry.logger = Pantry::Logger.new
|
18
|
+
assert_equal logger, Pantry.logger
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets the celluloid logger" do
|
22
|
+
logger = Pantry::Logger.new
|
23
|
+
|
24
|
+
assert Celluloid.logger.is_a?(::Logger), "Celluloid logger not set properly"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sets celluloid logger to a path if one given" do
|
28
|
+
config = Pantry::Config.new
|
29
|
+
config.log_to = File.expand_path("../../test.log", __FILE__)
|
30
|
+
|
31
|
+
logger = Pantry::Logger.new(config)
|
32
|
+
|
33
|
+
assert Celluloid.logger.is_a?(::Logger), "Celluloid logger not set properly"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sets the logger to go to Syslog if so configured" do
|
37
|
+
config = Pantry::Config.new
|
38
|
+
config.log_to = "syslog"
|
39
|
+
|
40
|
+
Syslog::Logger.expects(:new).with("pantry").returns(mock_logger)
|
41
|
+
|
42
|
+
logger = Pantry::Logger.new(config)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "configures the Syslog program name if one given in the config" do
|
46
|
+
config = Pantry::Config.new
|
47
|
+
config.log_to = "syslog"
|
48
|
+
config.syslog_program_name = "pantry-client"
|
49
|
+
|
50
|
+
Syslog::Logger.expects(:new).with("pantry-client").returns(mock_logger)
|
51
|
+
|
52
|
+
logger = Pantry::Logger.new(config)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "sets the log's level according to config.log_level" do
|
56
|
+
Pantry.config.log_level = :info
|
57
|
+
logger = Pantry::Logger.new
|
58
|
+
|
59
|
+
assert_equal ::Logger::INFO, Celluloid.logger.level
|
60
|
+
end
|
61
|
+
|
62
|
+
it "allows symbols when setting log level" do
|
63
|
+
config = Pantry::Config.new
|
64
|
+
config.log_level = :warn
|
65
|
+
|
66
|
+
logger = Pantry::Logger.new(config)
|
67
|
+
|
68
|
+
assert_equal ::Logger::WARN, Celluloid.logger.level
|
69
|
+
end
|
70
|
+
|
71
|
+
it "forwards unknown messages to the celluloid logger" do
|
72
|
+
logger = Pantry::Logger.new
|
73
|
+
|
74
|
+
Celluloid.logger.expects(:info).with("Message!")
|
75
|
+
|
76
|
+
logger.info("Message!")
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'unit/test_helper'
|
2
|
+
|
3
|
+
describe Pantry::Message do
|
4
|
+
|
5
|
+
it "takes a message type in constructor" do
|
6
|
+
message = Pantry::Message.new("message_type")
|
7
|
+
assert_equal "message_type", message.type
|
8
|
+
end
|
9
|
+
|
10
|
+
it "generates a UUID on construction" do
|
11
|
+
message = Pantry::Message.new("message_type")
|
12
|
+
assert_not_nil message.uuid
|
13
|
+
assert message.uuid.length > 10
|
14
|
+
end
|
15
|
+
|
16
|
+
it "knows who the message is meant for" do
|
17
|
+
message = Pantry::Message.new("")
|
18
|
+
message.to = "stream"
|
19
|
+
assert_equal "stream", message.to
|
20
|
+
end
|
21
|
+
|
22
|
+
it "defaults the #to value to all (the empty string)" do
|
23
|
+
message = Pantry::Message.new("")
|
24
|
+
assert_equal "", message.to
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can be given strings for the body parts" do
|
28
|
+
message = Pantry::Message.new("type")
|
29
|
+
message << "Part 1"
|
30
|
+
message << "Part 2"
|
31
|
+
|
32
|
+
assert_equal ["Part 1", "Part 2"], message.body
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can be given the identity of the sending party" do
|
36
|
+
message = Pantry::Message.new("type")
|
37
|
+
message.from = "server1"
|
38
|
+
|
39
|
+
assert_equal "server1", message.from
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can pull the identity string from an object that responds to identity" do
|
43
|
+
message = Pantry::Message.new("type")
|
44
|
+
client = Pantry::Client.new identity: "johnsonville"
|
45
|
+
message.from = client
|
46
|
+
|
47
|
+
assert_equal "johnsonville", message.from
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can be flagged to require a response" do
|
51
|
+
message = Pantry::Message.new("type")
|
52
|
+
message.requires_response!
|
53
|
+
|
54
|
+
assert message.requires_response?
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can build a response version of itself" do
|
58
|
+
message = Pantry::Message.new("type")
|
59
|
+
message << "Body part 1"
|
60
|
+
message << "Body part 2"
|
61
|
+
message.to = "server"
|
62
|
+
message.from = "client"
|
63
|
+
message.forwarded!
|
64
|
+
message.requires_response!
|
65
|
+
|
66
|
+
response = message.build_response
|
67
|
+
|
68
|
+
assert_equal "type", response.type
|
69
|
+
assert_equal [], response.body
|
70
|
+
assert_false response.requires_response?, "Message shouldn't require a response"
|
71
|
+
assert_equal "client", response.to
|
72
|
+
assert_equal "server", response.from
|
73
|
+
assert response.forwarded?
|
74
|
+
|
75
|
+
assert_equal message.uuid, response.uuid
|
76
|
+
end
|
77
|
+
|
78
|
+
it "clones custom metadata in a response message" do
|
79
|
+
message = Pantry::Message.new("type")
|
80
|
+
message[:custom_data] = "one"
|
81
|
+
|
82
|
+
response = message.build_response
|
83
|
+
|
84
|
+
assert_equal "one", response[:custom_data]
|
85
|
+
|
86
|
+
response[:custom_data] = "two"
|
87
|
+
assert_equal "one", message[:custom_data]
|
88
|
+
assert_equal "two", response[:custom_data]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "can be flagged as being forwarded" do
|
92
|
+
message = Pantry::Message.new("type")
|
93
|
+
assert_false message.forwarded?
|
94
|
+
|
95
|
+
message.forwarded!
|
96
|
+
assert message.forwarded?
|
97
|
+
end
|
98
|
+
|
99
|
+
it "has a hash of metadata" do
|
100
|
+
message = Pantry::Message.new
|
101
|
+
message.type = "read_stuff"
|
102
|
+
message.requires_response!
|
103
|
+
message.forwarded!
|
104
|
+
message.from = "99 Luftballoons"
|
105
|
+
message.to = "streamer"
|
106
|
+
|
107
|
+
assert_not_nil message.metadata[:uuid]
|
108
|
+
assert_equal "read_stuff", message.metadata[:type]
|
109
|
+
assert_equal "99 Luftballoons", message.metadata[:from]
|
110
|
+
assert_equal "streamer", message.metadata[:to]
|
111
|
+
assert message.metadata[:requires_response]
|
112
|
+
assert message.metadata[:forwarded]
|
113
|
+
end
|
114
|
+
|
115
|
+
it "ensures the #to field is always a string when writing metadata" do
|
116
|
+
message = Pantry::Message.new
|
117
|
+
assert_equal "", message.metadata[:to]
|
118
|
+
end
|
119
|
+
|
120
|
+
it "knows if it came from the server or a client" do
|
121
|
+
message = Pantry::Message.new
|
122
|
+
message.from = Pantry::SERVER_IDENTITY
|
123
|
+
|
124
|
+
assert message.from_server?
|
125
|
+
end
|
126
|
+
|
127
|
+
it "takes a hash of metadata and parses out approriate values" do
|
128
|
+
message = Pantry::Message.new
|
129
|
+
message.metadata = {
|
130
|
+
type: "read_stuff",
|
131
|
+
requires_response: true,
|
132
|
+
forwarded: true,
|
133
|
+
from: "99 Luftballoons",
|
134
|
+
to: "streamer",
|
135
|
+
uuid: "123-4567-890-1234"
|
136
|
+
}
|
137
|
+
|
138
|
+
assert_equal "123-4567-890-1234", message.uuid
|
139
|
+
assert_equal "read_stuff", message.type
|
140
|
+
assert_equal "99 Luftballoons", message.from
|
141
|
+
assert_equal "streamer", message.to
|
142
|
+
assert message.requires_response?
|
143
|
+
assert message.forwarded?
|
144
|
+
end
|
145
|
+
|
146
|
+
it "ensures the #to field is always a string when reading metadata" do
|
147
|
+
message = Pantry::Message.new
|
148
|
+
message.metadata = {
|
149
|
+
to: nil,
|
150
|
+
}
|
151
|
+
assert_equal "", message.to
|
152
|
+
end
|
153
|
+
|
154
|
+
it "allows custom metadata entries" do
|
155
|
+
message = Pantry::Message.new
|
156
|
+
message[:metadata_1] = "my metadata"
|
157
|
+
message[:some_name] = "johnson"
|
158
|
+
|
159
|
+
assert_equal "my metadata", message[:metadata_1]
|
160
|
+
assert_equal "johnson", message[:some_name]
|
161
|
+
|
162
|
+
assert_equal "my metadata", message.metadata[:custom][:metadata_1]
|
163
|
+
assert_equal "johnson", message.metadata[:custom][:some_name]
|
164
|
+
end
|
165
|
+
|
166
|
+
it "loads unknown metadata keys into the custom metadata" do
|
167
|
+
message = Pantry::Message.new
|
168
|
+
message.metadata = {
|
169
|
+
custom: {
|
170
|
+
metadata_1: "my metadata",
|
171
|
+
some_name: "johnson"
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
assert_equal "my metadata", message[:metadata_1]
|
176
|
+
assert_equal "johnson", message[:some_name]
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'unit/test_helper'
|
2
|
+
|
3
|
+
describe Pantry::MultiCommand do
|
4
|
+
|
5
|
+
class TestPart1 < Pantry::Command
|
6
|
+
def perform(message)
|
7
|
+
[1, client.identity, message.type]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class TestPart2 < Pantry::Command
|
12
|
+
def perform(message)
|
13
|
+
[2, client.identity, message.type]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TestPart3 < Pantry::Command
|
18
|
+
def perform(message)
|
19
|
+
[3, client.identity, message.type]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TestMultiCommand < Pantry::MultiCommand
|
24
|
+
performs [
|
25
|
+
TestPart1,
|
26
|
+
TestPart2,
|
27
|
+
TestPart3
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "runs multiple commands in order, combining return values" do
|
32
|
+
client = Pantry::Client.new identity: "Client"
|
33
|
+
command = TestMultiCommand.new
|
34
|
+
command.client = client
|
35
|
+
|
36
|
+
results = command.perform(Pantry::Message.new("Message"))
|
37
|
+
|
38
|
+
assert_equal [
|
39
|
+
[1, "Client", "Message"],
|
40
|
+
[2, "Client", "Message"],
|
41
|
+
[3, "Client", "Message"],
|
42
|
+
], results
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'unit/test_helper'
|
2
|
+
|
3
|
+
describe OptParsePlus do
|
4
|
+
|
5
|
+
it "adds block and option support to optparse" do
|
6
|
+
parser = OptParsePlus.new
|
7
|
+
parser.add_options do
|
8
|
+
option "-a", "--application APPLICATION", String, "An option"
|
9
|
+
end
|
10
|
+
|
11
|
+
command_line = %w(-a application_name)
|
12
|
+
options = parser.parse!(command_line)
|
13
|
+
|
14
|
+
assert_equal "application_name", options['application']
|
15
|
+
assert_equal "application_name", options[:application]
|
16
|
+
assert_equal [], command_line
|
17
|
+
end
|
18
|
+
|
19
|
+
it "adds command support to optparse" do
|
20
|
+
parser = OptParsePlus.new
|
21
|
+
parser.add_command("one") do
|
22
|
+
option "-a", "--application APPLICATION", String, "An option"
|
23
|
+
end
|
24
|
+
|
25
|
+
command_line = %w(one -a application_name)
|
26
|
+
options = parser.parse!(command_line)
|
27
|
+
|
28
|
+
assert_equal "application_name", options['one']['application']
|
29
|
+
assert_equal "application_name", options[:one][:application]
|
30
|
+
assert_equal [], command_line
|
31
|
+
end
|
32
|
+
|
33
|
+
it "allows setting an explicit banner" do
|
34
|
+
parser = OptParsePlus.new
|
35
|
+
parser.banner "pantry [command]"
|
36
|
+
|
37
|
+
help_text = parser.help
|
38
|
+
assert_match /pantry \[command\]/, help_text
|
39
|
+
end
|
40
|
+
|
41
|
+
it "allows specifying a description" do
|
42
|
+
parser = OptParsePlus.new
|
43
|
+
parser.add_options do
|
44
|
+
description "This is interesting yes!"
|
45
|
+
end
|
46
|
+
|
47
|
+
help_text = parser.help
|
48
|
+
assert_match /This is interesting/, help_text
|
49
|
+
end
|
50
|
+
|
51
|
+
it "works with commands with no block" do
|
52
|
+
parser = OptParsePlus.new
|
53
|
+
parser.add_command("run")
|
54
|
+
|
55
|
+
options = parser.parse!(%w(run))
|
56
|
+
assert_equal "run", options.command_found
|
57
|
+
end
|
58
|
+
|
59
|
+
it "allows specifying argument usage in the command name" do
|
60
|
+
parser = OptParsePlus.new
|
61
|
+
parser.add_command("run COMMAND")
|
62
|
+
|
63
|
+
command_line = %w(run Something)
|
64
|
+
options = parser.parse!(command_line)
|
65
|
+
|
66
|
+
assert_equal "run", options.command_found
|
67
|
+
assert_equal %w(Something), command_line
|
68
|
+
end
|
69
|
+
|
70
|
+
it "gives the command options the arguments as per the description string (???)"
|
71
|
+
|
72
|
+
it "processes arguments in order to support global and command options" do
|
73
|
+
parser = OptParsePlus.new
|
74
|
+
parser.add_options do
|
75
|
+
option "-L", "--log-level LEVEL"
|
76
|
+
end
|
77
|
+
|
78
|
+
parser.add_command("run") do
|
79
|
+
option "-c", "--command COMMAND"
|
80
|
+
end
|
81
|
+
|
82
|
+
command_line = %w(-L debug run --command DoThisNow)
|
83
|
+
options = parser.parse!(command_line)
|
84
|
+
|
85
|
+
assert_equal "run", options.command_found
|
86
|
+
assert_equal "debug", options['log-level']
|
87
|
+
assert_equal "DoThisNow", options['run']['command']
|
88
|
+
end
|
89
|
+
|
90
|
+
it "groups commands together, sorting subcommands alphabetically" do
|
91
|
+
parser = OptParsePlus.new
|
92
|
+
parser.add_command("run") do
|
93
|
+
group "Exercise"
|
94
|
+
end
|
95
|
+
|
96
|
+
parser.add_command("bike") do
|
97
|
+
group "Exercise"
|
98
|
+
end
|
99
|
+
|
100
|
+
parser.add_command("sleep") do
|
101
|
+
group "Lazy"
|
102
|
+
end
|
103
|
+
|
104
|
+
output, err = capture_io do
|
105
|
+
parser.parse!(%w(--help))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Group subheadings
|
109
|
+
assert_match /Exercise commands/, output
|
110
|
+
assert_match /Lazy commands/, output
|
111
|
+
|
112
|
+
# Check alphabetical sort
|
113
|
+
assert_match /bike.*run/m, output
|
114
|
+
end
|
115
|
+
|
116
|
+
it "adds a global help option" do
|
117
|
+
parser = OptParsePlus.new
|
118
|
+
|
119
|
+
options = nil
|
120
|
+
output, err = capture_io do
|
121
|
+
options = parser.parse!(%w(-h))
|
122
|
+
end
|
123
|
+
|
124
|
+
assert_match /Show this help message/, output
|
125
|
+
assert options['help'], "Help flag was not set"
|
126
|
+
end
|
127
|
+
|
128
|
+
it "adds help option to each command configured" do
|
129
|
+
parser = OptParsePlus.new
|
130
|
+
parser.add_command("run")
|
131
|
+
|
132
|
+
options = nil
|
133
|
+
output, err = capture_io do
|
134
|
+
options = parser.parse!(%w(run --help))
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_match /Show this help message/, output
|
138
|
+
assert options['help']
|
139
|
+
end
|
140
|
+
|
141
|
+
it "allows explicitly getting the help text" do
|
142
|
+
parser = OptParsePlus.new
|
143
|
+
help_text = parser.help
|
144
|
+
|
145
|
+
assert_match /Show this help message/, help_text
|
146
|
+
end
|
147
|
+
|
148
|
+
it "includes all known commands in the top-level help text" do
|
149
|
+
parser = OptParsePlus.new
|
150
|
+
parser.add_command("run") do
|
151
|
+
description "Run something"
|
152
|
+
end
|
153
|
+
|
154
|
+
parser.add_command("stop") do
|
155
|
+
description "Stop something from running"
|
156
|
+
end
|
157
|
+
|
158
|
+
parser.add_command("stock ITEM") do
|
159
|
+
description "Stock the item"
|
160
|
+
end
|
161
|
+
|
162
|
+
help_text = parser.help
|
163
|
+
|
164
|
+
assert_match /run\s+Run something/, help_text
|
165
|
+
assert_match /stop\s+Stop something/, help_text
|
166
|
+
assert_match /stock\s+Stock the item/, help_text
|
167
|
+
end
|
168
|
+
|
169
|
+
it "only shows the first line of a command's description in top-level help" do
|
170
|
+
parser = OptParsePlus.new
|
171
|
+
parser.add_command("run") do
|
172
|
+
description "Run something.
|
173
|
+
Run fast.
|
174
|
+
Don't run slow"
|
175
|
+
end
|
176
|
+
|
177
|
+
help_text = parser.help
|
178
|
+
|
179
|
+
assert_match /Run something/, help_text
|
180
|
+
assert_no_match /Run fast/, help_text
|
181
|
+
assert_no_match /Don't run slow/, help_text
|
182
|
+
end
|
183
|
+
|
184
|
+
it "includes sub-command descriptions and banner strings in help text" do
|
185
|
+
parser = OptParsePlus.new
|
186
|
+
parser.add_command("display MESSAGE") do
|
187
|
+
description "Show the given message"
|
188
|
+
option "-c", "--cap", "Capitalize the message"
|
189
|
+
end
|
190
|
+
|
191
|
+
help_text, error = capture_io do
|
192
|
+
parser.parse!(["display", "--help"])
|
193
|
+
end
|
194
|
+
|
195
|
+
assert_match /display \[options\] MESSAGE/, help_text
|
196
|
+
assert_match /-c, --cap/, help_text
|
197
|
+
assert_match /Capitalize the message/, help_text
|
198
|
+
assert_match /Show the given message/, help_text
|
199
|
+
end
|
200
|
+
|
201
|
+
it "cleans up extra white space in full command descriptions" do
|
202
|
+
parser = OptParsePlus.new
|
203
|
+
parser.add_command("display MESSAGE") do
|
204
|
+
description "Show the given message.
|
205
|
+
Requires a MESSAGE to be passed in.
|
206
|
+
and will Error out otherwise"
|
207
|
+
end
|
208
|
+
|
209
|
+
help_text, error = capture_io do
|
210
|
+
parser.parse!(["display", "--help"])
|
211
|
+
end
|
212
|
+
|
213
|
+
assert_match /^Show the given message/, help_text
|
214
|
+
assert_match /^Requires a MESSAGE/, help_text
|
215
|
+
assert_match /^and will Error/, help_text
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|