faefbfed20870c6b513cef772e694ebdec6b6f1c
[urisagit/Stem.git] / t / event / event_test.pl
1 #!/usr/local/bin/perl -w
2
3 BEGIN {
4         $Stem::Vars::Env{ 'event_loop' } = shift ;
5
6         unless ( eval { require Time::HiRes } ) {
7
8                 Time::HiRes->import( qw( time ) ) ;
9         }
10 }
11
12 use strict ;
13
14 use Test::More tests => 27 ;
15
16 use Symbol ;
17
18 use Stem::Event ;
19 use Stem::Class ;
20
21 my $self = bless {} ;
22
23 test_events() ;
24
25 exit ;
26
27 sub test_events {
28
29         test_null_events() ;
30         test_plain_events () ;
31         test_signal_events () ;
32         test_hard_timer_events () ;
33         test_soft_timer_events () ;
34         test_io_events () ;
35 }
36
37 sub test_null_events {
38
39         local $SIG{__WARN__} = sub{} if
40                         $Stem::Vars::Env{ 'event_loop' } eq 'event' ;
41
42         Stem::Event::start_loop() ;
43
44         ok( 1, 'null - event loop exit' ) ;
45 }
46
47 sub test_plain_events {
48
49         my $event = Stem::Event::Plain->new(
50                 'object' => $self
51         ) ;
52
53         ok( ref $event, 'plain event created' ) ;
54
55         Stem::Event::start_loop() ;
56
57         ok( 1, 'plain - event loop exit' ) ;
58 }
59
60 # callback method for plain
61
62 sub triggered {
63
64         my( $self ) = @_ ;
65
66         ok( 1, 'plain event triggered' ) ;
67         Stem::Event::stop_loop() ;
68 }
69
70 sub test_signal_events {
71
72         SKIP: {
73                 if ( $^O =~ /win32/i ) {
74
75                         skip( "signals not supported on windows", 3 ) ;
76                         return ;
77                 }
78
79                 my $event2 = Stem::Event::Timer->new(
80                         'object'        => $self,
81                         'method'        => 'send_int_signal',
82                         'delay'         => 3,
83                 ) ;
84
85                 ok( ref $event2, 'signal delay timer created' ) ;
86
87                 Stem::Event::start_loop() ;
88
89                 ok( 1, 'signal - event loop exit' ) ;
90         }
91 }
92
93 sub send_int_signal {
94
95                 my $event = Stem::Event::Signal->new(
96                         'object'        => $self,
97                         'signal'        => 'INT',
98                 ) ;
99
100                 ok( ref $event, 'signal event created' ) ;
101
102                 $self->{'sig_event'} = $event ;
103
104
105 print "kill INT\n" ;
106
107         kill 'INT', $$ ;
108 }
109
110 # callback method for signal
111
112 sub sig_int_handler {
113
114         my( $self ) = @_ ;
115
116         ok( 1, 'signal event triggered' ) ;
117
118         $self->{'sig_event'}->cancel() ;
119         Stem::Event::stop_loop() ;
120 }
121
122
123 use constant INTERVAL   => 4 ;
124 use constant SLEEP      => 2 ;
125 use constant TIMER_CNT  => 2 ;
126
127 # hard timeouts are timed from the beginning of the callback. so accumulated
128 # time in the callback doesn't affect the next callback.
129
130 sub test_hard_timer_events {
131
132         my $event = Stem::Event::Timer->new(
133                 'object'        => $self,
134                 'method'        => 'hard_timeout',
135                 'interval'      => INTERVAL,
136                 'delay'         => INTERVAL,    # REMOVE - only for .10
137                 'repeat'        => 1,
138                 'hard'          => 1,
139         ) ;
140
141         ok( ref $event, 'hard timer event created' ) ;
142         print "$event\n" unless ref $event ;
143
144         $self->{'hard_timer_event'} = $event ;
145         $self->{'hard_timer_count'} = TIMER_CNT ;
146         $self->{'hard_timer_start_time'} = time ;
147
148         Stem::Event::start_loop() ;
149
150         ok( 1, 'hard timer - event loop exit' ) ;
151 }
152
153 sub hard_timeout {
154
155         my( $self ) = @_ ;
156
157 send_int_signal() ;
158
159         ok( 1, 'hard timer event triggered' ) ;
160
161         if ( --$self->{'hard_timer_count'} > 0 ) {
162
163                 my $time = time ;
164                 my $delta = $time - $self->{'hard_timer_start_time'} ;
165                 $self->{'hard_timer_start_time'} = $time ;
166
167                 ok( $delta >= INTERVAL, 'hard delta' ) ;
168
169                 hard_sleep( SLEEP ) ;
170
171                 return ;
172         }
173
174         
175         my $time = time ;
176         my $delta = $time - $self->{'hard_timer_start_time'} ;
177
178 #print "O $self->{'hard_timer_start_time'} T $time D $delta I ", INTERVAL, "\n" ;
179
180         ok( $delta >= INTERVAL, 'hard delta 2' ) ;
181         ok( $delta <= INTERVAL + SLEEP, 'hard delta sleep' ) ;
182
183         $self->{'hard_timer_event'}->cancel() ;
184
185         Stem::Event::stop_loop() ;
186 }
187
188
189 # Soft timeouts are timed from the end of the callback. so accumulated
190 # time in the callback delays the next callback.
191
192 sub test_soft_timer_events {
193
194         my $event = Stem::Event::Timer->new(
195                 'object'        => $self,
196                 'method'        => 'soft_timeout',
197                 'interval'      => INTERVAL,
198                 'delay'         => INTERVAL,    # REMOVE  - only for .10
199                 'repeat'        => 1,
200         ) ;
201
202         ok( ref $event, 'soft timer event created' ) ;
203 #       print "$event\n" unless ref $event ;
204
205         $self->{'soft_timer_event'} = $event ;
206         $self->{'soft_timer_count'} = TIMER_CNT ;
207         $self->{'soft_timer_start_time'} = time ;
208
209 #print "OTIME $self->{'soft_timer_start_time'}\n" ;
210
211         Stem::Event::start_loop() ;
212
213         ok( 1, 'soft timer - event loop exit' ) ;
214 }
215
216 sub soft_timeout {
217
218         my( $self ) = @_ ;
219
220         ok( 1, 'soft timer event triggered' ) ;
221
222         if ( --$self->{'soft_timer_count'} > 0 ) {
223
224                 my $time = time ;
225                 my $delta = $time - $self->{'soft_timer_start_time'} ;
226
227 #print "T $time D $delta I ", INTERVAL, "\n" ;
228
229                 ok( $delta >= INTERVAL, 'soft delta' ) ;
230
231                 hard_sleep( SLEEP ) ;
232
233 #my $curr_time = time() ;
234 #print "DONE $curr_time\n" ;
235
236                 return ;
237         }
238
239         my $time = time ;
240         my $delta = $time - $self->{'soft_timer_start_time'} ;
241
242 #print "TIME2 $time OTIME $self->{'soft_timer_start_time'} DEL $delta INTERVAL ", INTERVAL, "\n" ;
243
244 #       ok( $delta >= INTERVAL, 'soft delta 2' ) ;
245         ok( $delta >= INTERVAL + SLEEP, 'soft delta 3' ) ;
246
247         $self->{'soft_timer_event'}->cancel() ;
248
249         Stem::Event::stop_loop() ;
250 }
251
252 sub test_io_events {
253
254         Stem::Event::init_loop() ;
255
256         my $read_fh = gensym ;
257         my $write_fh = gensym ;
258
259 # get a pipe to read/write through.
260
261         use Socket;
262         socketpair( $read_fh, $write_fh, AF_UNIX, SOCK_STREAM, PF_UNSPEC ) ;
263
264         $self->{read_fh} = $read_fh ;
265         $self->{write_fh} = $write_fh ;
266         $self->{message} = 'Stem Read/Write Event' ;
267
268         # create the read and write events
269
270         my $read_event = Stem::Event::Read->new(
271                                 'object'        =>      $self,
272                                 'fh'            =>      $read_fh,
273                                 'timeout'       =>      3,
274         ) ;
275
276         ok( ref $read_event, 'read event created' ) ;
277         $self->{'read_event'} = $read_event ;
278
279         my $write_event = Stem::Event::Write->new(
280                                 'object'        =>      $self,
281                                 'fh'            =>      $write_fh,
282         ) ;
283
284         ok( ref $write_event, 'write event created' ) ;
285         $self->{'write_event'} = $write_event ;
286
287         Stem::Event::start_loop() ;
288
289         ok( 1, 'io - event loop exit' ) ;
290 }
291
292 sub read_timeout {
293
294         my( $self ) = @_ ;
295
296         ok( 1, 'read event timed out' ) ;
297
298         $self->{'write_event'}->start() ;
299 }
300
301
302 sub writeable {
303
304         my( $self ) = @_ ;
305
306         ok( 1, 'write event triggered' ) ;
307
308         syswrite( $self->{'write_fh'}, $self->{'message'} ) ;
309
310         $self->{'write_event'}->cancel() ;
311 }
312
313 sub readable {
314
315         my( $self ) = @_ ;
316
317         ok(1, 'read event triggered' ) ;
318
319         my( $read_buf ) ;
320
321         my $bytes_read = sysread( $self->{'read_fh'}, $read_buf, 1000 ) ;
322
323         ok( $bytes_read, 'read byte count' ) ;
324
325         is( $read_buf, $self->{'message'}, 'read event compare' ) ;
326
327         $self->{'read_event'}->cancel() ;
328
329         Stem::Event::stop_loop() ;
330 }
331
332 # do a real hard sleep without alarm signal as that can screw up the tests
333 # sleep time is in (float) seconds
334
335 sub hard_sleep {
336
337         my( $sleep_time ) = @_ ;
338
339 #print "BEFORE TIME $sleep_time\n" ;
340         while( $sleep_time > 0 ) {
341
342                 my $curr_time = time() ;
343                 select( undef, undef, undef, $sleep_time ) ;
344
345                 $sleep_time -= time() - $curr_time ;
346
347 #print "AFTER TIME $sleep_time\n" ;
348         }
349 }
350
351 1 ;