Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 10 files changed
  • 0 comments
  • 1 contributor
2  .travis.yml
... ... @@ -1,5 +1,7 @@
1 1 before_install:
2 2 - sudo apt-get install libdb-dev
  3 +services:
  4 + - redis-server
3 5 language: ruby
4 6 rvm:
5 7 - ree-1.8.7
15 Gemfile
@@ -8,11 +8,12 @@ gem "yajl-ruby"
8 8
9 9 group :development do
10 10 gem "bdb"
11   - gem "yard", "~> 0.8.0"
12   - gem "minitest"
13   - gem "bundler", "~> 1.2"
14   - gem "jeweler", "~> 1.8.4"
15   - gem "simplecov"
16   - gem "simplecov-rcov"
17   - gem "travis-lint"
  11 + gem "redis-namespace"
  12 + gem "yard", "~> 0.8.0"
  13 + gem "minitest", "~> 4.5"
  14 + gem "bundler", "~> 1.2"
  15 + gem "jeweler", "~> 1.8.4"
  16 + gem "simplecov", "~> 0.7.1"
  17 + gem "simplecov-rcov", "~> 0.2.3"
  18 + gem "travis-lint", "~> 1.4"
18 19 end
28 Gemfile.lock
@@ -22,23 +22,26 @@ GEM
22 22 git (>= 1.2.5)
23 23 rake
24 24 rdoc
25   - json (1.7.5)
26   - minitest (4.2.0)
27   - multi_json (1.3.7)
28   - rake (0.9.2.2)
29   - rdoc (3.12)
  25 + json (1.7.6)
  26 + minitest (4.5.0)
  27 + multi_json (1.5.0)
  28 + rake (10.0.3)
  29 + rdoc (3.12.1)
30 30 json (~> 1.4)
  31 + redis (3.0.2)
  32 + redis-namespace (1.2.1)
  33 + redis (~> 3.0.0)
31 34 simplecov (0.7.1)
32 35 multi_json (~> 1.0)
33 36 simplecov-html (~> 0.7.1)
34 37 simplecov-html (0.7.1)
35 38 simplecov-rcov (0.2.3)
36 39 simplecov (>= 0.4.1)
37   - travis-lint (1.4.0)
38   - hashr (>= 0.0.19)
  40 + travis-lint (1.6.0)
  41 + hashr (~> 0.0.22)
39 42 tuple (0.1.2)
40 43 yajl-ruby (1.1.0)
41   - yard (0.8.3)
  44 + yard (0.8.4.1)
42 45
43 46 PLATFORMS
44 47 ruby
@@ -50,10 +53,11 @@ DEPENDENCIES
50 53 eventmachine
51 54 http_parser.rb
52 55 jeweler (~> 1.8.4)
53   - minitest
54   - simplecov
55   - simplecov-rcov
56   - travis-lint
  56 + minitest (~> 4.5)
  57 + redis-namespace
  58 + simplecov (~> 0.7.1)
  59 + simplecov-rcov (~> 0.2.3)
  60 + travis-lint (~> 1.4)
57 61 tuple
58 62 yajl-ruby
59 63 yard (~> 0.8.0)
59 lib/yup.rb
... ... @@ -1,3 +1,4 @@
  1 +require 'uri'
1 2 require 'rubygems'
2 3 require 'eventmachine'
3 4 require 'logger'
@@ -7,6 +8,7 @@
7 8 require 'yup/version'
8 9 require 'yup/request_forwarder'
9 10 require 'yup/request_handler'
  11 +require 'yup/state'
10 12
11 13 module Yup
12 14 @@resend_delay = 60.0
@@ -26,8 +28,8 @@ def self.retry_unless_2xx; @@retry_unless_2xx end
26 28 def self.retry_unless_2xx=(bool); @@retry_unless_2xx = bool end
27 29
28 30 def self.run(config)
29   - host = config[:listen_host] || 'localhost'
30   - port = config[:listen_port] || 8080
  31 + host = config[:listen_host] || 'localhost'
  32 + port = config[:listen_port] || 8080
31 33 status_code = config[:status_code] || 200
32 34 forward_to = config[:forward_to]
33 35 timeout = config[:timeout] || 60
@@ -39,7 +41,18 @@ def self.run(config)
39 41 end
40 42
41 43 def self.run_with_state(config)
42   - require 'yup/state'
  44 + case State.state_type(config[:persistent])
  45 + when :bdb
  46 + self.run_with_bdb(config)
  47 + when :redis
  48 + self.run_with_redis(config)
  49 + else
  50 + abort "Unknown scheme of persistent queue."
  51 + end
  52 + end
  53 +
  54 + def self.run_with_bdb(config)
  55 + require 'yup/state/bdb'
43 56
44 57 host = config[:listen_host] || 'localhost'
45 58 port = config[:listen_port] || 8080
@@ -48,17 +61,17 @@ def self.run_with_state(config)
48 61 dbpath = config[:persistent]
49 62 timeout = config[:timeout] || 60
50 63 feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
51   - state = Yup::State.new(dbpath, forward_to, feedback_channel)
  64 + state = State::BDB.new(dbpath, forward_to, feedback_channel)
52 65
53 66 pid = Process.fork do
54   - State::RequestForwarder.new(state, forward_to, timeout).run_loop
  67 + State::BDB::RequestForwarder.new(state, forward_to, timeout).run_loop
55 68 end
56 69
57 70 if pid
58 71 db_closer = proc do
59 72 Yup.logger.info { "Terminating consumer #{$$}" }
60 73 Process.kill("KILL", pid)
61   - state.close
  74 + state.dispose()
62 75 exit 0
63 76 end
64 77 Signal.trap("TERM", &db_closer)
@@ -66,11 +79,43 @@ def self.run_with_state(config)
66 79 end
67 80
68 81 EM.run do
69   - EM.start_unix_domain_server(feedback_channel, State::FeedbackHandler, state)
  82 + EM.start_unix_domain_server(feedback_channel, State::BDB::FeedbackHandler, state)
70 83 logger.info { "Feedback through #{feedback_channel}" }
71 84
72 85 EM.start_server(host, port, RequestHandler, forward_to, status_code, state, timeout)
73 86 logger.info { "Listening on #{host}:#{port}" }
74 87 end
75 88 end
  89 +
  90 + def self.run_with_redis(config)
  91 + require 'yup/state/redis'
  92 +
  93 + host = config[:listen_host] || 'localhost'
  94 + port = config[:listen_port] || 8080
  95 + status_code = config[:status_code] || 200
  96 + forward_to = config[:forward_to]
  97 + dbpath = config[:persistent]
  98 + timeout = config[:timeout] || 60
  99 + state = State::Redis.new(dbpath, forward_to)
  100 +
  101 + pid = Process.fork do
  102 + State::Redis::RequestForwarder.new(state, forward_to, timeout).run_loop
  103 + end
  104 +
  105 + if pid
  106 + db_closer = proc do
  107 + Yup.logger.info { "Terminating consumer #{$$}" }
  108 + Process.kill("KILL", pid)
  109 + state.dispose()
  110 + exit 0
  111 + end
  112 + Signal.trap("TERM", &db_closer)
  113 + Signal.trap("INT", &db_closer)
  114 + end
  115 +
  116 + EM.run do
  117 + EM.start_server(host, port, RequestHandler, forward_to, status_code, state, timeout)
  118 + logger.info { "Listening on #{host}:#{port}" }
  119 + end
  120 + end
76 121 end
128 lib/yup/request_forwarder.rb
@@ -67,132 +67,4 @@ def log_response(http)
67 67 end
68 68 end
69 69 end
70   -
71   - class State
72   - class RequestForwarder
73   - def initialize(state, forward_to, timeout)
74   - @state = state
75   - @forward_to = forward_to
76   - @timeout = timeout
77   - @logger = Yup.logger.clone
78   - @logger.progname = "Yup::State::RequestForwarder"
79   -
80   - @yajl = Yajl::Parser.new(:symbolize_keys => true)
81   - @yajl.on_parse_complete = self.method(:make_request)
82   - end
83   -
84   - def run_loop
85   - loop do
86   - data = @state.bpop
87   - begin
88   - @yajl << data
89   - rescue Yajl::ParseError
90   - @logger.error { "Error while parsing \"#{data}\"" }
91   - end
92   - end
93   - end
94   -
95   - def make_request(req)
96   - begin
97   - @http_method, @request_url, headers, body = req
98   - headers = Hash[*headers.to_a.flatten.map(&:to_s)]
99   - headers["Host"] = @forward_to
100   - headers["Connection"] = "Close"
101   -
102   - req = "#{@http_method.upcase} #{@request_url} HTTP/1.1\r\n"
103   - headers.each do |k, v|
104   - req << "#{k}: #{v}\r\n"
105   - end
106   - req << "\r\n"
107   - req << body if !body.empty?
108   - raw_response = send_data(req.to_s, @forward_to)
109   -
110   - response_body = ""
111   - http = Http::Parser.new()
112   - http.on_body = proc do |chunk|
113   - response_body << chunk
114   - end
115   - http << raw_response
116   -
117   - if http.status_code && http.status_code / 100 == 2
118   - log_response(raw_response, response_body, http)
119   - @logger.info "Success"
120   - else
121   - log_response(raw_response, response_body, http)
122   - if Yup.retry_unless_2xx
123   - @logger.info "Fail: got status code #{http.status_code}; will retry after #{Yup.resend_delay} seconds"
124   - @state.to_feedback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
125   -
126   - sleep Yup.resend_delay
127   - else
128   - @logger.info "Fail; will not retry"
129   - end
130   - end
131   -
132   - rescue Exception, Timeout::Error => e
133   - log_response(raw_response, response_body, http)
134   - @logger.info "Error: #{e.class}: #{e.message}; will retry after #{Yup.resend_delay} seconds"
135   -
136   - @state.to_feedback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
137   -
138   - sleep Yup.resend_delay
139   - end
140   - end
141   -
142   - private
143   - def log_response(raw_response, body, http)
144   - @logger.info { "HTTP request: #{@http_method.upcase} #{@request_url} HTTP/1.1" }
145   - if raw_response && !raw_response.empty?
146   - @logger.info { "HTTP response: #{raw_response.lines.first.chomp}" }
147   - @logger.debug { "HTTP response headers" + (http.headers.empty? ? " is empty" : "\n" + http.headers.inspect) }
148   - @logger.debug { "HTTP response body" + (body.empty? ? " is empty" : "\n" + body.inspect) }
149   - end
150   - end
151   -
152   - def send_data(data, host)
153   - host, port = host.split(":")
154   - addr = Socket.getaddrinfo(host, nil)
155   - sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
156   -
157   - secs = Integer(@timeout)
158   - usecs = Integer((@timeout - secs) * 1_000_000)
159   - optval = [secs, usecs].pack("l_2")
160   - sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval)
161   - sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval)
162   -
163   - resp = Timeout::timeout(@timeout) do
164   - sock.connect(Socket.pack_sockaddr_in(port, addr[0][3]))
165   - sock.write(data)
166   - sock.read()
167   - end
168   - return resp
169   - ensure
170   - sock.close()
171   - end
172   - end
173   -
174   - class FeedbackHandler < EM::Connection
175   - def initialize(state)
176   - @state = state
177   -
178   - @yajl = Yajl::Parser.new(:symbolize_keys => true)
179   - @yajl.on_parse_complete = method(:on_message)
180   -
181   - @logger = Yup.logger.clone
182   - @logger.progname = "Yup::State::FeedbackHandler"
183   - end
184   -
185   - def receive_data(data)
186   - begin
187   - @yajl << data
188   - rescue Yajl::ParseError
189   - @logger.error { "Error while parsing \"#{data}\"" }
190   - end
191   - end
192   -
193   - def on_message(req)
194   - @state.push(Yajl::Encoder.encode(req))
195   - end
196   - end
197   - end
198 70 end
149 lib/yup/state.rb
... ... @@ -1,64 +1,115 @@
1   -begin
2   - require 'bdb'
3   - require 'bdb/database'
4   -rescue LoadError
5   - puts "Install bdb gem to use a persistent queue."
6   -end
  1 +module Yup
  2 + module State
  3 + def self.queue_type(str)
  4 + uri = URI.parse(str)
  5 + case uri.scheme
  6 + when "bdb"
  7 + :bdb
  8 + when "redis"
  9 + :redis
  10 + end
  11 + end
7 12
8   -require "timeout"
  13 + class RequestForwarder
  14 + def initialize(state, forward_to, timeout)
  15 + @state = state
  16 + @forward_to = forward_to
  17 + @timeout = timeout
  18 + @logger = Yup.logger.clone
  19 + @logger.progname = "Yup::State::RequestForwarder"
9 20
10   -module Yup
11   - class State
12   - RE_LEN = 1000
  21 + @yajl = Yajl::Parser.new(:symbolize_keys => true)
  22 + @yajl.on_parse_complete = self.method(:make_request)
  23 + end
13 24
14   - attr_reader :queue
  25 + def run_loop
  26 + loop do
  27 + data = @state.bpop
  28 + begin
  29 + @yajl << data
  30 + rescue Yajl::ParseError
  31 + @logger.error { "Error while parsing \"#{data}\"" }
  32 + end
  33 + end
  34 + end
15 35
16   - def self.repair_if_need(path)
17   - env = Bdb::Env.new(0)
18   - env.open(path, Bdb::DB_CREATE | Bdb::DB_INIT_TXN | Bdb::DB_RECOVER, 0)
19   - env.close()
20   - end
  36 + def make_request(req)
  37 + begin
  38 + @http_method, @request_url, headers, body = req
  39 + headers = Hash[*headers.to_a.flatten.map(&:to_s)]
  40 + headers["Host"] = @forward_to
  41 + headers["Connection"] = "Close"
21 42
22   - def initialize(path, name, feedback_channel)
23   - @path = path
24   - @name = name
25   - @feedback_channel = feedback_channel
  43 + req = "#{@http_method.upcase} #{@request_url} HTTP/1.1\r\n"
  44 + headers.each do |k, v|
  45 + req << "#{k}: #{v}\r\n"
  46 + end
  47 + req << "\r\n"
  48 + req << body if !body.empty?
  49 + raw_response = send_data(req.to_s, @forward_to)
26 50
27   - @logger = Yup.logger.clone
28   - @logger.progname = "Yup::State"
  51 + response_body = ""
  52 + http = Http::Parser.new()
  53 + http.on_body = proc do |chunk|
  54 + response_body << chunk
  55 + end
  56 + http << raw_response
29 57
30   - FileUtils.mkdir_p(@path)
31   - @env = Bdb::Env.new(0)
32   - @env = @env.open(@path, Bdb::DB_CREATE | Bdb::DB_INIT_MPOOL | Bdb::DB_INIT_CDB, 0)
33   - @queue = @env.db
34   - @queue.re_len = RE_LEN
35   - @queue.open(nil, @name, nil, Bdb::Db::QUEUE, Bdb::DB_CREATE, 0)
36   - end
  58 + if http.status_code && http.status_code / 100 == 2
  59 + log_response(raw_response, response_body, http)
  60 + @logger.info "Success"
  61 + else
  62 + log_response(raw_response, response_body, http)
  63 + if Yup.retry_unless_2xx
  64 + @logger.info "Fail: got status code #{http.status_code}; will retry after #{Yup.resend_delay} seconds"
  65 + @state.pushback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
37 66
38   - def push(data)
39   - @logger.debug { "Push: #{data}" }
40   - i = 0
41   - until (chunk = data.slice(i, RE_LEN)).nil?
42   - @queue.put(nil, "", chunk, Bdb::DB_APPEND)
43   - i += @queue.re_len
  67 + sleep Yup.resend_delay
  68 + else
  69 + @logger.info "Fail; will not retry"
  70 + end
  71 + end
  72 +
  73 + rescue Exception, Timeout::Error => e
  74 + log_response(raw_response, response_body, http)
  75 + @logger.info "Error: #{e.class}: #{e.message}; will retry after #{Yup.resend_delay} seconds"
  76 +
  77 + @state.pushback(Yajl::Encoder.encode([@http_method.downcase, @request_url, headers, body]))
  78 +
  79 + sleep Yup.resend_delay
  80 + end
44 81 end
45   - end
46 82
47   - def bpop
48   - data = @queue.get(nil, "", nil, Bdb::DB_CONSUME_WAIT)
49   - @logger.debug { "Bpoped: #{data.strip}" }
50   - data
51   - end
  83 + private
  84 + def log_response(raw_response, body, http)
  85 + @logger.info { "HTTP request: #{@http_method.upcase} #{@request_url} HTTP/1.1" }
  86 + if raw_response && !raw_response.empty?
  87 + @logger.info { "HTTP response: #{raw_response.lines.first.chomp}" }
  88 + @logger.debug { "HTTP response headers" + (http.headers.empty? ? " is empty" : "\n" + http.headers.inspect) }
  89 + @logger.debug { "HTTP response body" + (body.empty? ? " is empty" : "\n" + body.inspect) }
  90 + end
  91 + end
52 92
53   - def to_feedback(data)
54   - @logger.debug { "Push to the feedback channel: #{data.strip}" }
55   - sock = UNIXSocket.new(@feedback_channel)
56   - sock.send(data, 0)
57   - sock.close
58   - end
  93 + def send_data(data, host)
  94 + host, port = host.split(":")
  95 + addr = Socket.getaddrinfo(host, nil)
  96 + sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
59 97
60   - def close
61   - @queue.close(0)
  98 + secs = Integer(@timeout)
  99 + usecs = Integer((@timeout - secs) * 1_000_000)
  100 + optval = [secs, usecs].pack("l_2")
  101 + sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval)
  102 + sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval)
  103 +
  104 + resp = Timeout::timeout(@timeout) do
  105 + sock.connect(Socket.pack_sockaddr_in(port, addr[0][3]))
  106 + sock.write(data)
  107 + sock.read()
  108 + end
  109 + return resp
  110 + ensure
  111 + sock.close()
  112 + end
62 113 end
63 114 end
64 115 end
63 test/helper.rb
@@ -28,7 +28,68 @@ def format(result)
28 28 $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
29 29 require 'yup'
30 30
31   -class MiniTest::Unit::TestCase
  31 +class YupTestCase < MiniTest::Unit::TestCase
  32 + def after_setup
  33 + Service.attempts = 0
  34 + super
  35 + end
  36 +
  37 + class Service < EM::Connection
  38 + @@attempts = 0
  39 + def self.attempts; @@attempts end
  40 + def self.attempts=(n); @@attempts = n end
  41 +
  42 + def post_init
  43 + @parser = Http::Parser.new(self)
  44 + end
  45 +
  46 + def receive_data(data)
  47 + @parser << data
  48 + end
  49 +
  50 + def on_message_complete
  51 + $service_parser = @parser
  52 +
  53 + case @@attempts
  54 + when 0
  55 + when 1
  56 + send_data "HTTP/1.1 400 Bad Request\r\nServer: test\r\n\r\n"
  57 + close_connection_after_writing
  58 + when 2
  59 + send_data "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n"
  60 + close_connection_after_writing
  61 + end
  62 +
  63 + @@attempts += 1
  64 + end
  65 +
  66 + def unbind
  67 + if @@attempts > 2
  68 + EM.add_timer(1) do
  69 + Process.kill("KILL", $pid)
  70 + EM.stop_event_loop()
  71 + end
  72 + end
  73 + end
  74 + end
  75 +
  76 + module Client
  77 + def connection_completed
  78 + send_data("GET /foo HTTP/1.0\r\n\r\n")
  79 + end
  80 +
  81 + def post_init
  82 + @parser = Http::Parser.new(self)
  83 + end
  84 +
  85 + def receive_data(data)
  86 + @parser << data
  87 + end
  88 +
  89 + def on_message_complete
  90 + $client_parser = @parser
  91 + end
  92 + end
32 93 end
33 94
34 95 MiniTest::Unit.autorun
105 test/test_persistence_yup.rb
... ... @@ -1,105 +0,0 @@
1   -require 'helper'
2   -
3   -require 'tmpdir'
4   -require 'fileutils'
5   -require 'yup/state'
6   -
7   -class Yup::State::FeedbackHandler
8   - alias :on_message_original :on_message
9   - def on_message(req)
10   - on_message_original(req)
11   - $attempts += 1
12   - end
13   -end
14   -
15   -class TestPersistenceYup < MiniTest::Unit::TestCase
16   - class RequestHandlerMock < Yup::RequestHandler
17   - end
18   -
19   - class Service < EM::Connection
20   - def post_init
21   - @parser = Http::Parser.new(self)
22   - end
23   -
24   - def receive_data(data)
25   - @parser << data
26   - end
27   -
28   - def on_message_complete
29   - $service_parser = @parser
30   -
31   - case $attempts
32   - when 0
33   - when 1
34   - send_data "HTTP/1.1 400 Bad Request\r\nServer: test\r\n\r\n"
35   - close_connection_after_writing
36   - when 2
37   - send_data "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n"
38   - close_connection_after_writing
39   - end
40   - end
41   -
42   - def unbind
43   - if $attempts >= 2
44   - EM.add_timer(1) do
45   - Process.kill("KILL", $pid)
46   - EM.stop_event_loop()
47   - end
48   - end
49   - end
50   - end
51   -
52   - module Client
53   - def connection_completed
54   - send_data("GET /foo HTTP/1.0\r\n\r\n")
55   - end
56   -
57   - def post_init
58   - @parser = Http::Parser.new(self)
59   - end
60   -
61   - def receive_data(data)
62   - @parser << data
63   - end
64   -
65   - def on_message_complete
66   - $client_parser = @parser
67   - end
68   - end
69   -
70   - def test_request_handler
71   - $attempts = 0
72   -
73   - dbpath = Dir.mktmpdir("yupd-db")
74   - feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
75   -
76   - forward_to = "127.0.0.1:26785"
77   - status_code = 200
78   - state = Yup::State.new(dbpath, forward_to, feedback_channel)
79   - timeout = 1
80   -
81   - Yup.resend_delay = 1
82   - Yup.retry_unless_2xx = true
83   -
84   - $pid = Process.fork do
85   - Yup::State::RequestForwarder.new(state, forward_to, timeout).run_loop
86   - end
87   -
88   - EM.run {
89   - EM.start_server("127.0.0.1", 26785, Service)
90   - EM.start_unix_domain_server(feedback_channel, Yup::State::FeedbackHandler, state)
91   - EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
92   - EM.connect("127.0.0.1", 26784, Client)
93   - }
94   -
95   - assert $client_parser
96   - assert_equal 200, $client_parser.status_code
97   - assert_equal "yupd", $client_parser.headers["Server"]
98   - assert $service_parser
99   - assert_equal "/foo", $service_parser.request_url
100   - ensure
101   - Process.kill("KILL", $pid) if $pid
102   - state.close if state
103   - FileUtils.remove_entry_secure(dbpath) if dbpath
104   - end
105   -end
47 test/test_stateful_yup_with_bdb.rb
... ... @@ -0,0 +1,47 @@
  1 +require 'helper'
  2 +
  3 +require 'tmpdir'
  4 +require 'fileutils'
  5 +require 'yup/state/bdb'
  6 +
  7 +class TestStatefulYupWithBDB < YupTestCase
  8 + class RequestHandlerMock < Yup::RequestHandler
  9 + end
  10 +
  11 + def test_request_handler
  12 + Service.attempts = 0
  13 +
  14 + dbpath = Dir.mktmpdir("yupd-db")
  15 + uri = "bdb://#{dbpath}"
  16 + feedback_channel = File.join(Dir.tmpdir, "yupd-#{$$}-feedback")
  17 + forward_to = "127.0.0.1:26785"
  18 + status_code = 200
  19 + state = Yup::State::BDB.new(uri, forward_to, feedback_channel)
  20 + timeout = 1
  21 +
  22 + Yup.resend_delay = 1
  23 + Yup.retry_unless_2xx = true
  24 +
  25 + $pid = Process.fork do
  26 + Yup::State::BDB::RequestForwarder.new(state, forward_to, timeout).run_loop
  27 + end
  28 +
  29 + EM.run {
  30 + EM.start_server("127.0.0.1", 26785, Service)
  31 + EM.start_unix_domain_server(feedback_channel, Yup::State::BDB::FeedbackHandler, state)
  32 + EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
  33 + EM.connect("127.0.0.1", 26784, Client)
  34 + }
  35 +
  36 + assert $client_parser
  37 + assert_equal 200, $client_parser.status_code
  38 + assert_equal "yupd", $client_parser.headers["Server"]
  39 + assert $service_parser
  40 + assert_equal "/foo", $service_parser.request_url
  41 + assert_equal 3, Service.attempts
  42 + ensure
  43 + Process.kill("KILL", $pid) if $pid
  44 + state.dispose() if state
  45 + FileUtils.remove_entry_secure(dbpath) if dbpath
  46 + end
  47 +end
41 test/test_stateful_yup_with_redis.rb
... ... @@ -0,0 +1,41 @@
  1 +require 'helper'
  2 +
  3 +require 'tmpdir'
  4 +require 'fileutils'
  5 +require 'yup/state/redis'
  6 +
  7 +class TestStatefulYupWithRedis < YupTestCase
  8 + class RequestHandlerMock < Yup::RequestHandler
  9 + end
  10 +
  11 + def test_request_handler
  12 + uri = "redis://localhost/yup-testing-#{Time.now.to_f}"
  13 + forward_to = "127.0.0.1:26785"
  14 + status_code = 200
  15 + state = Yup::State::Redis.new(uri, forward_to)
  16 + timeout = 1
  17 +
  18 + Yup.resend_delay = 1
  19 + Yup.retry_unless_2xx = true
  20 +
  21 + $pid = Process.fork do
  22 + Yup::State::Redis::RequestForwarder.new(state, forward_to, timeout).run_loop
  23 + end
  24 +
  25 + EM.run {
  26 + EM.start_server("127.0.0.1", 26785, Service)
  27 + EM.start_server("127.0.0.1", 26784, RequestHandlerMock, forward_to, status_code, state, timeout)
  28 + EM.connect("127.0.0.1", 26784, Client)
  29 + }
  30 +
  31 + assert $client_parser
  32 + assert_equal 200, $client_parser.status_code
  33 + assert_equal "yupd", $client_parser.headers["Server"]
  34 + assert $service_parser
  35 + assert_equal "/foo", $service_parser.request_url
  36 + assert_equal 3, Service.attempts
  37 + ensure
  38 + Process.kill("KILL", $pid) if $pid
  39 + state.dispose() if state
  40 + end
  41 +end

No commit comments for this range

Something went wrong with that request. Please try again.