m2r 2.0.2 → 2.1.0.pre
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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +11 -3
- data/Vagrantfile +16 -0
- data/example/http_0mq.rb +4 -0
- data/kitchen/Rakefile +28 -0
- data/kitchen/auth.cfg +2 -0
- data/kitchen/cookbooks/build-essential/README.md +24 -0
- data/kitchen/cookbooks/build-essential/metadata.json +35 -0
- data/kitchen/cookbooks/build-essential/metadata.rb +10 -0
- data/kitchen/cookbooks/build-essential/recipes/default.rb +45 -0
- data/kitchen/cookbooks/essential/CHANGELOG.md +12 -0
- data/kitchen/cookbooks/essential/README.md +12 -0
- data/kitchen/cookbooks/essential/metadata.json +29 -0
- data/kitchen/cookbooks/essential/metadata.rb +6 -0
- data/kitchen/cookbooks/essential/recipes/default.rb +16 -0
- data/kitchen/cookbooks/m2r/CHANGELOG.md +12 -0
- data/kitchen/cookbooks/m2r/README.md +12 -0
- data/kitchen/cookbooks/m2r/metadata.json +29 -0
- data/kitchen/cookbooks/m2r/metadata.rb +6 -0
- data/kitchen/cookbooks/m2r/recipes/default.rb +13 -0
- data/kitchen/cookbooks/mongrel2/CHANGELOG.md +12 -0
- data/kitchen/cookbooks/mongrel2/README.md +12 -0
- data/kitchen/cookbooks/mongrel2/metadata.json +29 -0
- data/kitchen/cookbooks/mongrel2/metadata.rb +6 -0
- data/kitchen/cookbooks/mongrel2/recipes/default.rb +38 -0
- data/kitchen/cookbooks/ruby-build/README.md +12 -0
- data/kitchen/cookbooks/ruby-build/definitions/ruby.rb +65 -0
- data/kitchen/cookbooks/ruby-build/metadata.json +29 -0
- data/kitchen/cookbooks/ruby-build/metadata.rb +6 -0
- data/kitchen/cookbooks/ruby-build/recipes/default.rb +9 -0
- data/kitchen/cookbooks/zmq/CHANGELOG.md +12 -0
- data/kitchen/cookbooks/zmq/README.md +12 -0
- data/kitchen/cookbooks/zmq/metadata.json +29 -0
- data/kitchen/cookbooks/zmq/metadata.rb +6 -0
- data/kitchen/cookbooks/zmq/recipes/default.rb +36 -0
- data/kitchen/data_bags/README +1 -0
- data/kitchen/data_bags/vagrant.key +27 -0
- data/kitchen/data_bags/vagrant.pub +1 -0
- data/kitchen/m2r.cfg +5 -0
- data/kitchen/nodes/m2r.local.json +16 -0
- data/kitchen/roles/.gitkeep +0 -0
- data/kitchen/site-cookbooks/README +1 -0
- data/lib/m2r.rb +2 -0
- data/lib/m2r/connection.rb +30 -5
- data/lib/m2r/handler.rb +8 -0
- data/lib/m2r/multithread_handler.rb +27 -0
- data/lib/m2r/parser.rb +44 -0
- data/lib/m2r/rack_handler.rb +0 -2
- data/lib/m2r/request.rb +2 -21
- data/lib/m2r/version.rb +1 -1
- data/lib/rack/handler/mongrel2.rb +7 -3
- data/m2r.gemspec +3 -3
- data/test/support/test_handler.rb +29 -12
- data/test/test_helper.rb +1 -1
- data/test/unit/connection_test.rb +51 -16
- data/test/unit/handler_test.rb +33 -5
- data/test/unit/m2r_test.rb +2 -0
- data/test/unit/multithread_handler_test.rb +75 -0
- data/test/unit/rack_handler_test.rb +6 -2
- data/test/unit/{request_test.rb → request_parsing_test.rb} +5 -5
- metadata +71 -62
data/lib/m2r/parser.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'm2r/request'
|
2
|
+
|
3
|
+
module M2R
|
4
|
+
# Mongrel2 Request Parser
|
5
|
+
# @api public
|
6
|
+
class Parser
|
7
|
+
# Parse Mongrel2 request received via ZMQ message
|
8
|
+
#
|
9
|
+
# @param [String] msg Monrel2 Request message formatted according to rules
|
10
|
+
# of creating it described it m2 manual.
|
11
|
+
# @return [Request]
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
# @threadsafe true
|
15
|
+
def parse(msg)
|
16
|
+
sender, conn_id, path, rest = msg.split(' ', 4)
|
17
|
+
|
18
|
+
headers, rest = TNetstring.parse(rest)
|
19
|
+
body, _ = TNetstring.parse(rest)
|
20
|
+
headers = MultiJson.load(headers)
|
21
|
+
headers, mong = split_headers(headers)
|
22
|
+
headers = Headers.new headers, true
|
23
|
+
mong = Headers.new mong, true
|
24
|
+
Request.new(sender, conn_id, path, headers, mong, body)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def split_headers(headers)
|
30
|
+
http = {}
|
31
|
+
mongrel = {}
|
32
|
+
headers.each do |header, value|
|
33
|
+
if Request::MONGREL2_HEADERS.include?(header)
|
34
|
+
mongrel[header.downcase] = value
|
35
|
+
else
|
36
|
+
http[header] = value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return http, mongrel
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/lib/m2r/rack_handler.rb
CHANGED
data/lib/m2r/request.rb
CHANGED
@@ -57,16 +57,9 @@ module M2R
|
|
57
57
|
# @return [Request]
|
58
58
|
#
|
59
59
|
# @api public
|
60
|
+
# @deprecated
|
60
61
|
def self.parse(msg)
|
61
|
-
|
62
|
-
|
63
|
-
headers, rest = TNetstring.parse(rest)
|
64
|
-
body, _ = TNetstring.parse(rest)
|
65
|
-
headers = MultiJson.load(headers)
|
66
|
-
headers, mong = split_headers(headers)
|
67
|
-
headers = Headers.new headers, true
|
68
|
-
mong = Headers.new mong, true
|
69
|
-
self.new(sender, conn_id, path, headers, mong, body)
|
62
|
+
Parser.new.parse(msg)
|
70
63
|
end
|
71
64
|
|
72
65
|
# @return [M2R::Headers] HTTP headers
|
@@ -120,17 +113,5 @@ module M2R
|
|
120
113
|
method == 'JSON'
|
121
114
|
end
|
122
115
|
|
123
|
-
def self.split_headers(headers)
|
124
|
-
http = {}
|
125
|
-
mongrel = {}
|
126
|
-
headers.each do |header, value|
|
127
|
-
if MONGREL2_HEADERS.include?(header)
|
128
|
-
mongrel[header.downcase] = value
|
129
|
-
else
|
130
|
-
http[header] = value
|
131
|
-
end
|
132
|
-
end
|
133
|
-
return http, mongrel
|
134
|
-
end
|
135
116
|
end
|
136
117
|
end
|
data/lib/m2r/version.rb
CHANGED
@@ -13,10 +13,14 @@ module Rack
|
|
13
13
|
}
|
14
14
|
|
15
15
|
def self.run(app, options = {})
|
16
|
-
options
|
17
|
-
|
18
|
-
adapter
|
16
|
+
options = OpenStruct.new( DEFAULT_OPTIONS.merge(options) )
|
17
|
+
threadsafe_parser = M2R::Parser.new
|
18
|
+
adapter = M2R::RackHandler.new(app, connection_factory(options), threadsafe_parser)
|
19
|
+
graceful = Proc.new { adapter.stop }
|
20
|
+
trap("INT", &graceful)
|
21
|
+
trap("TERM", &graceful)
|
19
22
|
adapter.listen
|
23
|
+
M2R.zmq_context.terminate
|
20
24
|
end
|
21
25
|
|
22
26
|
def self.valid_options
|
data/m2r.gemspec
CHANGED
@@ -18,15 +18,15 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.version = M2R::VERSION
|
20
20
|
|
21
|
-
gem.add_dependency "ffi-rzmq", "
|
22
|
-
gem.add_dependency "ffi",
|
21
|
+
gem.add_dependency "ffi-rzmq", ">= 1.0.1"
|
22
|
+
gem.add_dependency "ffi", ">= 1.0.0"
|
23
23
|
gem.add_dependency "multi_json"
|
24
24
|
gem.add_dependency "tnetstring"
|
25
25
|
|
26
26
|
gem.add_development_dependency "rack"
|
27
27
|
gem.add_development_dependency "rake"
|
28
28
|
gem.add_development_dependency "minitest", "= 3.2.0"
|
29
|
-
gem.add_development_dependency "mocha", "
|
29
|
+
gem.add_development_dependency "mocha", ">= 0.14.0"
|
30
30
|
gem.add_development_dependency "bbq", "= 0.0.4"
|
31
31
|
gem.add_development_dependency "capybara-mechanize", "= 0.3.0"
|
32
32
|
gem.add_development_dependency "activesupport", "~> 3.2.7"
|
@@ -1,55 +1,72 @@
|
|
1
|
+
require 'thread'
|
1
2
|
require 'm2r/handler'
|
2
3
|
|
3
4
|
class TestHandler < M2R::Handler
|
4
5
|
attr_reader :called_methods
|
5
|
-
def initialize(
|
6
|
+
def initialize(connection_factory, parser)
|
6
7
|
super
|
8
|
+
@mutex = Mutex.new
|
7
9
|
@called_methods = []
|
10
|
+
Thread.current[:called_methods] = []
|
8
11
|
end
|
9
12
|
|
10
13
|
def on_wait()
|
11
|
-
unless
|
14
|
+
unless Thread.current[:called_methods].empty?
|
12
15
|
stop
|
13
16
|
return
|
14
17
|
end
|
15
|
-
|
18
|
+
called_method :wait
|
16
19
|
end
|
17
20
|
|
18
21
|
def on_request(request)
|
19
|
-
|
22
|
+
called_method :request
|
20
23
|
end
|
21
24
|
|
22
25
|
def process(request)
|
23
|
-
|
26
|
+
called_method :process
|
24
27
|
return "response"
|
25
28
|
end
|
26
29
|
|
27
30
|
def on_disconnect(request)
|
28
|
-
|
31
|
+
called_method :disconnect
|
29
32
|
end
|
30
33
|
|
31
34
|
def on_upload_start(request)
|
32
|
-
|
35
|
+
called_method :start
|
33
36
|
end
|
34
37
|
|
35
38
|
def on_upload_done(request)
|
36
|
-
|
39
|
+
called_method :done
|
37
40
|
end
|
38
41
|
|
39
42
|
def after_process(request, response)
|
40
|
-
|
43
|
+
called_method :after
|
41
44
|
return response
|
42
45
|
end
|
43
46
|
|
44
47
|
def after_reply(request, response)
|
45
|
-
|
48
|
+
called_method :reply
|
46
49
|
end
|
47
50
|
|
48
51
|
def after_all(request, response)
|
49
|
-
|
52
|
+
called_method :all
|
50
53
|
end
|
51
54
|
|
52
55
|
def on_error(request, response, error)
|
53
|
-
|
56
|
+
called_method :error
|
54
57
|
end
|
58
|
+
|
59
|
+
def on_interrupted
|
60
|
+
called_method :interrupted
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def called_method(mth)
|
66
|
+
Thread.current[:called_methods] << mth
|
67
|
+
@mutex.synchronize do
|
68
|
+
@called_methods << mth
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
55
72
|
end
|
data/test/test_helper.rb
CHANGED
@@ -11,17 +11,16 @@ module M2R
|
|
11
11
|
@push = M2R.zmq_context.socket(ZMQ::PUSH)
|
12
12
|
assert_equal 0, @push.bind(@request_addr), "Could not bind push socket in tests"
|
13
13
|
|
14
|
-
@sub = M2R.zmq_context.socket(ZMQ::SUB)
|
15
|
-
assert_equal 0, @sub.bind(@response_addr), "Could not bind sub socket in tests"
|
16
|
-
@sub.setsockopt(ZMQ::SUBSCRIBE, "")
|
17
|
-
|
18
|
-
|
19
14
|
@request_socket = M2R.zmq_context.socket(ZMQ::PULL)
|
20
15
|
@request_socket.connect(@request_addr)
|
21
16
|
|
22
17
|
@response_socket = M2R.zmq_context.socket(ZMQ::PUB)
|
23
|
-
@response_socket.
|
18
|
+
@response_socket.bind(@response_addr)
|
24
19
|
@response_socket.setsockopt(ZMQ::IDENTITY, @sender_id = SecureRandom.uuid)
|
20
|
+
|
21
|
+
@sub = M2R.zmq_context.socket(ZMQ::SUB)
|
22
|
+
assert_equal 0, @sub.connect(@response_addr), "Could not connect sub socket in tests"
|
23
|
+
@sub.setsockopt(ZMQ::SUBSCRIBE, "")
|
25
24
|
end
|
26
25
|
|
27
26
|
def teardown
|
@@ -33,48 +32,48 @@ module M2R
|
|
33
32
|
|
34
33
|
def test_receive_message
|
35
34
|
connection = Connection.new(@request_socket, @response_socket)
|
36
|
-
@push.send_string(msg = "1c5fd481-1121-49d8-a706-69127975db1a ebb407b2-49aa-48a5-9f96-9db121051484 / 2:{},0:,", ZMQ::
|
35
|
+
@push.send_string(msg = "1c5fd481-1121-49d8-a706-69127975db1a ebb407b2-49aa-48a5-9f96-9db121051484 / 2:{},0:,", ZMQ::NonBlocking)
|
37
36
|
assert_equal msg, connection.receive
|
38
37
|
end
|
39
38
|
|
40
39
|
def test_deliver_message
|
41
40
|
connection = Connection.new(@request_socket, @response_socket)
|
42
41
|
connection.deliver('uuid', ['conn1', 'conn2'], 'ddaattaa')
|
43
|
-
|
42
|
+
assert @sub.recv_string(msg = "") > 0
|
44
43
|
assert_equal "uuid 11:conn1 conn2, ddaattaa", msg
|
45
44
|
end
|
46
45
|
|
47
46
|
def test_string_reply_non_close
|
48
47
|
connection = Connection.new(@request_socket, @response_socket)
|
49
48
|
connection.reply( stub(sender: 'uuid', conn_id: 'conn1', close?: false), 'ddaattaa')
|
50
|
-
|
49
|
+
assert @sub.recv_string(msg = "") > 0
|
51
50
|
assert_equal "uuid 5:conn1, ddaattaa", msg
|
52
|
-
assert_equal -1, @sub.recv_string(msg = "", ZMQ::
|
51
|
+
assert_equal -1, @sub.recv_string(msg = "", ZMQ::NonBlocking)
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_string_reply_close
|
56
55
|
connection = Connection.new(@request_socket, @response_socket)
|
57
56
|
connection.reply( stub(sender: 'uuid', conn_id: 'conn1', close?: true), 'ddaattaa')
|
58
|
-
|
57
|
+
assert @sub.recv_string(msg = "") > 0
|
59
58
|
assert_equal "uuid 5:conn1, ddaattaa", msg
|
60
|
-
|
59
|
+
assert @sub.recv_string(msg = "") > 0
|
61
60
|
assert_equal "uuid 5:conn1, ", msg
|
62
61
|
end
|
63
62
|
|
64
63
|
def test_response_reply_non_close
|
65
64
|
connection = Connection.new(@request_socket, @response_socket)
|
66
65
|
connection.reply( stub(sender: 'uuid', conn_id: 'conn1'), mock(to_s: 'ddaattaa', close?: false))
|
67
|
-
|
66
|
+
assert @sub.recv_string(msg = "") > 0
|
68
67
|
assert_equal "uuid 5:conn1, ddaattaa", msg
|
69
|
-
assert_equal -1, @sub.recv_string(msg = "", ZMQ::
|
68
|
+
assert_equal -1, @sub.recv_string(msg = "", ZMQ::NonBlocking)
|
70
69
|
end
|
71
70
|
|
72
71
|
def test_response_reply_close
|
73
72
|
connection = Connection.new(@request_socket, @response_socket)
|
74
73
|
connection.reply( stub(sender: 'uuid', conn_id: 'conn1'), mock(to_s: 'ddaattaa', close?: true))
|
75
|
-
|
74
|
+
assert @sub.recv_string(msg = "") > 0
|
76
75
|
assert_equal "uuid 5:conn1, ddaattaa", msg
|
77
|
-
|
76
|
+
assert @sub.recv_string(msg = "") > 0
|
78
77
|
assert_equal "uuid 5:conn1, ", msg
|
79
78
|
end
|
80
79
|
|
@@ -84,6 +83,42 @@ module M2R
|
|
84
83
|
assert_raises(Connection::Error) { connection.receive }
|
85
84
|
end
|
86
85
|
|
86
|
+
def test_exception_erron_when_receiving
|
87
|
+
request_socket = mock(:recv_string => -1)
|
88
|
+
ZMQ::Util.expects(:errno).at_least_once.returns(4)
|
89
|
+
connection = Connection.new request_socket, nil
|
90
|
+
begin
|
91
|
+
connection.receive
|
92
|
+
flunk "exception expected"
|
93
|
+
rescue => er
|
94
|
+
assert_equal 4, er.errno
|
95
|
+
assert er.signal?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_exception_when_deliverying
|
100
|
+
ZMQ::Util.expects(:errno).at_least_once.returns(1)
|
101
|
+
response_socket = mock(:send_string => -1)
|
102
|
+
connection = Connection.new nil, response_socket
|
103
|
+
assert_raises(Connection::Error) { connection.deliver('uuid', ['connection_ids'], 'data') }
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_exception_signal_retry
|
107
|
+
ZMQ::Util.expects(:errno).at_least_once.returns(4)
|
108
|
+
response_socket = mock
|
109
|
+
response_socket.expects(:send_string).times(3).returns(-1)
|
110
|
+
connection = Connection.new nil, response_socket
|
111
|
+
assert_raises(Connection::Error) { connection.deliver('uuid', ['connection_ids'], 'data') }
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_exception_signal_retry_ok
|
115
|
+
ZMQ::Util.expects(:errno).at_least_once.returns(4)
|
116
|
+
response_socket = mock
|
117
|
+
response_socket.expects(:send_string).twice.returns(-1).then.returns(0)
|
118
|
+
connection = Connection.new nil, response_socket
|
119
|
+
assert connection.deliver('uuid', ['connection_ids'], 'data').size > 0
|
120
|
+
end
|
121
|
+
|
87
122
|
def test_exception_when_deliverying
|
88
123
|
response_socket = mock(:send_string => -1)
|
89
124
|
connection = Connection.new nil, response_socket
|
data/test/unit/handler_test.rb
CHANGED
@@ -4,7 +4,7 @@ module M2R
|
|
4
4
|
class HandlerTest < MiniTest::Unit::TestCase
|
5
5
|
|
6
6
|
def test_lifecycle_for_disconnect
|
7
|
-
connection = stub(:receive => "")
|
7
|
+
connection = stub(:receive => "", :close => nil)
|
8
8
|
connection.stubs(:connection).returns(connection)
|
9
9
|
parser = stub(:parse => disconnect_request)
|
10
10
|
h = TestHandler.new(connection, parser)
|
@@ -13,7 +13,7 @@ module M2R
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_lifecycle_for_upload_start
|
16
|
-
connection = stub(:receive => "")
|
16
|
+
connection = stub(:receive => "", :close => nil)
|
17
17
|
connection.stubs(:connection).returns(connection)
|
18
18
|
parser = stub(:parse => upload_start_request)
|
19
19
|
h = TestHandler.new(connection, parser)
|
@@ -22,7 +22,7 @@ module M2R
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_lifecycle_for_upload_done
|
25
|
-
connection = stub(:receive => "", :reply => nil)
|
25
|
+
connection = stub(:receive => "", :reply => nil, :close => nil)
|
26
26
|
connection.stubs(:connection).returns(connection)
|
27
27
|
parser = stub(:parse => upload_done_request)
|
28
28
|
h = TestHandler.new(connection, parser)
|
@@ -31,7 +31,7 @@ module M2R
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_lifecycle_for_exception_when_getting_request
|
34
|
-
connection = stub()
|
34
|
+
connection = stub(:close => nil)
|
35
35
|
connection.stubs(:receive).raises(StandardError)
|
36
36
|
connection.stubs(:connection).returns(connection)
|
37
37
|
h = TestHandler.new(connection, nil)
|
@@ -40,7 +40,7 @@ module M2R
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_lifecycle_for_exception_when_processing
|
43
|
-
connection = stub(:receive => "", :reply => nil)
|
43
|
+
connection = stub(:receive => "", :reply => nil, :close => nil)
|
44
44
|
connection.stubs(:connection).returns(connection)
|
45
45
|
parser = stub(:parse => request)
|
46
46
|
h = TestHandler.new(connection, parser)
|
@@ -54,6 +54,34 @@ module M2R
|
|
54
54
|
assert_equal [:wait, :request, :process, :all, :error], h.called_methods
|
55
55
|
end
|
56
56
|
|
57
|
+
def test_signal_when_receive
|
58
|
+
e = Connection::Error.new.tap{|x| x.errno = 4}
|
59
|
+
connection = stub(:reply => nil, :close => nil)
|
60
|
+
connection.stubs(:connection).returns(connection)
|
61
|
+
connection.expects(:receive).raises(e).then.returns("").twice
|
62
|
+
parser = stub(:parse => request)
|
63
|
+
h = TestHandler.new(connection, parser)
|
64
|
+
h.extend(Module.new(){
|
65
|
+
def on_wait
|
66
|
+
if @called_methods.size > 2
|
67
|
+
stop
|
68
|
+
return
|
69
|
+
end
|
70
|
+
@called_methods << :wait
|
71
|
+
end
|
72
|
+
})
|
73
|
+
h.listen
|
74
|
+
assert_equal [:wait, :interrupted, :wait, :request, :process, :after, :reply, :all], h.called_methods
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_connection_closed
|
78
|
+
connection = mock(:close => nil)
|
79
|
+
connection.expects(:connection).returns(connection)
|
80
|
+
h = TestHandler.new(connection, nil)
|
81
|
+
h.stop
|
82
|
+
h.listen
|
83
|
+
end
|
84
|
+
|
57
85
|
|
58
86
|
private
|
59
87
|
|
data/test/unit/m2r_test.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module M2R
|
4
|
+
class MultithreadHandlerTest < MiniTest::Unit::TestCase
|
5
|
+
SLEEP_TIME = 3
|
6
|
+
MARGIN_TIME = 1
|
7
|
+
WAIT_TIME = 1
|
8
|
+
|
9
|
+
class ThreadTestHandler < TestHandler
|
10
|
+
def process(request)
|
11
|
+
sleep(SLEEP_TIME)
|
12
|
+
super
|
13
|
+
return Thread.current.object_id.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TestSinglethreadHandlerFactory
|
18
|
+
def initialize(connection_factory, parser)
|
19
|
+
@connection_factory = connection_factory
|
20
|
+
@parser = parser
|
21
|
+
end
|
22
|
+
|
23
|
+
def new
|
24
|
+
ThreadTestHandler.new(@connection_factory, @parser)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup
|
29
|
+
@request_addr = "inproc://#{SecureRandom.hex}"
|
30
|
+
@response_addr = "inproc://#{SecureRandom.hex}"
|
31
|
+
|
32
|
+
@push = M2R.zmq_context.socket(ZMQ::PUSH)
|
33
|
+
assert_equal 0, @push.bind(@request_addr), "Could not bind push socket in tests"
|
34
|
+
|
35
|
+
@sub = M2R.zmq_context.socket(ZMQ::SUB)
|
36
|
+
assert_equal 0, @sub.bind(@response_addr), "Could not bind sub socket in tests"
|
37
|
+
@sub.setsockopt(ZMQ::SUBSCRIBE, "")
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
@push.close if @push
|
42
|
+
@sub.close if @sub
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_threads_are_processing_request_simultaneously
|
46
|
+
cf = ConnectionFactory.new(ConnectionFactory::Options.new(nil, @request_addr, @response_addr))
|
47
|
+
par = Parser.new
|
48
|
+
mth = MultithreadHandler.new(TestSinglethreadHandlerFactory.new(cf, par))
|
49
|
+
mth.listen
|
50
|
+
sleep(WAIT_TIME)
|
51
|
+
|
52
|
+
start = Time.now
|
53
|
+
8.times do |i|
|
54
|
+
@push.send_string(msg = "1c5fd481-1121-49d8-a706-69127975db1a ebb407b2-49aa-48a5-9f96-9db12105148#{i} / 2:{},1:#{i},", ZMQ::NonBlocking)
|
55
|
+
end
|
56
|
+
responses = 16.times.map do
|
57
|
+
@sub.recv_string(msg = "")
|
58
|
+
msg
|
59
|
+
end
|
60
|
+
finish = Time.now
|
61
|
+
|
62
|
+
mth.threads.each do |t|
|
63
|
+
t.join
|
64
|
+
end
|
65
|
+
|
66
|
+
blob = responses.join("\n")
|
67
|
+
mth.threads.each do |t|
|
68
|
+
assert blob.include?(", #{t.object_id}")
|
69
|
+
end
|
70
|
+
|
71
|
+
delta = finish - start
|
72
|
+
assert_in_delta(SLEEP_TIME, delta, MARGIN_TIME)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|