3 # Author:: Francis Cianfrocca (gmail: blackhedd)
4 # Homepage:: http://rubyeventmachine.com
7 # See EventMachine and EventMachine::Connection for documentation and
10 #----------------------------------------------------------------------------
12 # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 # This program is free software; you can redistribute it and/or modify
16 # it under the terms of either: 1) the GNU General Public License
17 # as published by the Free Software Foundation; either version 2 of the
18 # License, or (at your option) any later version; or 2) Ruby's License.
20 # See the file COPYING for complete licensing information.
22 #---------------------------------------------------------------------------
27 $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
28 require 'eventmachine'
32 class TestBasic < Test::Unit::TestCase
35 assert(!EM.reactor_running?)
39 assert(!EM.reactor_running?)
42 #-------------------------------------
45 lt = EventMachine.library_type
46 em_lib = (ENV["EVENTMACHINE_LIBRARY"] || $eventmachine_library || :xxx).to_sym
48 # Running from test runner, under jruby.
49 if RUBY_PLATFORM == 'java'
50 unless em_lib == :pure_ruby
51 assert_equal( :java, lt )
58 assert_equal( :pure_ruby, lt )
60 assert_equal( :extension, lt )
62 assert_equal( :java, lt )
64 # Running from jruby as a standalone test.
65 if RUBY_PLATFORM == 'java'
66 assert_equal( :java, lt )
68 assert_equal( :extension, lt )
73 #-------------------------------------
78 EventMachine.add_timer 0 do
84 #-------------------------------------
89 EventMachine.add_periodic_timer(0.1) {
91 EventMachine.stop if n == 2
96 #-------------------------------------
98 # This test once threw an already-running exception.
107 EventMachine.start_server "localhost", 9000, Trivial
108 EventMachine.connect "localhost", 9000
110 assert( true ) # make sure it halts
113 #--------------------------------------
115 # EventMachine#run_block starts the reactor loop, runs the supplied block, and then STOPS
116 # the loop automatically. Contrast with EventMachine#run, which keeps running the reactor
117 # even after the supplied block completes.
119 assert !EM.reactor_running?
121 EM.run_block { a = "Worked" }
123 assert !EM.reactor_running?
127 #--------------------------------------
129 # TODO! This is an unfinished edge case.
130 # EM mishandles uncaught Ruby exceptions that fire from within #unbind handlers.
131 # A uncaught Ruby exception results in a call to EM::release_machine (which is in an ensure
132 # block in EM::run). But if EM is processing an unbind request, the release_machine call
133 # will cause a segmentation fault.
136 TestHost = "127.0.0.1"
139 class UnbindError < EM::Connection
143 def connection_completed
144 close_connection_after_writing
151 def xxx_test_unbind_error
152 assert_raises( RuntimeError ) {
154 EM.start_server TestHost, TestPort
155 EM.connect TestHost, TestPort, UnbindError
160 #------------------------------------
162 # TODO. This is an unfinished bug fix.
163 # This case was originally reported by Dan Aquino. If you throw a Ruby exception
164 # in a post_init handler, it gets rethrown as a confusing reactor exception.
165 # The problem is in eventmachine.rb, which calls post_init within the private
166 # initialize method of the EM::Connection class. This happens in both the EM::connect
167 # method and in the code that responds to connection-accepted events.
168 # What happens is that we instantiate the new connection object, which calls
169 # initialize, and then after initialize returns, we stick the new connection object
170 # into EM's @conns hashtable.
171 # But the problem is that Connection::initialize calls #post_init before it returns,
172 # and this may be user-written code that may throw an uncaught Ruby exception.
173 # If that happens, the reactor will abort, and it will then try to run down open
174 # connections. Because @conns never got a chance to properly reflect the new connection
175 # (because initialize never returned), we throw a ConnectionNotBound error
176 # (eventmachine.rb line 1080).
177 # When the bug is fixed, activate this test case.
180 class PostInitError < EM::Connection
182 aaa bbb # should produce a Ruby exception
185 # This test causes issues, the machine becomes unreleasable after
186 # release_machine suffers an exception in event_callback.
187 def xxx_test_post_init_error
188 assert_raises( EventMachine::ConnectionNotBound ) {
190 EM::Timer.new(1) {EM.stop}
191 EM.start_server TestHost, TestPort
192 EM.connect TestHost, TestPort, PostInitError
198 assert !EM.reactor_running?
202 def receive_data data
212 close_connection_after_writing
217 def test_byte_range_send
219 $sent = (0..255).to_a.pack('C*')
221 EM::start_server TestHost, TestPort, BrsTestSrv
222 EM::connect TestHost, TestPort, BrsTestCli
224 EM::add_timer(0.5) { assert(false, 'test timed out'); EM.stop; Kernel.warn "test timed out!" }
226 assert_equal($sent, $received)
229 def test_bind_connect
230 local_ip = UDPSocket.open {|s| s.connect('google.com', 80); s.addr.last }
232 bind_port = rand(33333)+1025
236 EM.start_server(TestHost, TestPort, Module.new do
237 define_method :post_init do
239 test.assert_equal bind_port, Socket.unpack_sockaddr_in(get_peername).first
240 test.assert_equal local_ip, Socket.unpack_sockaddr_in(get_peername).last
246 EM.bind_connect local_ip, bind_port, TestHost, TestPort
250 def test_reactor_thread?
251 assert !EM.reactor_thread?
252 EM.run { assert EM.reactor_thread?; EM.stop }
253 assert !EM.reactor_thread?
256 def test_schedule_on_reactor_thread
259 EM.schedule { x = true }
265 def test_schedule_from_thread
269 Thread.new { EM.schedule { x = true; EM.stop } }.join
274 def test_set_heartbeat_interval
277 EM.set_heartbeat_interval interval
278 $interval = EM.get_heartbeat_interval
281 assert_equal(interval, $interval)