File: events.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 (317 lines) | stat: -rw-r--r-- 8,946 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
# vim: ts=2 sw=2 expandtab
use strict;

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

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

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

BEGIN { use_ok("POE") }

sub BOGUS_SESSION () { 31415 }

my $baseline_event    = 0;
my $baseline_refcount = 0;

# This subsystem is still very closely tied to POE::Kernel, so we
# can't call initialize ourselves.  TODO Separate it, if possible,
# enough to make this feasible.

{ # Create a new event, and verify that it's good.

  my $event_id = $poe_kernel->_data_ev_enqueue(
    $poe_kernel,  # session
    $poe_kernel,  # source_session
    "event",      # event
    POE::Kernel::ET_ALARM,  # event type
    [],           # etc
    __FILE__,     # file
    __LINE__,     # line
    "called_from",# caller state
    0,            # time (beginning thereof)
  );

  # Event 1 is the kernel's performance poll timer.
  is(
    $event_id, $baseline_event + 1,
    "first user created event has correct ID"
  );

  # Kernel should therefore have one events due.
  # A nonexistent session should have zero.

  is(
    $poe_kernel->_data_ev_get_count_from($poe_kernel->ID), $baseline_event,
    "POE::Kernel has enqueued correct number of events"
  );

  is(
    $poe_kernel->_data_ev_get_count_to($poe_kernel->ID), $baseline_event + 1,
    "POE::Kernel has three events enqueued for it"
  );

  is(
    $poe_kernel->_data_ev_get_count_from("nothing"), 0,
    "unknown session has enqueued no events"
  );

  is(
    $poe_kernel->_data_ev_get_count_to("nothing"), 0,
    "unknown session has no events enqueued for it"
  );

  # Performance timer only counts once now.

  is(
    $poe_kernel->_data_ses_refcount($poe_kernel->ID), $baseline_refcount + 1,
    "POE::Kernel's timer count is correct"
  );
}

{ # Dispatch due events, and stuff.

  $poe_kernel->_data_ev_dispatch_due();
  check_references(
    $poe_kernel, 0, 0, 0, "after due events are dispatched"
  );
}

# Test timer maintenance functions.  Add some alarms: Three with
# identical names, and one with another name.  Remember the ID of one
# of them, so we can remove it explicitly.  The other three should
# remain.  Remove them by name, and both the remaining ones with the
# same name should disappear.  The final alarm will be removed by
# clearing alarms for the session.

my @ids;
for (1..4) {
  my $timer_name = "timer";
  $timer_name = "other-timer" if $_ == 4;

  push(
    @ids,
    $poe_kernel->_data_ev_enqueue(
      $poe_kernel,           # session
      $poe_kernel,           # source_session
      $timer_name,           # event
      POE::Kernel::ET_ALARM, # event type
      [],                    # etc
      __FILE__,              # file
      __LINE__,              # line
      undef,                 # called from state
      $_,                    # time
    )
  );
}

# The from and to counts should add up to the reference count.

check_references(
  $poe_kernel, 0, 0, 4, "after some timers are enqueued"
);

{ # Remove one of the alarms by its ID.

  my ($time, $event) = $poe_kernel->_data_ev_clear_alarm_by_id(
    $poe_kernel->ID(), $ids[1]
  );

  is($time, 2, "removed event has the expected due time");
  is(
    $event->[POE::Kernel::EV_NAME], "timer",
    "removed event has the expected name"
  );

  check_references(
    $poe_kernel, 0, 0, 3, "after a single named event is removed"
  );
}

{ # Try to remove a nonexistent alarm by the ID it would have if it
  # did exist, except it doesn't.

  my ($time, $event) = $poe_kernel->_data_ev_clear_alarm_by_id(
    $poe_kernel->ID(), 8675309
  );

  ok(!defined($time), "can't clear bogus alarm by nonexistent ID");
  check_references(
    $poe_kernel, 0, 0, 3, "after trying to clear a bogus alarm"
  );
}

# Remove an alarm by name, except that this is for a nonexistent
# session.

$poe_kernel->_data_ev_clear_alarm_by_name(BOGUS_SESSION, "timer");
check_references(
  $poe_kernel, 0, 0, 3, "after removing timers from a bogus session"
);

is(
  $poe_kernel->_data_ev_get_count_from(BOGUS_SESSION), 0,
  "bogus session has created no events"
);

is(
  $poe_kernel->_data_ev_get_count_to(BOGUS_SESSION), 0,
  "bogus session has no events enqueued for it"
);

# Remove the alarm by name, for real.  We should be down to one timer
# (the original poll thing).

$poe_kernel->_data_ev_clear_alarm_by_name($poe_kernel->ID(), "timer");
check_references(
  $poe_kernel, 0, 0, 1, "after removing 'timer' by name"
);

{ # Try to remove timers from some other (nonexistent should be ok)
  # session.

  my @removed = $poe_kernel->_data_ev_clear_alarm_by_session(8675309);
  is(@removed, 0, "didn't remove alarm from nonexistent session");
}

{ # Remove the last of the timers.  The Kernel session is the only
  # reference left for it.

  my @removed = $poe_kernel->_data_ev_clear_alarm_by_session($poe_kernel->ID());
  is(@removed, 1, "removed the last alarm successfully");

  # Verify that the removed timer is the correct one.  We still have
  # the signal polling timer around there somewhere.
  my ($removed_name, $removed_time, $removed_args) = @{$removed[0]};
  is($removed_name, "other-timer", "last alarm had the corrent name");
  is($removed_time, 4, "last alarm had the corrent due time");

  check_references(
    $poe_kernel, 0, 0, 0, "after clearing all alarms for a session"
  );
}

# Remove all events for the kernel session.  Now it should be able to
# finalize cleanly.
$poe_kernel->_data_ev_clear_session($poe_kernel);

{ # Catch a trap when enqueuing an event for a nonexistent session.

  eval {
    $poe_kernel->_data_ev_enqueue(
      "moo",                  # dest session
      "moo",                  # source session
      "event",                # event name
      POE::Kernel::ET_ALARM,  # event type
      [],                     # etc
      __FILE__,               # file
      __LINE__,               # line
      undef,                  # called from state
      1,                      # due time
    );
  };
  ok(
    $@ && $@ =~ /Can't locate object method "ID"/,
    "trap while enqueuing event for non-existent session"
  );
}

{ # Exercise _data_ev_clear_session when events are sent from one
  # session to another.

  my $session = POE::Session->create(
    inline_states => {
      _start => sub { },
      _stop  => sub { },
    }
  );

  $poe_kernel->_data_ev_enqueue(
    $session,               # dest session
    $poe_kernel,            # source session
    "event-1",              # event name
    POE::Kernel::ET_POST,   # event type
    [],                     # etc
    __FILE__,               # file
    __LINE__,               # line
    undef,                  # called from state
    1,                      # due time
  );

  $poe_kernel->_data_ev_enqueue(
    $poe_kernel,            # dest session
    $session,               # source session
    "event-2",              # event name
    POE::Kernel::ET_POST,   # event type
    [],                     # etc
    __FILE__,               # file
    __LINE__,               # line
    undef,                  # called from state
    2,                      # due time
  );

  check_references(
    $poe_kernel, 1, 1, 1, "after creating inter-session messages"
  );

  $poe_kernel->_data_ev_clear_session($session->ID());

  check_references(
    $poe_kernel, 1, 0, 0, "after clearing inter-session messages"
  );

  $poe_kernel->_data_ev_clear_session($poe_kernel->ID());

  check_references(
    $poe_kernel, 1, 0, 0, "after clearing kernel messages"
  );
}

# A final test.

ok(
  $poe_kernel->_data_ev_finalize(),
  "POE::Resource::Events finalized cleanly"
);

# END OF EXECUTION HERE, BUT I CAN'T USE EXIT

# Every time we cross-check a session for events and reference counts,
# there should be twice as many references as events.  This is because
# each event counts twice: once because the session sent the event,
# and again because the event was due for the session.  Check that the
# from- and to counts add up to the reference count, and that they are
# equal.
#
# The "base" references are ones from sources other than events.  In
# later tests, they're from the addition of another session.

sub check_references {
  my ($session, $base_ref, $expected_from, $expected_to, $when) = @_;

  my $from_count = $poe_kernel->_data_ev_get_count_from($session->ID);
  my $to_count   = $poe_kernel->_data_ev_get_count_to($session->ID);

  # Reference count stopped being simply the from + to + base counts.
  #my $ref_count  = $poe_kernel->_data_ses_refcount($session->ID);
  #my $check_sum  = $from_count + $to_count + $base_ref;
  #is($check_sum, $ref_count, "refcnts $ref_count == $check_sum $when");

  is(
    $from_count, $expected_from,
    "from evcount $from_count == $expected_from $when"
  );
  is(
    $to_count, $expected_to,
    "to evcount $to_count == $expected_to $when"
  );
}

# We created a session, so run it.
POE::Kernel->run();

1;