File: signals.pm

package info (click to toggle)
libpoe-perl 2%3A1.3670-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,996 kB
  • ctags: 1,416
  • sloc: perl: 22,865; makefile: 9
file content (372 lines) | stat: -rw-r--r-- 10,672 bytes parent folder | download | duplicates (7)
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# vim: ts=2 sw=2 expandtab
use strict;

use lib qw(./mylib ../mylib);
use Test::More tests => 46;

sub POE::Kernel::ASSERT_DEFAULT () { 1 }

BEGIN {
  package POE::Kernel;
  use constant TRACE_DEFAULT => exists($INC{'Devel/Cover.pm'});
}

BEGIN { use_ok("POE") }

# Verify that we have safe signals.
#
# We only verify that at least one signal is "safe".  Matching a
# larger set is HARD because the set of supported signals probably
# varies like crazy.

{ my @safe_signals = $poe_kernel->_data_sig_get_safe_signals();
  ok( grep(/^INT$/, @safe_signals), "at least SIGINT is available" );
}

# What happens if signals are initialized more than once?

$poe_kernel->_data_sig_initialize();

# Create some sessions for testing.

sub create_session {
  my $session = bless [ ], "POE::Session";
  my $sid     = $poe_kernel->_data_sid_allocate();

  $session->_set_id($sid);
  $poe_kernel->_data_ses_allocate(
    $session,         # session
    $sid,             # sid
    $poe_kernel->ID,  # parent
  );

  return($session, $sid);
}


# Add some signals for testing.

my ($ses_1, $sid_1) = create_session();
$poe_kernel->_data_sig_add($ses_1, "signal-1", "event-1", [ 1, 2, 3 ]);
$poe_kernel->_data_sig_add($ses_1, "signal-2", "event-2", [ 4, 5, 6 ]);

my ($ses_2, $sid_2) = create_session();
$poe_kernel->_data_sig_add($ses_2, "signal-2", "event-3");

# Verify that the signals were added, and also that nonexistent signal
# watchers don't cause false positives in this test.

ok(
  $poe_kernel->_data_sig_explicitly_watched("signal-1"),
  "signal-1 is explicitly watched"
);

ok(
  $poe_kernel->_data_sig_explicitly_watched("signal-2"),
  "signal-2 is explicitly watched"
);

ok(
  !$poe_kernel->_data_sig_explicitly_watched("signal-0"),
  "signal-0 is not explicitly watched"
);

# More detailed checks.  Test that each signal is watched by its
# proper session.

ok(
  $poe_kernel->_data_sig_is_watched_by_session("signal-1", $ses_1->ID),
  "session 1 watches signal-1"
);

ok(
  $poe_kernel->_data_sig_is_watched_by_session("signal-2", $ses_1->ID),
  "session 1 watches signal-2"
);

ok(
  !$poe_kernel->_data_sig_is_watched_by_session("signal-1", $ses_2->ID),
  "session 2 does not watch signal-1"
);

# Make sure we can determine watchers for each signal.

# Single watcher test...
{ my %watchers = $poe_kernel->_data_sig_watchers("signal-1");
  ok(
    eq_hash(\%watchers, { $ses_1->ID => [ "event-1", [ 1, 2, 3 ], $ses_1 ] }),
    "signal-1 maps to session 1 and event-1"
  );
}

# Multiple watcher test...
{ my %watchers = $poe_kernel->_data_sig_watchers("signal-2");
  ok(
    eq_hash(
      \%watchers, {
        $ses_1->ID => [ "event-2", [ 4, 5, 6 ], $ses_1 ],
        $ses_2->ID => [ "event-3", [ ], $ses_2 ],
      }
    ),
    "signal-2 maps to session 1 and event-2; session 2 and event-3"
  );
}

# Remove one of the multiple signals, and verify that the remaining
# ones are correct.

$poe_kernel->_data_sig_remove($ses_1->ID, "signal-2");

# Single watcher test...

{ my %watchers = $poe_kernel->_data_sig_watchers("signal-1");
  ok(
    eq_hash(\%watchers, { $ses_1->ID => [ "event-1", [ 1, 2, 3 ], $ses_1 ] }),
    "signal-1 still maps to session 1 and event-1"
  );
}

# Multiple watcher test...

{ my %watchers = $poe_kernel->_data_sig_watchers("signal-2");
  ok(
    eq_hash(\%watchers, { $ses_2->ID => [ "event-3", [ ], $ses_2 ] }),
    "signal-2 still maps to session 2 and event-3"
  );
}

# Ad some more signals for one of the sessions, then clear all the
# signals for that session.  Verify that they're all added and cleaned
# up correctly.

$poe_kernel->_data_sig_add($ses_1, "signal-3", "event-3");
$poe_kernel->_data_sig_add($ses_1, "signal-4", "event-3");
$poe_kernel->_data_sig_add($ses_1, "signal-5", "event-3");
$poe_kernel->_data_sig_add($ses_1, "signal-6", "event-3");

{ my %watchers = $poe_kernel->_data_sig_watched_by_session($ses_1->ID);
  ok(
    eq_hash(
      \%watchers,
      { "signal-1", [ "event-1", [ 1, 2, 3 ], $ses_1 ],
        "signal-3", [ "event-3", [ ], $ses_1 ],
        "signal-4", [ "event-3", [ ], $ses_1 ],
        "signal-5", [ "event-3", [ ], $ses_1 ],
        "signal-6", [ "event-3", [ ], $ses_1 ],
      }
    ),
    "several signal watchers were added correctly"
  );
}

$poe_kernel->_data_sig_clear_session($ses_1->ID);

{ my %watchers = $poe_kernel->_data_sig_watchers("signal-2");
  ok(
    eq_hash(\%watchers, { $ses_2->ID => [ "event-3", [ ], $ses_2 ] }),
    "cleared session isn't watching signal-2"
  );
}

# Check signal types.

ok(
  $poe_kernel->_data_sig_type("QUIT") == POE::Kernel::SIGTYPE_TERMINAL,
  "SIGQUIT is terminal"
);

ok(
  $poe_kernel->_data_sig_type("nonexistent") == POE::Kernel::SIGTYPE_BENIGN,
  "nonexistent signal is benign"
);

# Test the signal handling flag things.

$poe_kernel->_data_sig_reset_handled("QUIT");

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok(!defined($tot), "SIGQUIT handled by zero sessions");
  ok($type == POE::Kernel::SIGTYPE_TERMINAL, "SIGQUIT is terminal");
  ok( eq_array($ses, []), "no sessions touched by SIGQUIT" );
}

# Touch a session with the signal.

$poe_kernel->_data_sig_touched_session($ses_2);

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok(!defined($tot), "SIGQUIT handled by zero sessions");
  ok($type == POE::Kernel::SIGTYPE_TERMINAL, "SIGQUIT is terminal");
  ok( eq_array($ses, [ $ses_2 ]), "SIGQUIT touched correct session" );
}

$poe_kernel->_data_sig_handled();

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok($tot == 1, "SIGQUIT handled by one session");
  ok($type == POE::Kernel::SIGTYPE_TERMINAL, "SIGQUIT is terminal");
  ok( eq_array($ses, [ $ses_2 ]), "SIGQUIT touched correct session" );
}

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok($tot == 1, "SIGQUIT handled by one session");
  ok($type == POE::Kernel::SIGTYPE_TERMINAL, "SIGQUIT is terminal");
  ok( eq_array($ses, [ $ses_2 ]), "SIGQUIT touched correct session" );
}

$poe_kernel->_data_sig_reset_handled("nonexistent");

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok(!defined($tot), "reset signal status = handled by zero sessions");
  ok(
    $type == POE::Kernel::SIGTYPE_BENIGN,
    "reset signal status = benign"
  );
  ok( eq_array($ses, []), "reset signal status = no sessions touched" );
}

# Benign signal the test session.  It doesn't handle the signal.  Try
# to free it.  Make sure it's not freed.
#
# -><- Currently the deprecated behavior is to free everything that
# has _data_sig_touched_session() called on it.  We can enable this
# test properly once the deprecated behavior is removed.
#
# -><- This test is itself not properly tested.

TODO: {
  my ($session, $sid) = create_session();

  $poe_kernel->_data_sig_reset_handled("nonexistent");

  # Clear the implicit handling.
  $poe_kernel->_data_sig_reset_handled("nonexistent");

  # Touch it again, but don't handle it.
  $poe_kernel->_data_sig_touched_session($session);

  my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok(!defined($tot), "nonexistent signal handled by zero sessions");
  ok(
    $type == POE::Kernel::SIGTYPE_BENIGN,
    "nonexistent signal is benign"
  );
  ok(
    eq_array($ses, [ $session ]),
    "nonexistent signal touched target session"
  );

  # Free a benignly-handled session.
  $poe_kernel->_data_sig_free_terminated_sessions();

  # TODO - Enable this test when the signal behavior changes.
  todo_skip "benign signal free test is for future behavior", 1;

  ok(
    $poe_kernel->_data_ses_exists($session->ID),
    "unhandled benign signal does not free session"
  );
}

# Terminal signal the test session.  It handles the signal.  Try to
# free it.  Make sure it's not freed.
# 
# -><- Also tests future behavior.  Enable when _signal is removed.

TODO: {
  $poe_kernel->_data_sig_reset_handled("QUIT");

  $poe_kernel->_data_sig_touched_session($ses_2);

  $poe_kernel->_data_sig_handled();

  # What happens if the session is handled explicitly and implicitly?
  # Well, the implicit deprecation warning should not be triggered.
  $poe_kernel->_data_sig_touched_session($ses_2);

  # Now see if the session's freed.
  $poe_kernel->_data_sig_free_terminated_sessions();

  # TODO - Enable the following test when signal deprecations are
  # done.
  todo_skip "terminal signal free test is for future behavior", 1;

  ok(
    $poe_kernel->_data_ses_exists($ses_2->ID),
    "handled terminal signal does not free session"
  );
}

# Terminal signal the test session.  It does not handle the signal.
# Try to free it.  Make sure it is freed.

$poe_kernel->_data_sig_reset_handled("QUIT");

$poe_kernel->_data_sig_touched_session($ses_2);

{ my ($tot, $type, $ses) = $poe_kernel->_data_sig_handled_status();
  ok(!defined($tot), "SIGQUIT handled by zero sessions");
  ok($type == POE::Kernel::SIGTYPE_TERMINAL, "SIGQUIT is terminal");
  ok( eq_array($ses, [ $ses_2 ]), "SIGQUIT touched session 2" );
}

$poe_kernel->_data_sig_free_terminated_sessions();
ok(
  !$poe_kernel->_data_ses_exists($ses_2->ID),
  "unhandled terminal signal freed session 2"
);

# Nonmaskable signals terminate sessions no matter what.

{ my $ses = bless [ ], "POE::Session";
  my $sid = $poe_kernel->_data_sid_allocate();

  $ses->_set_id($sid);
  $poe_kernel->_data_ses_allocate(
    $ses,              # session
    $sid,              # sid
    $poe_kernel->ID,   # parent
  );

  $poe_kernel->_data_sig_reset_handled("UIDESTROY");

  $poe_kernel->_data_sig_touched_session($ses);

  $poe_kernel->_data_sig_handled();

  my ($tot, $type, $touched_ses) = $poe_kernel->_data_sig_handled_status();
  ok($tot == 1, "SIGUIDESTROY handled by zero sessions");
  ok(
    $type == POE::Kernel::SIGTYPE_NONMASKABLE,
    "SIGUIDESTROY is not maskable"
  );
  ok(
    eq_array([ $ses ], $touched_ses),
    "SIGUIDESTROY touched session correct session"
  );

  $poe_kernel->_data_sig_free_terminated_sessions();
  ok(
    !$poe_kernel->_data_ses_exists($ses->ID),
    "handled SIGUIDESTROY freed target session anyway"
  );
}

# It's ok to clear signals from a nonexistent session, because not all
# sessions watch signals.  This exercises a branch not usually taken
# in the tests.

$poe_kernel->_data_sig_clear_session("nonexistent");

# Check whether anybody's watching a bogus signal.  This exercises a
# branch that's not normally taken in the tests.

ok(
  !$poe_kernel->_data_sig_is_watched_by_session("nonexistent", $ses_2->ID),
  "session 2 isn't watching for a nonexistent signal"
);

# Ensure the data structures are clean when we're done.
ok($poe_kernel->_data_sig_finalize(), "POE::Resource::Signals finalized ok");

1;