bane 0.3.0 → 0.4.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.
- checksums.yaml +15 -0
- data/README.md +16 -6
- data/Rakefile +1 -1
- data/TODO +5 -8
- data/bin/bane +4 -12
- data/examples/multiple_behaviors.rb +7 -6
- data/examples/readme_example.rb +2 -1
- data/examples/single_behavior.rb +2 -1
- data/lib/bane.rb +18 -5
- data/lib/bane/arguments_parser.rb +73 -0
- data/lib/bane/behavior_maker.rb +39 -0
- data/lib/bane/behaviors/responders/close_after_pause.rb +21 -0
- data/lib/bane/behaviors/responders/close_immediately.rb +14 -0
- data/lib/bane/behaviors/responders/deluge_response.rb +27 -0
- data/lib/bane/behaviors/responders/echo_response.rb +16 -0
- data/lib/bane/behaviors/responders/exported.rb +9 -0
- data/lib/bane/behaviors/responders/fixed_response.rb +25 -0
- data/lib/bane/behaviors/responders/for_each_line.rb +18 -0
- data/lib/bane/behaviors/responders/http_refuse_all_credentials.rb +31 -0
- data/lib/bane/behaviors/responders/never_respond.rb +27 -0
- data/lib/bane/behaviors/responders/newline_response.rb +18 -0
- data/lib/bane/behaviors/responders/random_response.rb +24 -0
- data/lib/bane/behaviors/responders/slow_response.rb +32 -0
- data/lib/bane/behaviors/servers/exported.rb +18 -0
- data/lib/bane/behaviors/servers/responder_server.rb +50 -0
- data/lib/bane/behaviors/servers/timeout_in_listen_queue.rb +51 -0
- data/lib/bane/command_line_configuration.rb +22 -79
- data/lib/bane/extensions.rb +7 -0
- data/test/bane/acceptance_test.rb +65 -0
- data/test/bane/arguments_parser_test.rb +76 -0
- data/test/bane/bane_test.rb +12 -0
- data/test/bane/behaviors/responders/close_after_pause_test.rb +30 -0
- data/test/bane/behaviors/responders/close_immediately_test.rb +14 -0
- data/test/bane/behaviors/responders/deluge_response_test.rb +20 -0
- data/test/bane/behaviors/responders/echo_response_test.rb +16 -0
- data/test/bane/behaviors/responders/fixed_response_test.rb +14 -0
- data/test/bane/behaviors/responders/for_each_line_test.rb +29 -0
- data/test/bane/behaviors/responders/http_refuse_all_credentials_test.rb +18 -0
- data/test/bane/behaviors/responders/never_respond_test.rb +31 -0
- data/test/bane/behaviors/responders/newline_response_test.rb +14 -0
- data/test/bane/behaviors/responders/random_response_test.rb +15 -0
- data/test/bane/behaviors/responders/slow_response_test.rb +21 -0
- data/test/bane/behaviors/servers/responder_server_test.rb +77 -0
- data/test/bane/behaviors/servers/timeout_in_listen_queue_test.rb +23 -0
- data/test/bane/command_line_configuration_test.rb +54 -72
- data/test/bane/extensions_test.rb +17 -0
- data/test/bane/fake_connection_test.rb +1 -1
- data/test/bane/launchable_role_tests.rb +20 -0
- data/test/bane/naive_http_response_test.rb +1 -1
- data/test/test_helper.rb +42 -1
- metadata +143 -99
- data/lib/bane/behavior_server.rb +0 -47
- data/lib/bane/behaviors.rb +0 -171
- data/lib/bane/compatibility.rb +0 -36
- data/lib/bane/configuration_parser.rb +0 -89
- data/lib/bane/service_registry.rb +0 -21
- data/test/bane/behavior_server_test.rb +0 -59
- data/test/bane/behaviors_test.rb +0 -135
- data/test/bane/configuration_parser_test.rb +0 -111
- data/test/bane/integration_test.rb +0 -92
- data/test/bane/service_registry_test.rb +0 -20
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Y2M3MGZkYWY0NDNhNjZlYTY5M2I2MGViMDljNjY3YzRiYmY2MDg3OA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OWY2YTY3ZDFmNDU4Y2I1MzEwZjViNDIzZGU0YzMzNzk4ZjdiMmIxOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODE5MDJlYzkyMzNmYzllYzRlMTAwY2RjYjNhYzlkNjA1NTU0ODRiZmNhOGZh
|
10
|
+
NjczN2E4ZjM4YjcyMjUyYTBlODUxNjVkM2NiODc4MjIyM2Q2MjE3OWNmYzk0
|
11
|
+
YmFjZmVlNzVmYjMyOGE4ZmJhZmYzYzU3MTljOWMyODc5YjRiYjM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MmI5ZjZmYjM5YTczYzQ0NjFmYjNlMTBlY2I5ZmJiY2ZkMmQ4MDM5MjczYjgw
|
14
|
+
MTJkMWQxOTVkOTExN2FiMjVjNjUxOGRlOWU1YTc3OGUxMjUxNDM1Mjk1Zjkw
|
15
|
+
NDU5YzgzYzE2OGQ0MTY4OTdlY2RjYzNlNDM0ZDEyZmEyMGI3YzI=
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Bane
|
2
2
|
|
3
|
+
[](http://travis-ci.org/danielwellman/bane) [](https://codeclimate.com/github/danielwellman/bane)
|
4
|
+
|
3
5
|
Bane is a test harness used to test your application's interaction with other servers. It is based upon the material from Michael Nygard's ["Release It!"](http://www.pragprog.com/titles/mnee/release-it) book as described in the "Test Harness" chapter.
|
4
6
|
|
5
7
|
## Why Use Bane?
|
@@ -8,12 +10,14 @@ If you are building an application, you may depend on third-party servers or web
|
|
8
10
|
|
9
11
|
## Setup
|
10
12
|
|
11
|
-
Bane is available as a gem. Install it with
|
13
|
+
Bane is available as a Ruby gem. Install it with
|
12
14
|
|
13
15
|
`gem install bane`
|
14
16
|
|
15
17
|
Note that Bane installs an executable, `bane`. Simply invoke `bane` with no arguments to get a usage description.
|
16
18
|
|
19
|
+
Bane requires Ruby 1.9 or later. If you would like to use a Ruby 1.8.7-compatible version, install version 0.3.0.
|
20
|
+
|
17
21
|
## Usage
|
18
22
|
|
19
23
|
Bane is designed with a few usage scenarios in mind:
|
@@ -40,13 +44,14 @@ require 'bane'
|
|
40
44
|
include Bane
|
41
45
|
|
42
46
|
launcher = Launcher.new(
|
43
|
-
[BehaviorServer.new(3000, Behaviors::FixedResponse.new(:
|
47
|
+
[BehaviorServer.new(3000, Behaviors::Responders::FixedResponse.new(message: "Shall we play a game?"))])
|
44
48
|
launcher.start
|
45
49
|
launcher.join
|
46
50
|
```
|
47
51
|
|
48
|
-
See the `examples`directory for more examples. For a list of options supported by the
|
49
|
-
included behaviors, see the source for the behaviors in `
|
52
|
+
See the `examples` directory for more examples. For a list of options supported by the
|
53
|
+
included behaviors, see the source for the behaviors in `lib/bane/behaviors`; note that you will find both
|
54
|
+
servers (that bind to sockets directly) and responders (that assume a running TCP server and communicate with a socket connection).
|
50
55
|
|
51
56
|
## Listening on all hosts
|
52
57
|
|
@@ -60,7 +65,7 @@ By default, the socket behaviors that send any data will close the connection im
|
|
60
65
|
|
61
66
|
For example, if you want to send a static response and then close the connection immediately, use `FixedResponse`. If you want to keep the connection open and respond to every line of input with the same data, use `FixedResponseForEachLine`. Note that these behaviors will never close the connection; they will happily respond to every line of input until you stop Bane.
|
62
67
|
|
63
|
-
If you are implementing a new behavior, you should consider whether or not you would like to provide another variation which keeps a connection open and responds after every line of input. If so, create the basic behavior which responds and closes the connection immediately, then create another behavior which includes the `ForEachLine` module. See the source in `lib/bane/behaviors.rb` for some examples.
|
68
|
+
If you are implementing a new behavior, you should consider whether or not you would like to provide another variation which keeps a connection open and responds after every line of input. If so, create the basic behavior which responds and closes the connection immediately, then create another behavior which includes the `ForEachLine` module. See the source in `lib/bane/behaviors/responders/fixed_response.rb` for some examples.
|
64
69
|
|
65
70
|
## Background
|
66
71
|
|
@@ -83,7 +88,7 @@ See the implementation of HttpRefuseAllCredentials for a simple example of an HT
|
|
83
88
|
* The service can send a response of HTML instead of the expected XML.
|
84
89
|
|
85
90
|
The following behaviors are not yet supported. These require the ability to manipulate
|
86
|
-
TCP packets at a low level
|
91
|
+
TCP packets at a low level, which may require a C or C++ extension or raw sockets.
|
87
92
|
|
88
93
|
* The connection can be refused.
|
89
94
|
* The request can sit in a listen queue until the caller times out.
|
@@ -93,3 +98,8 @@ TCP packets at a low level; which may require a C or C++ extension.
|
|
93
98
|
* The connection can be established, but packets could be lost causing retransmit delays
|
94
99
|
* The connection can be established, but the remote end never acknowledges receiving a packet, causing endless retransmits
|
95
100
|
|
101
|
+
## Support
|
102
|
+
|
103
|
+
<a href="http://www.cyrusinnovation.com/"><img src="http://www.cyrusinnovation.com/marketing/logo.png" alt="Cyrus"></a>
|
104
|
+
|
105
|
+
Thank you to [Cyrus](http://www.cyrusinnovation.com/) for supporting the development of this project.
|
data/Rakefile
CHANGED
@@ -22,7 +22,7 @@ Jeweler::Tasks.new do |gem|
|
|
22
22
|
other servers. It is based upon the material from Michael Nygard's "Release
|
23
23
|
It!" book as described in the "Test Harness" chapter.
|
24
24
|
END
|
25
|
-
gem.authors = ["Daniel Wellman"]
|
25
|
+
gem.authors = ["Daniel Wellman", "Joe Leo"]
|
26
26
|
gem.email = "dan@danielwellman.com"
|
27
27
|
gem.files = FileList[ 'lib/**/*', 'bin/*', 'test/**/*', 'examples/*',
|
28
28
|
'Rakefile' ]
|
data/TODO
CHANGED
@@ -1,21 +1,18 @@
|
|
1
1
|
Features:
|
2
|
-
- Quieter exits on Ctrl-C (than plain stack trace)
|
3
2
|
|
4
3
|
Design questions / Ideas:
|
5
|
-
- Make BasicBehavior a module called Behavior, and include that in each behavior?
|
6
|
-
- Is there a natural separation in Configuration between parsing arguments and instantiating/finding behaviors?
|
7
|
-
In particular, mocking "new" on a class seems to be a smell -- at least because I keep forgetting that 'new' must
|
8
|
-
return an object, and my mocks didn't do that (see CommandLineConfigurationTest, and the messier ConfigurationParserTest)
|
9
|
-
- Explore the ServiceRegistry usage -- should "find" behaviors be there? Printing?
|
10
|
-
- Decide if the current behaviors should be tied more directly to BehaviorServer, via subclassing or some other way.
|
11
4
|
- Figure out where the logger configuration logic belongs in the Launcher/BehaviorServer relationship
|
12
5
|
- Should the default logger go to STDERR or STDOUT?
|
13
|
-
- Break the Behaviors out into several files and test files?
|
14
6
|
- Log every request to the server/behavior, in addition to open, close. For this to work, it would have to be the
|
15
7
|
behavior's responsibility, since GServer#serve gets called only once for the lifetime of the connection.
|
8
|
+
- If we extract a commong logger, we might use that to test for proper disconnection in NeverRespondTest#test_disconnects_after_client_closes_connection
|
16
9
|
|
17
10
|
Future Behaviors:
|
18
11
|
- Create a more configurable version of the DelugeResponse which allows for a header, footer, content and times to repeat.
|
19
12
|
- Write the remaining bad HTTP behaviors. In addition, we may want to replace the NaiveHttpResponse with something
|
20
13
|
from the standard Ruby library, so that there's less code in this project, and so we know that we're
|
21
14
|
following the HTTP protocol.
|
15
|
+
- Have a tiny listen queue (queue size 0) and a connection never gets into the queue
|
16
|
+
- Have a giant listen queue (queue size max?) and only one thread processing -- times out in the listen queue
|
17
|
+
- Close the write part of the connection, but not the read
|
18
|
+
- Close the read part of the connection, but not the write
|
data/bin/bane
CHANGED
@@ -1,22 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
4
3
|
require 'bane'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
rescue Bane::ConfigurationError => ce
|
10
|
-
puts ce.message
|
11
|
-
puts config.usage
|
5
|
+
parser = Bane::CommandLineConfiguration.new(Bane.find_makeables)
|
6
|
+
servers = parser.process(ARGV) do |error_message|
|
7
|
+
puts error_message
|
12
8
|
exit 1
|
13
9
|
end
|
14
10
|
|
15
|
-
if servers.empty?
|
16
|
-
puts config.usage
|
17
|
-
exit 0
|
18
|
-
end
|
19
|
-
|
20
11
|
launcher = Bane::Launcher.new(servers)
|
21
12
|
launcher.start
|
13
|
+
trap("SIGINT") { Thread.new { launcher.stop; exit } }
|
22
14
|
launcher.join
|
@@ -2,18 +2,19 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
|
2
2
|
require 'bane'
|
3
3
|
|
4
4
|
include Bane
|
5
|
+
include Behaviors
|
5
6
|
|
6
7
|
# This example creates several behavior listening on distinct ports.
|
7
8
|
# Note the FixedResponse port specifies to listen to all hosts (0.0.0.0), all
|
8
9
|
# other servers listen to localhost only by default (127.0.0.1).
|
9
10
|
|
10
|
-
close_immediately =
|
11
|
-
never_respond =
|
12
|
-
fixed_response =
|
11
|
+
close_immediately = Responders::CloseImmediately.new
|
12
|
+
never_respond = Responders::NeverRespond.new
|
13
|
+
fixed_response = Responders::FixedResponse.new(message: "OK")
|
13
14
|
|
14
|
-
launcher = Launcher.new([
|
15
|
-
|
16
|
-
|
15
|
+
launcher = Launcher.new([Servers::ResponderServer.new(3000, close_immediately),
|
16
|
+
Servers::ResponderServer.new(8000, never_respond),
|
17
|
+
Servers::ResponderServer.new(8080, fixed_response, Servers::ALL_INTERFACES)])
|
17
18
|
launcher.start
|
18
19
|
# To run until interrupt, use the following line:
|
19
20
|
#launcher.join
|
data/examples/readme_example.rb
CHANGED
@@ -2,8 +2,9 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
|
2
2
|
require 'bane'
|
3
3
|
|
4
4
|
include Bane
|
5
|
+
include Behaviors
|
5
6
|
|
6
7
|
launcher = Launcher.new(
|
7
|
-
[
|
8
|
+
[Servers::ResponderServer.new(3000, Responders::FixedResponse.new(message: "Shall we play a game?"))])
|
8
9
|
launcher.start
|
9
10
|
launcher.join
|
data/examples/single_behavior.rb
CHANGED
@@ -2,11 +2,12 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
|
2
2
|
require 'bane'
|
3
3
|
|
4
4
|
include Bane
|
5
|
+
include Behaviors
|
5
6
|
|
6
7
|
# This example creates a single behavior listening on port 3000.
|
7
8
|
# Note that the behavior, CloseAfterPause, specifies a default duration to pause - 60 seconds.
|
8
9
|
|
9
|
-
behavior =
|
10
|
+
behavior = Servers::ResponderServer.new(3000, Responders::CloseAfterPause.new(duration: 60))
|
10
11
|
launcher = Launcher.new([behavior])
|
11
12
|
launcher.start
|
12
13
|
# To run until interrupt, use the following line:
|
data/lib/bane.rb
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
-
require 'bane/
|
2
|
-
require 'bane/
|
3
|
-
require 'bane/behaviors'
|
1
|
+
require 'bane/extensions'
|
2
|
+
require 'bane/behavior_maker'
|
3
|
+
require 'bane/behaviors/responders/for_each_line'
|
4
|
+
require 'bane/behaviors/responders/close_after_pause'
|
5
|
+
require 'bane/behaviors/responders/close_immediately'
|
6
|
+
require 'bane/behaviors/responders/deluge_response'
|
7
|
+
require 'bane/behaviors/responders/echo_response'
|
8
|
+
require 'bane/behaviors/responders/fixed_response'
|
9
|
+
require 'bane/behaviors/responders/http_refuse_all_credentials'
|
10
|
+
require 'bane/behaviors/responders/never_respond'
|
11
|
+
require 'bane/behaviors/responders/newline_response'
|
12
|
+
require 'bane/behaviors/responders/random_response'
|
13
|
+
require 'bane/behaviors/responders/slow_response'
|
14
|
+
require 'bane/behaviors/responders/exported'
|
15
|
+
require 'bane/behaviors/servers/responder_server'
|
16
|
+
require 'bane/behaviors/servers/timeout_in_listen_queue'
|
17
|
+
require 'bane/behaviors/servers/exported'
|
4
18
|
require 'bane/launcher'
|
5
|
-
require 'bane/
|
19
|
+
require 'bane/arguments_parser'
|
6
20
|
require 'bane/command_line_configuration'
|
7
|
-
require 'bane/configuration_parser'
|
8
21
|
require 'bane/naive_http_response'
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Bane
|
4
|
+
class ArgumentsParser
|
5
|
+
def initialize(makeable_names)
|
6
|
+
@makeable_names = makeable_names
|
7
|
+
@options = {host: default_host}
|
8
|
+
@option_parser = init_option_parser
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(args)
|
12
|
+
@option_parser.parse!(args)
|
13
|
+
|
14
|
+
raise ConfigurationError, "Missing arguments" if args.empty?
|
15
|
+
|
16
|
+
port = parse_port(args[0])
|
17
|
+
behaviors = args.drop(1)
|
18
|
+
ParsedArguments.new(port, @options[:host], behaviors)
|
19
|
+
rescue OptionParser::InvalidOption => io
|
20
|
+
raise ConfigurationError, io.message
|
21
|
+
end
|
22
|
+
|
23
|
+
def usage
|
24
|
+
@option_parser.help
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def init_option_parser
|
30
|
+
OptionParser.new do |opts|
|
31
|
+
opts.banner = 'Usage: bane [options] port [behaviors]'
|
32
|
+
opts.separator ''
|
33
|
+
opts.on('-l', '--listen-on-localhost',
|
34
|
+
"Listen on localhost, (#{default_host}). [default]") do
|
35
|
+
@options[:host] = default_host
|
36
|
+
end
|
37
|
+
opts.on('-a', '--listen-on-all-hosts', "Listen on all interfaces, (#{all_interfaces})") do
|
38
|
+
@options[:host] = all_interfaces
|
39
|
+
end
|
40
|
+
opts.separator ''
|
41
|
+
opts.separator 'All behaviors:'
|
42
|
+
opts.separator @makeable_names.sort.map { |title| " - #{title}" }.join("\n")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_port(port)
|
47
|
+
Integer(port)
|
48
|
+
rescue ArgumentError
|
49
|
+
raise ConfigurationError, "Invalid port number: #{port}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def all_interfaces
|
53
|
+
Behaviors::Servers::ALL_INTERFACES
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_host
|
57
|
+
Behaviors::Servers::LOCALHOST
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class ParsedArguments
|
62
|
+
|
63
|
+
attr_reader :port, :host, :behaviors
|
64
|
+
|
65
|
+
def initialize(port, host, behaviors)
|
66
|
+
@host = host
|
67
|
+
@port = port
|
68
|
+
@behaviors = behaviors
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Bane
|
2
|
+
|
3
|
+
class BehaviorMaker
|
4
|
+
def initialize(makeables)
|
5
|
+
@makeables = makeables
|
6
|
+
end
|
7
|
+
|
8
|
+
def create(behavior_names, starting_port, host)
|
9
|
+
behavior_names
|
10
|
+
.map { |behavior| makeables.fetch(behavior) { raise UnknownBehaviorError.new(behavior) } }
|
11
|
+
.map.with_index { |maker, index| maker.make(starting_port + index, host) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_all(starting_port, host)
|
15
|
+
makeables.sort.map.with_index { |name_maker_pair, index| name_maker_pair.last.make(starting_port + index, host) }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :makeables
|
21
|
+
end
|
22
|
+
|
23
|
+
class UnknownBehaviorError < RuntimeError
|
24
|
+
def initialize(name)
|
25
|
+
super "Unknown behavior: #{name}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ResponderMaker
|
30
|
+
def initialize(responder)
|
31
|
+
@responer = responder
|
32
|
+
end
|
33
|
+
|
34
|
+
def make(port, host)
|
35
|
+
Behaviors::Servers::ResponderServer.new(port, @responer.new, host)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bane
|
2
|
+
module Behaviors
|
3
|
+
module Responders
|
4
|
+
|
5
|
+
# Accepts a connection, pauses a fixed duration, then closes the connection.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# - duration: The number of seconds to wait before disconnect. Default: 30
|
9
|
+
class CloseAfterPause
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = {duration: 30}.merge(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def serve(io)
|
15
|
+
sleep(@options[:duration])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Bane
|
2
|
+
module Behaviors
|
3
|
+
module Responders
|
4
|
+
|
5
|
+
# Sends a large response. Response consists of a repeated 'x' character.
|
6
|
+
#
|
7
|
+
# Options
|
8
|
+
# - length: The size in bytes of the response to send. Default: 1,000,000 bytes
|
9
|
+
class DelugeResponse
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = {length: 1_000_000}.merge(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def serve(io)
|
15
|
+
length = @options[:length]
|
16
|
+
|
17
|
+
length.times { io.write('x') }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class DelugeResponseForEachLine < DelugeResponse
|
22
|
+
include ForEachLine
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bane
|
2
|
+
module Behaviors
|
3
|
+
module Responders
|
4
|
+
|
5
|
+
# Sends a static response.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# - message: The response message to send. Default: "Hello, world!"
|
9
|
+
class FixedResponse
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = {message: "Hello, world!"}.merge(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def serve(io)
|
15
|
+
io.write @options[:message]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class FixedResponseForEachLine < FixedResponse
|
20
|
+
include ForEachLine
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|