summaryrefslogtreecommitdiff
path: root/test/webrick/test_server.rb
blob: 37b1dd50cad3dabe3965d765106aa6136084baf2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require "test/unit"
require "tempfile"
require "webrick"
require_relative "utils"

class TestWEBrickServer < Test::Unit::TestCase
  class Echo < WEBrick::GenericServer
    def run(sock)
      while line = sock.gets
        sock << line
      end
    end
  end

  def test_server
    TestWEBrick.start_server(Echo){|server, addr, port, log|
      TCPSocket.open(addr, port){|sock|
        sock.puts("foo"); assert_equal("foo\n", sock.gets, log.call)
        sock.puts("bar"); assert_equal("bar\n", sock.gets, log.call)
        sock.puts("baz"); assert_equal("baz\n", sock.gets, log.call)
        sock.puts("qux"); assert_equal("qux\n", sock.gets, log.call)
      }
    }
  end

  def test_start_exception
    stopped = 0

    log = []
    logger = WEBrick::Log.new(log, WEBrick::BasicLog::WARN)

    assert_raise(SignalException) do
      listener = Object.new
      def listener.to_io # IO.select invokes #to_io.
        raise SignalException, 'SIGTERM' # simulate signal in main thread
      end
      def listener.shutdown
      end
      def listener.close
      end

      server = WEBrick::HTTPServer.new({
        :BindAddress => "127.0.0.1", :Port => 0,
        :StopCallback => Proc.new{ stopped += 1 },
        :Logger => logger,
      })
      server.listeners[0].close
      server.listeners[0] = listener

      server.start
    end

    assert_equal(1, stopped)
    assert_equal(1, log.length)
    assert_match(/FATAL SignalException: SIGTERM/, log[0])
  end

  def test_callbacks
    accepted = started = stopped = 0
    config = {
      :AcceptCallback => Proc.new{ accepted += 1 },
      :StartCallback => Proc.new{ started += 1 },
      :StopCallback => Proc.new{ stopped += 1 },
    }
    TestWEBrick.start_server(Echo, config){|server, addr, port, log|
      true while server.status != :Running
      assert_equal(1, started, log.call)
      assert_equal(0, stopped, log.call)
      assert_equal(0, accepted, log.call)
      TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets }
      TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets }
      TCPSocket.open(addr, port){|sock| (sock << "foo\n").gets }
      assert_equal(3, accepted, log.call)
    }
    assert_equal(1, started)
    assert_equal(1, stopped)
  end

  def test_daemon
    begin
      r, w = IO.pipe
      pid1 = Process.fork{
        r.close
        WEBrick::Daemon.start
        w.puts(Process.pid)
        sleep 10
      }
      pid2 = r.gets.to_i
      assert(Process.kill(:KILL, pid2))
      assert_not_equal(pid1, pid2)
    rescue NotImplementedError
      # snip this test
    ensure
      Process.wait(pid1) if pid1
      r.close
      w.close
    end
  end

  def test_restart_after_shutdown
    address = '127.0.0.1'
    port = 0
    log = []
    config = {
      :BindAddress => address,
      :Port => port,
      :Logger => WEBrick::Log.new(log, WEBrick::BasicLog::WARN),
    }
    server = Echo.new(config)
    client_proc = lambda {|str|
      begin
        ret = server.listeners.first.connect_address.connect {|s|
          s.write(str)
          s.close_write
          s.read
        }
        assert_equal(str, ret)
      ensure
        server.shutdown
      end
    }
    server_thread = Thread.new { server.start }
    client_thread = Thread.new { client_proc.call("a") }
    assert_join_threads([client_thread, server_thread])
    server.listen(address, port)
    server_thread = Thread.new { server.start }
    client_thread = Thread.new { client_proc.call("b") }
    assert_join_threads([client_thread, server_thread])
    assert_equal([], log)
  end

  def test_restart_after_stop
    log = Object.new
    class << log
      include Test::Unit::Assertions
      def <<(msg)
        flunk "unexpected log: #{msg.inspect}"
      end
    end
    warn_flunk = WEBrick::Log.new(log, WEBrick::BasicLog::WARN)
    server = WEBrick::HTTPServer.new(
      :BindAddress => '0.0.0.0',
      :Port => 0,
      :Logger => warn_flunk)
    2.times {
      server_thread = Thread.start {
        server.start
      }
      client_thread = Thread.start {
        sleep 0.1 until server.status == :Running || !server_thread.status
        server.stop
        sleep 0.1 until server.status == :Stop || !server_thread.status
      }
      assert_join_threads([client_thread, server_thread])
    }
  end
end