pantry 0.0.0 → 0.1.0

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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +19 -0
  5. data/Gemfile +15 -0
  6. data/Guardfile +16 -0
  7. data/LICENSE +20 -0
  8. data/README.md +53 -0
  9. data/Rakefile +18 -0
  10. data/Vagrantfile +86 -0
  11. data/bin/pantry +11 -0
  12. data/bin/pantry-client +38 -0
  13. data/bin/pantry-server +33 -0
  14. data/dist/client.yml +79 -0
  15. data/dist/server.yml +56 -0
  16. data/dist/upstart/pantry-client.conf +12 -0
  17. data/dist/upstart/pantry-server.conf +12 -0
  18. data/doc/message_packet.dot +19 -0
  19. data/doc/message_packet.dot.png +0 -0
  20. data/doc/network_topology.dot +42 -0
  21. data/doc/network_topology.dot.png +0 -0
  22. data/lib/celluloid_zmq_patches.rb +16 -0
  23. data/lib/opt_parse_plus.rb +184 -0
  24. data/lib/pantry.rb +197 -0
  25. data/lib/pantry/cli.rb +154 -0
  26. data/lib/pantry/client.rb +131 -0
  27. data/lib/pantry/client_info.rb +34 -0
  28. data/lib/pantry/client_registry.rb +104 -0
  29. data/lib/pantry/command.rb +194 -0
  30. data/lib/pantry/command_handler.rb +53 -0
  31. data/lib/pantry/command_line.rb +115 -0
  32. data/lib/pantry/commands/create_client.rb +30 -0
  33. data/lib/pantry/commands/download_directory.rb +35 -0
  34. data/lib/pantry/commands/echo.rb +32 -0
  35. data/lib/pantry/commands/edit_application.rb +60 -0
  36. data/lib/pantry/commands/register_client.rb +38 -0
  37. data/lib/pantry/commands/status.rb +78 -0
  38. data/lib/pantry/commands/sync_directory.rb +50 -0
  39. data/lib/pantry/commands/update_application.rb +45 -0
  40. data/lib/pantry/commands/upload_file.rb +68 -0
  41. data/lib/pantry/communication.rb +20 -0
  42. data/lib/pantry/communication/client.rb +75 -0
  43. data/lib/pantry/communication/client_filter.rb +117 -0
  44. data/lib/pantry/communication/file_service.rb +125 -0
  45. data/lib/pantry/communication/file_service/file_progress.rb +164 -0
  46. data/lib/pantry/communication/file_service/receive_file.rb +97 -0
  47. data/lib/pantry/communication/file_service/send_file.rb +74 -0
  48. data/lib/pantry/communication/publish_socket.rb +20 -0
  49. data/lib/pantry/communication/reading_socket.rb +89 -0
  50. data/lib/pantry/communication/receive_socket.rb +23 -0
  51. data/lib/pantry/communication/security.rb +44 -0
  52. data/lib/pantry/communication/security/authentication.rb +98 -0
  53. data/lib/pantry/communication/security/curve_key_store.rb +120 -0
  54. data/lib/pantry/communication/security/curve_security.rb +70 -0
  55. data/lib/pantry/communication/security/null_security.rb +32 -0
  56. data/lib/pantry/communication/send_socket.rb +19 -0
  57. data/lib/pantry/communication/serialize_message.rb +84 -0
  58. data/lib/pantry/communication/server.rb +97 -0
  59. data/lib/pantry/communication/subscribe_socket.rb +33 -0
  60. data/lib/pantry/communication/wait_list.rb +45 -0
  61. data/lib/pantry/communication/writing_socket.rb +46 -0
  62. data/lib/pantry/config.rb +182 -0
  63. data/lib/pantry/file_editor.rb +67 -0
  64. data/lib/pantry/logger.rb +78 -0
  65. data/lib/pantry/message.rb +134 -0
  66. data/lib/pantry/multi_command.rb +36 -0
  67. data/lib/pantry/server.rb +132 -0
  68. data/lib/pantry/test/acceptance.rb +83 -0
  69. data/lib/pantry/test/support/fake_fs.rb +31 -0
  70. data/lib/pantry/test/support/matchers.rb +13 -0
  71. data/lib/pantry/test/support/minitest.rb +13 -0
  72. data/lib/pantry/test/support/mock_ui.rb +23 -0
  73. data/lib/pantry/test/unit.rb +13 -0
  74. data/lib/pantry/ui.rb +68 -0
  75. data/lib/pantry/version.rb +3 -0
  76. data/pantry.gemspec +40 -0
  77. data/test/acceptance/cli/error_handling_test.rb +7 -0
  78. data/test/acceptance/cli/execute_command_on_clients_test.rb +32 -0
  79. data/test/acceptance/cli/request_info_from_server_test.rb +44 -0
  80. data/test/acceptance/communication/client_requests_info_from_server_test.rb +28 -0
  81. data/test/acceptance/communication/heartbeat_test.rb +19 -0
  82. data/test/acceptance/communication/pub_sub_communication_test.rb +53 -0
  83. data/test/acceptance/communication/security_test.rb +117 -0
  84. data/test/acceptance/communication/server_requests_info_from_client_test.rb +41 -0
  85. data/test/acceptance/test_helper.rb +25 -0
  86. data/test/fixtures/config.yml +22 -0
  87. data/test/fixtures/empty.yml +2 -0
  88. data/test/fixtures/file_to_upload +3 -0
  89. data/test/root_dir/.gitkeep +0 -0
  90. data/test/unit/cli_test.rb +173 -0
  91. data/test/unit/client_registry_test.rb +61 -0
  92. data/test/unit/client_test.rb +128 -0
  93. data/test/unit/command_handler_test.rb +79 -0
  94. data/test/unit/command_line_test.rb +5 -0
  95. data/test/unit/command_test.rb +206 -0
  96. data/test/unit/commands/create_client_test.rb +25 -0
  97. data/test/unit/commands/download_directory_test.rb +58 -0
  98. data/test/unit/commands/echo_test.rb +22 -0
  99. data/test/unit/commands/edit_application_test.rb +84 -0
  100. data/test/unit/commands/register_client_test.rb +41 -0
  101. data/test/unit/commands/status_test.rb +81 -0
  102. data/test/unit/commands/sync_directory_test.rb +75 -0
  103. data/test/unit/commands/update_application_test.rb +35 -0
  104. data/test/unit/commands/upload_file_test.rb +51 -0
  105. data/test/unit/communication/client_filter_test.rb +262 -0
  106. data/test/unit/communication/client_test.rb +99 -0
  107. data/test/unit/communication/file_service/receive_file_test.rb +214 -0
  108. data/test/unit/communication/file_service/send_file_test.rb +110 -0
  109. data/test/unit/communication/file_service_test.rb +56 -0
  110. data/test/unit/communication/publish_socket_test.rb +19 -0
  111. data/test/unit/communication/reading_socket_test.rb +110 -0
  112. data/test/unit/communication/receive_socket_test.rb +20 -0
  113. data/test/unit/communication/security/authentication_test.rb +97 -0
  114. data/test/unit/communication/security/curve_key_store_test.rb +110 -0
  115. data/test/unit/communication/security/curve_security_test.rb +44 -0
  116. data/test/unit/communication/security/null_security_test.rb +15 -0
  117. data/test/unit/communication/security_test.rb +49 -0
  118. data/test/unit/communication/send_socket_test.rb +19 -0
  119. data/test/unit/communication/serialize_message_test.rb +128 -0
  120. data/test/unit/communication/server_test.rb +106 -0
  121. data/test/unit/communication/subscribe_socket_test.rb +46 -0
  122. data/test/unit/communication/wait_list_test.rb +60 -0
  123. data/test/unit/communication/writing_socket_test.rb +46 -0
  124. data/test/unit/config_test.rb +150 -0
  125. data/test/unit/logger_test.rb +79 -0
  126. data/test/unit/message_test.rb +179 -0
  127. data/test/unit/multi_command_test.rb +45 -0
  128. data/test/unit/opt_parse_plus_test.rb +218 -0
  129. data/test/unit/pantry_test.rb +82 -0
  130. data/test/unit/server_test.rb +166 -0
  131. data/test/unit/test_helper.rb +25 -0
  132. data/test/unit/ui_test.rb +58 -0
  133. 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