1Test::POE::Server::TCP(U3s)er Contributed Perl DocumentatTieosnt::POE::Server::TCP(3)
2
3
4
6 Test::POE::Server::TCP - A POE Component providing TCP server services
7 for test cases
8
10 version 1.20
11
13 A very simple echo server with logging of requests by each client:
14
15 use strict;
16 use POE;
17 use Test::POE::Server::TCP;
18
19 POE::Session->create(
20 package_states => [
21 'main' => [qw(
22 _start
23 testd_connected
24 testd_disconnected
25 testd_client_input
26 )],
27 ],
28 );
29
30 $poe_kernel->run();
31 exit 0;
32
33 sub _start {
34 # Spawn the Test::POE::Server::TCP server.
35 $_[HEAP]->{testd} = Test::POE::Server::TCP->spawn(
36 address => '127.0.0.1',
37 port => 0,
38 );
39 return;
40 }
41
42 sub testd_connected {
43 my ($heap,$id) = @_[HEAP,ARG0];
44
45 # A client connected the unique ID is in ARG0
46 # Create a blank arrayref for this client on *our* heap
47
48 $heap->{clients}->{ $id } = [ ];
49
50 return;
51 }
52
53 sub testd_client_input {
54 my ($kernel,$heap,$sender,$id,$input) = @_[KERNEL,HEAP,SENDER,ARG0,ARG1];
55
56 # The client sent us a line of input
57 # lets store it
58
59 push @{ $heap->{clients}->{ $id } }, $input;
60
61 # Okay, we are an echo server so lets send it back to the client
62 # We know the SENDER so can always obtain the server object.
63
64 my $testd = $sender->get_heap();
65 $testd->send_to_client( $id, $input );
66
67 # Or even
68
69 # $sender->get_heap()->send_to_client( $id, $input );
70
71 # Alternatively we could just post back to the SENDER
72
73 # $kernel->post( $sender, 'send_to_client', $id, $input );
74
75 return;
76 }
77
78 sub testd_disconnected {
79 my ($heap,$id) = @_[HEAP,ARG0];
80
81 # Client disconnected for whatever reason
82 # We need to free up our storage
83
84 delete $heap->{clients}->{ $id };
85
86 return;
87 }
88
89 Using the module in a testcase:
90
91 use strict;
92 use Test::More;
93 use POE qw(Wheel::SocketFactory Wheel::ReadWrite Filter::Line);
94 use Test::POE::Server::TCP;
95
96 plan tests => 5;
97
98 my @data = (
99 'This is a test',
100 'This is another test',
101 'This is the last test',
102 );
103
104 POE::Session->create(
105 package_states => [
106 'main' => [qw(
107 _start
108 _sock_up
109 _sock_fail
110 _sock_in
111 _sock_err
112 testd_connected
113 testd_disconnected
114 testd_client_input
115 )],
116 ],
117 heap => { data => \@data, },
118 );
119
120 $poe_kernel->run();
121 exit 0;
122
123 sub _start {
124 $_[HEAP]->{testd} = Test::POE::Server::TCP->spawn(
125 address => '127.0.0.1',
126 port => 0,
127 );
128 return;
129 }
130
131 sub testd_registered {
132 my ($heap,$object) = @_[HEAP,ARG0];
133 $heap->{port} = $object->port();
134 $heap->{factory} = POE::Wheel::SocketFactory->new(
135 RemoteAddress => '127.0.0.1',
136 RemotePort => $heap->{port},
137 SuccessEvent => '_sock_up',
138 FailureEvent => '_sock_fail',
139 );
140 return;
141 }
142
143 sub _sock_up {
144 my ($heap,$socket) = @_[HEAP,ARG0];
145 delete $heap->{factory};
146 $heap->{socket} = POE::Wheel::ReadWrite->new(
147 Handle => $socket,
148 InputEvent => '_sock_in',
149 ErrorEvent => '_sock_err',
150 );
151 $heap->{socket}->put( $heap->{data}->[0] );
152 return;
153 }
154
155 sub _sock_fail {
156 my $heap = $_[HEAP];
157 delete $heap->{factory};
158 $heap->{testd}->shutdown();
159 return;
160 }
161
162 sub _sock_in {
163 my ($heap,$input) = @_[HEAP,ARG0];
164 my $data = shift @{ $heap->{data} };
165 ok( $input eq $data, 'Data matched' );
166 unless ( scalar @{ $heap->{data} } ) {
167 delete $heap->{socket};
168 return;
169 }
170 $heap->{socket}->put( $heap->{data}->[0] );
171 return;
172 }
173
174 sub _sock_err {
175 delete $_[HEAP]->{socket};
176 return;
177 }
178
179 sub testd_connected {
180 my ($heap,$state,$id) = @_[HEAP,STATE,ARG0];
181 pass($state);
182 return;
183 }
184
185 sub testd_disconnected {
186 pass($_[STATE]);
187 $poe_kernel->post( $_[SENDER], 'shutdown' );
188 return;
189 }
190
191 sub testd_client_input {
192 my ($sender,$id,$input) = @_[SENDER,ARG0,ARG1];
193 my $testd = $_[SENDER]->get_heap();
194 $testd->send_to_client( $id, $input );
195 return;
196 }
197
199 Test::POE::Server::TCP is a POE component that provides a TCP server
200 framework for inclusion in client component test cases, instead of
201 having to roll your own.
202
203 Once registered with the component, a session will receive events
204 related to client connects, disconnects, input and flushed output. Each
205 of these events will refer to a unique client ID which may be used in
206 communication with the component when sending data to the client or
207 disconnecting a client connection.
208
209 If AF_INET6 sockets are supported the component with create an AF_INET
210 and an AF_INET6 socket.
211
213 "spawn"
214 Takes a number of optional arguments:
215
216 'alias', set an alias on the component;
217 'address', bind the listening socket to a particular address;
218 'port', listen on a particular port, default is 0, assign a random port;
219 'options', a hashref of POE::Session options;
220 'filter', specify a POE::Filter to use for client connections, default is POE::Filter::Line;
221 'inputfilter', specify a POE::Filter for client input;
222 'outputfilter', specify a POE::Filter for output to clients;
223 'prefix', specify a different prefix than 'testd' for events;
224
225 The semantics for "filter", "inputfilter" and "outputfilter" are
226 the same as for POE::Component::Server::TCP in that one may provide
227 either a "SCALAR", "ARRAYREF" or an "OBJECT".
228
229 If the component is "spawn"ed within another session it will
230 automatically "register" the parent session to receive "all"
231 events.
232
234 "session_id"
235 Returns the POE::Session ID of the component.
236
237 "shutdown"
238 Terminates the component. Shuts down the listener and disconnects
239 connected clients.
240
241 "send_to_client"
242 Send some output to a connected client. First parameter must be a
243 valid client id. Second parameter is a string of text to send. The
244 second parameter may also be an arrayref of items to send to the
245 client. If the filter you have used requires an arrayref as input,
246 nest that arrayref within another arrayref.
247
248 "send_to_all_clients"
249 Send some output to all connected clients. The parameter is a
250 string of text to send. The parameter may also be an arrayref of
251 items to send to the clients. If the filter you have used requires
252 an arrayref as input, nest that arrayref within another arrayref.
253
254 "client_info"
255 Retrieve socket information of a given client. Requires a valid
256 client ID as a parameter. If called in a list context it returns a
257 list consisting of, in order, the client address, the client TCP
258 port, our address and our TCP port. In a scalar context it returns
259 a HASHREF with the following keys:
260
261 'peeraddr', the client address;
262 'peerport', the client TCP port;
263 'sockaddr', our address;
264 'sockport', our TCP port;
265
266 "client_wheel"
267 Retrieve the POE::Wheel::ReadWrite object of a given client.
268 Requires a valid client ID as a parameter. This enables one to
269 manipulate the given POE::Wheel::ReadWrite object, say to switch
270 POE::Filter.
271
272 "disconnect"
273 Places a client connection in pending disconnect state. Requires a
274 valid client ID as a parameter. Set this, then send an applicable
275 message to the client using send_to_client() and the client
276 connection will be terminated.
277
278 "terminate"
279 Immediately disconnects a client conenction. Requires a valid
280 client ID as a parameter.
281
282 "pause_listening"
283 Stops the underlying listening socket from accepting new
284 connections. This lets you test whether you handle the connection
285 timing out gracefully.
286
287 "resume_listening"
288 The companion of "pause_listening"
289
290 "getsockname"
291 Access to the POE::Wheel::SocketFactory method of the underlying
292 listening AF_INET socket.
293
294 "port"
295 Returns the port that the component is listening on.
296
297 "getsockname6"
298 Access to the POE::Wheel::SocketFactory method of the underlying
299 listening AF_INET6 socket.
300
301 "port6"
302 Returns the port that the component is listening on for AF_INET6.
303
304 "start_listener"
305 If the listener fails on "listen" you can attempt to restart it
306 with this.
307
309 These are events that the component will accept:
310
311 "register"
312 Takes N arguments: a list of event names that your session wants to
313 listen for, minus the 'testd_' prefix.
314
315 Registering for 'all' will cause it to send all TESTD-related
316 events to you; this is the easiest way to handle it.
317
318 "unregister"
319 Takes N arguments: a list of event names which you don't want to
320 receive. If you've previously done a 'register' for a particular
321 event which you no longer care about, this event will tell the
322 POP3D to stop sending them to you. (If you haven't, it just ignores
323 you. No big deal).
324
325 "shutdown"
326 Terminates the component. Shuts down the listener and disconnects
327 connected clients.
328
329 "send_to_client"
330 Send some output to a connected client. First parameter must be a
331 valid client id. Second parameter is a string of text to send. The
332 second parameter may also be an arrayref of items to send to the
333 client. If the filter you have used requires an arrayref as input,
334 nest that arrayref within another arrayref.
335
336 "send_to_all_clients"
337 Send some output to all connected clients. The parameter is a
338 string of text to send. The parameter may also be an arrayref of
339 items to send to the clients. If the filter you have used requires
340 an arrayref as input, nest that arrayref within another arrayref.
341
342 "disconnect"
343 Places a client connection in pending disconnect state. Requires a
344 valid client ID as a parameter. Set this, then send an applicable
345 message to the client using send_to_client() and the client
346 connection will be terminated.
347
348 "terminate"
349 Immediately disconnects a client conenction. Requires a valid
350 client ID as a parameter.
351
352 "start_listener"
353 If the listener fails on "listen" you can attempt to restart it
354 with this.
355
357 The component sends the following events to registered sessions. If you
358 have changed the "prefix" option in "spawn" then substitute "testd"
359 with the event prefix that you specified.
360
361 "testd_registered"
362 This event is sent to a registering session. ARG0 is the
363 Test::POE::Server::TCP object.
364
365 "testd_listener_failed"
366 Generated if the component cannot either start a listener or there
367 is a problem accepting client connections. ARG0 contains the name
368 of the operation that failed. ARG1 and ARG2 hold numeric and
369 string values for $!, respectively.
370
371 If the operation was "listen", the component will remove the
372 listener. You may attempt to start it again using
373 "start_listener".
374
375 "testd_connected"
376 Generated whenever a client connects to the component. ARG0 is the
377 client ID, ARG1 is the client's IP address, ARG2 is the client's
378 TCP port. ARG3 is our IP address and ARG4 is our socket port.
379
380 "testd_disconnected"
381 Generated whenever a client disconnects. ARG0 was the client ID,
382 ARG1 was the client's IP address, ARG2 was the client's TCP port.
383 ARG3 was our IP address and ARG4 was our socket port.
384
385 "testd_client_input"
386 Generated whenever a client sends us some traffic. ARG0 is the
387 client ID, ARG1 is the data sent ( tokenised by whatever
388 POE::Filter you specified ).
389
390 "testd_client_flushed"
391 Generated whenever anything we send to the client is actually
392 flushed down the 'line'. ARG0 is the client ID.
393
395 This module uses code borrowed from POE::Component::Server::TCP by
396 Rocco Caputo, Ann Barcomb and Jos Boumans.
397
399 POE
400
401 POE::Component::Server::TCP
402
404 Chris Williams <chris@bingosnet.co.uk>
405
407 This software is copyright (c) 2016 by Chris Williams, Rocco Caputo,
408 Ann Barcomb and Jos Boumans.
409
410 This is free software; you can redistribute it and/or modify it under
411 the same terms as the Perl 5 programming language system itself.
412
413
414
415perl v5.32.0 2020-07-28 Test::POE::Server::TCP(3)