File: tcp_server_spec.rb

package info (click to toggle)
ruby-cool.io 1.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 716 kB
  • sloc: ansic: 6,851; ruby: 1,730; makefile: 6
file content (225 lines) | stat: -rw-r--r-- 4,853 bytes parent folder | download | duplicates (3)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
require File.expand_path('../spec_helper', __FILE__)

TIMEOUT = 0.010
HOST = '127.0.0.1'
PORT = unused_port

def send_data(data)
  io = TCPSocket.new('127.0.0.1', PORT)
  begin
    io.write data
  ensure
    io.close
  end
end

class MyConnection < Coolio::Socket
  attr_accessor :data, :connected, :closed

  def initialize(io, on_message)
    super(io)
    @on_message = on_message
  end

  def on_connect
    @connected = true
  end

  def on_close
    @closed = true
  end

  def on_read(data)
    @on_message.call(data)
  end
end

@data = ""
def on_message(data)
  @data = data
end

def test_run(data = nil)
  reactor = Coolio::Loop.new
  server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
  reactor.attach(server)
  thread = Thread.new { reactor.run }
  send_data(data) if data
  sleep TIMEOUT
  reactor.stop
  server.detach
  send_data('') # to leave from blocking loop
  thread.join
  @data
ensure
  server.close
end

def test_run_once(data = nil)
  reactor = Coolio::Loop.new
  server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
  reactor.attach(server)
  thread = Thread.new do
    reactor.run_once # on_connect
    reactor.run_once # on_read
  end
  send_data(data) if data
  thread.join
  server.detach
  @data
ensure
  server.close
end

def test_run_once_timeout(timeout = TIMEOUT)
  @data = ""
  reactor = Coolio::Loop.new
  server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
  reactor.attach(server)
  thread = Thread.new { reactor.run_once(timeout) }
  sleep timeout
  server.detach
  thread.join
  @data
ensure
  server.close
end

def test_run_timeout(data = nil, timeout = TIMEOUT)
  reactor = Coolio::Loop.new
  server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
  reactor.attach(server)
  running = true
  thread = Thread.new do
    while running and reactor.has_active_watchers?
      reactor.run_once(timeout)
    end
  end
  send_data(data) if data
  sleep timeout
  server.detach
  running = false # another send is not required
  thread.join
  @data
ensure
  server.close
end

# This test should work on Windows
describe Coolio::TCPServer do

  it '#run' do
    expect(test_run("hello")).to eq("hello")
  end

  it '#run_once' do
    expect(test_run_once("hello")).to eq("hello")
  end

  it '#run_once(timeout)' do
    test_run_once_timeout # should not block
  end

  it '#run_once(-timeout)' do
    expect { test_run_once_timeout(-0.1) }.to raise_error(ArgumentError)
  end

  it '#run(timeout)' do
    expect(test_run_timeout("hello")).to eq("hello")
  end

  describe "functionaltest" do
    let :loop do
      Coolio::Loop.new
    end
    
    let :port do
      unused_port
    end
    
    context "#on_connect" do
      class ServerOnConnect < Coolio::Socket
        def initialize(io, cb)
          super(io)
          @cb = cb
        end
        def on_connect
          @cb.call
        end
      end
      
      it "connected socket called on_connect" do
        begin
          connected = false
          server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { connected = true })
          loop.attach server
          s = TCPSocket.open("localhost", port)
          loop.run_once
          s.close
          expect(connected).to eq true
        ensure
          server.detach
        end
      end
    end
    
    context "#on_close" do
      class ServerOnClose < Coolio::Socket
        def initialize(io, cb)
          super(io)
          @cb = cb
        end
        def on_close
          @cb.call
        end
      end
      
      it "closed socket called on_close" do
        begin
          closed = false
          server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { closed = true })
          loop.attach server
          s = TCPSocket.open("localhost", port)
          loop.run_once
          s.close
          loop.run_once
          expect(closed).to eq true
        ensure
          server.detach
        end
      end
    end
    
    context "#on_read" do
      class Echo < Coolio::Socket
        def initialize(io, cb)
          super(io)
          @cb = cb
        end
        def on_read(data)
          @cb.call data
          _size = write(data + "fff")
        end
      end
      
      it "server socket received data" do
        begin
          data = "aaa"
          server = Cool.io::TCPServer.new("localhost", port, Echo, proc { |d| data = d })
          loop.attach server
          thread = Thread.new { loop.run }
          s = TCPSocket.open("localhost", port)
          s.write "zzz"
          sleep 0.1
          expect(data).to eq "zzz"
          expect(s.read 6).to eq "zzzfff"
        ensure
          s.close
          loop.stop
          server.detach
          thread.join
        end
      end
    end
  end
end