1NAME
2
3 Test::POE::Client::TCP - A POE Component providing TCP client services
4 for test cases
5
6VERSION
7
8 version 1.26
9
10SYNOPSIS
11
12 use strict;
13 use Socket;
14 use Test::More tests => 15;
15 use POE qw(Wheel::SocketFactory Wheel::ReadWrite Filter::Line);
16 use Test::POE::Client::TCP;
17
18 my @data = (
19 'This is a test',
20 'This is another test',
21 'This is the last test',
22 );
23
24 POE::Session->create(
25 package_states => [
26 'main' => [qw(
27 _start
28 _accept
29 _failed
30 _sock_in
31 _sock_err
32 testc_registered
33 testc_connected
34 testc_disconnected
35 testc_input
36 testc_flushed
37 )],
38 ],
39 heap => { data => \@data, },
40 );
41
42 $poe_kernel->run();
43 exit 0;
44
45 sub _start {
46 my ($kernel,$heap) = @_[KERNEL,HEAP];
47 $heap->{listener} = POE::Wheel::SocketFactory->new(
48 BindAddress => '127.0.0.1',
49 SuccessEvent => '_accept',
50 FailureEvent => '_failed',
51 SocketDomain => AF_INET, # Sets the socket() domain
52 SocketType => SOCK_STREAM, # Sets the socket() type
53 SocketProtocol => 'tcp', # Sets the socket() protocol
54 Reuse => 'on', # Lets the port be reused
55 );
56 $heap->{testc} = Test::POE::Client::TCP->spawn();
57 return;
58 }
59
60 sub _accept {
61 my ($kernel,$heap,$socket) = @_[KERNEL,HEAP,ARG0];
62 my $wheel = POE::Wheel::ReadWrite->new(
63 Handle => $socket,
64 InputEvent => '_sock_in',
65 ErrorEvent => '_sock_err',
66 );
67 $heap->{wheels}->{ $wheel->ID } = $wheel;
68 return;
69 }
70
71 sub _failed {
72 my ($kernel,$heap,$operation,$errnum,$errstr,$wheel_id) = @_[KERNEL,HEAP,ARG0..ARG3];
73 die "Wheel $wheel_id generated $operation error $errnum: $errstr\n";
74 return;
75 }
76
77 sub _sock_in {
78 my ($heap,$input,$wheel_id) = @_[HEAP,ARG0,ARG1];
79 pass('Got input from client');
80 $heap->{wheels}->{ $wheel_id }->put( $input ) if $heap->{wheels}->{ $wheel_id };
81 return;
82 }
83
84 sub _sock_err {
85 my ($heap,$wheel_id) = @_[HEAP,ARG3];
86 pass('Client disconnected');
87 delete $heap->{wheels}->{ $wheel_id };
88 return;
89 }
90
91 sub testc_registered {
92 my ($kernel,$sender,$object) = @_[KERNEL,SENDER,ARG0];
93 pass($_[STATE]);
94 my $port = ( sockaddr_in( $_[HEAP]->{listener}->getsockname() ) )[0];
95 $kernel->post( $sender, 'connect', { address => '127.0.0.1', port => $port } );
96 return;
97 }
98
99 sub testc_connected {
100 my ($kernel,$heap,$sender) = @_[KERNEL,HEAP,SENDER];
101 pass($_[STATE]);
102 $kernel->post( $sender, 'send_to_server', $heap->{data}->[0] );
103 return;
104 }
105
106 sub testc_flushed {
107 pass($_[STATE]);
108 return;
109 }
110
111 sub testc_input {
112 my ($heap,$input) = @_[HEAP,ARG0];
113 pass('Got something back from the server');
114 my $data = shift @{ $heap->{data} };
115 ok( $input eq $data, "Data matched: '$input'" );
116 unless ( scalar @{ $heap->{data} } ) {
117 $heap->{testc}->terminate();
118 return;
119 }
120 $poe_kernel->post( $_[SENDER], 'send_to_server', $heap->{data}->[0] );
121 return;
122 }
123
124 sub testc_disconnected {
125 my ($heap,$state) = @_[HEAP,STATE];
126 pass($state);
127 delete $heap->{wheels};
128 delete $heap->{listener};
129 $heap->{testc}->shutdown();
130 return;
131 }
132
133DESCRIPTION
134
135 Test::POE::Client::TCP is a POE component that provides a TCP client
136 framework for inclusion in client component test cases, instead of
137 having to roll your own.
138
139 Once registered with the component, a session will receive events
140 related to connections made, disconnects, flushed output and input from
141 the specified server.
142
143CONSTRUCTOR
144
145 spawn
146
147 Takes a number of optional arguments:
148
149 'alias', set an alias on the component;
150 'address', the remote address to connect to;
151 'port', the remote port to connect to;
152 'options', a hashref of POE::Session options;
153 'filter', specify a POE::Filter to use for client connections, default is POE::Filter::Line;
154 'inputfilter', specify a POE::Filter for client input;
155 'outputfilter', specify a POE::Filter for output to clients;
156 'localaddr', specify that connections be made from a particular local address;
157 'localport', specify that connections be made from a particular port;
158 'autoconnect', set to a true value to make the poco connect immediately;
159 'prefix', specify an event prefix other than the default of 'testc';
160 'timeout', specify number of seconds to wait for socket timeouts;
161 'context', anything that can fit into a scalar, such as a ref, etc.
162 'usessl', enable SSL/TLS if POE::Component::SSLify is available;
163 'sslctx', set to a SSL Context to configure the SSL Connection;
164 'sslcert', set to a x509 Certificate(PEM encoded) to connect using a client cert;
165 'sslkey', set to a private Key(PEM encoded) to connect using a client cert;
166
167 The semantics for filter, inputfilter and outputfilter are the same
168 as for POE::Component::Server::TCP in that one may provide either a
169 SCALAR, ARRAYREF or an OBJECT.
170
171 If the component is spawned within another session it will
172 automatically register the parent session to receive all events.
173
174 address and port are optional within spawn, but if they aren't
175 specified they must be provided to subsequent connects. If
176 autoconnect is specified, address and port must also be defined.
177
178 usessl is dependent on whether POE::Component::SSLify is available.
179
180METHODS
181
182 connect
183
184 Initiates a connection to the given server. Takes a number of
185 parameters:
186
187 'address', the remote address to connect to;
188 'port', the remote port to connect to;
189 'localaddr', specify that connections be made from a particular local address, optional;
190 'localport', specify that connections be made from a particular port, optional;
191 'usessl', enable SSL/TLS if POE::Component::SSLify is available;
192
193 address and port are optional if they have been already specified
194 during spawn.
195
196 session_id
197
198 Returns the POE::Session ID of the component.
199
200 shutdown
201
202 Terminates the component. It will terminate any pending connects or
203 connections.
204
205 server_info
206
207 Retrieves socket information about the current connection. In a list
208 context it returns a list consisting of, in order, the server
209 address, the server TCP port, our address and our TCP port. In a
210 scalar context it returns a HASHREF with the following keys:
211
212 'peeraddr', the server address;
213 'peerport', the server TCP port;
214 'sockaddr', our address;
215 'sockport', our TCP port;
216
217 send_to_server
218
219 Send some output to the connected server. The first parameter is a
220 string of text to send. This parameter may also be an arrayref of
221 items to send to the client. If the filter you have used requires an
222 arrayref as input, nest that arrayref within another arrayref.
223
224 disconnect
225
226 Places the server connection into pending disconnect state. Set this,
227 then send an applicable message to the server using send_to_server()
228 and the server connection will be terminated.
229
230 terminate
231
232 Immediately disconnects a server connection.
233
234 wheel
235
236 Returns the underlying POE::Wheel::ReadWrite object if we are
237 currently connected to a server, undef otherwise. You can use this
238 method to call methods on the wheel object to switch filters, etc.
239 Exercise caution.
240
241 alias
242
243 Returns the currently configured alias.
244
245 context
246
247 Returns whatever was provided as context when the component was
248 spawned. If nothing was provided then it returns nothing.
249
250INPUT EVENTS
251
252 These are events that the component will accept:
253
254 register
255
256 Takes N arguments: a list of event names that your session wants to
257 listen for, minus the 'testc_' prefix.
258
259 Registering for 'all' will cause it to send all TESTC-related events
260 to you; this is the easiest way to handle it.
261
262 unregister
263
264 Takes N arguments: a list of event names which you don't want to
265 receive. If you've previously done a 'register' for a particular
266 event which you no longer care about, this event will tell the poco
267 to stop sending them to you. (If you haven't, it just ignores you. No
268 big deal).
269
270 connect
271
272 Initiates a connection to the given server. Takes a number of
273 parameters:
274
275 'address', the remote address to connect to;
276 'port', the remote port to connect to;
277 'localaddr', specify that connections be made from a particular local address, optional;
278 'localport', specify that connections be made from a particular port, optional;
279
280 address and port are optional if they have been already specified
281 during spawn.
282
283 shutdown
284
285 Terminates the component. It will terminate any pending connects or
286 connections.
287
288 send_to_server
289
290 Send some output to the connected server. The first parameter is a
291 string of text to send. This parameter may also be an arrayref of
292 items to send to the client. If the filter you have used requires an
293 arrayref as input, nest that arrayref within another arrayref.
294
295 disconnect
296
297 Places the server connection into pending disconnect state. Set this,
298 then send an applicable message to the server using send_to_server()
299 and the server connection will be terminated.
300
301 terminate
302
303 Immediately disconnects a server connection.
304
305OUTPUT EVENTS
306
307 The component sends the following events to registered sessions. If you
308 have changed the prefix option in spawn then substitute testc with the
309 event prefix that you specified.
310
311 testc_registered
312
313 This event is sent to a registering session. ARG0 is the
314 Test::POE::Client::TCP object.
315
316 testc_socket_failed
317
318 Generated if the component cannot make a socket connection. ARG0
319 contains the name of the operation that failed. ARG1 and ARG2 hold
320 numeric and string values for $!, respectively.
321
322 testc_connected
323
324 Generated whenever a connection is established. ARG0 is the server's
325 IP address, ARG1 is the server's TCP port. ARG3 is our IP address and
326 ARG4 is our socket port.
327
328 testc_disconnected
329
330 Generated whenever we disconnect from the server.
331
332 testc_input
333
334 Generated whenever the server sends us some traffic. ARG0 is the data
335 sent ( tokenised by whatever POE::Filter you specified ).
336
337 testc_flushed
338
339 Generated whenever anything we send to the server is actually flushed
340 down the 'line'.
341
342KUDOS
343
344 Contains code borrowed from POE::Component::Server::TCP by Rocco
345 Caputo, Ann Barcomb and Jos Boumans.
346
347SEE ALSO
348
349 POE
350
351 POE::Component::Server::TCP
352
353AUTHOR
354
355 Chris Williams <chris@bingosnet.co.uk>
356
357COPYRIGHT AND LICENSE
358
359 This software is copyright (c) 2018 by Chris Williams, Rocco Caputo,
360 Ann Barcomb and Jos Boumans.
361
362 This is free software; you can redistribute it and/or modify it under
363 the same terms as the Perl 5 programming language system itself.
364
365