File Coverage

blib/lib/Test/Statsd.pm
Criterion Covered Total %
statement 77 82 93.9
branch 8 12 66.6
condition 3 7 42.8
subroutine 16 16 100.0
pod 0 6 0.0
total 104 123 84.5


line stmt bran cond sub pod time code
1             package Test::Statsd;
2             $Test::Statsd::VERSION = '0.20';
3 14     14   22738 use 5.008;
  14         32  
4 14     14   94 use strict;
  14         18  
  14         292  
5 14     14   42 use warnings;
  14         16  
  14         294  
6              
7 14     14   11904 use AnyEvent;
  14         53118  
  14         372  
8 14     14   5546 use AnyEvent::Strict;
  14         156512  
  14         330  
9 14     14   8472 use AnyEvent::Handle;
  14         174244  
  14         500  
10 14     14   7330 use AnyEvent::Socket;
  14         138744  
  14         1168  
11 14     14   6336 use IO::Socket::INET ();
  14         158078  
  14         308  
12 14     14   6338 use Time::HiRes;
  14         13436  
  14         56  
13              
14             sub new {
15 14     14 0 4374 my ($class, $opt) = @_;
16 14   33     90 $class = ref $class || $class;
17 14   50     74 $opt ||= {};
18             my $self = {
19             binary => $opt->{binary},
20             config => $opt->{config},
21 14         66 _statsd_pid => undef,
22             };
23 14         40 bless $self, $class;
24             }
25              
26             # A read callback (read_cb) can optionally be used in special
27             # cases when you don't want the TCP server to be shut down
28             # when the first flush data is received (see delete-idle-stats test
29             # for an example).
30              
31             sub wait_and_collect_flush_data {
32 7     7 0 325 my ($self, $port, $read_cb) = @_;
33              
34 7         36 $self->{_flush_data} = "";
35              
36             # Pretend to be a carbon/graphite daemon
37 7   50     153 $port ||= 40003;
38              
39 7         15 my $srv;
40 7         414 my $cv = AE::cv;
41              
42             $srv = tcp_server undef, $port, sub {
43 9     9   7231282 my ($fh, $host, $port) = @_;
44 9         13 my $hdl;
45             $hdl = AnyEvent::Handle->new(
46             fh => $fh,
47             on_error => sub {
48 0         0 warn "Socket error: $!\n";
49 0         0 $_[0]->destroy
50             },
51             on_read => sub {
52 9         4810 my ($ae_handle) = @_;
53             # Store graphite data into a private object member
54 9         50 $self->{_flush_data} .= $ae_handle->rbuf;
55 9 100       71 if ($read_cb) {
56 4         25 $read_cb->($hdl, $cv, $self->{_flush_data});
57             # We need to clear the received data now, or our
58             # reader will be surprised receiving the old + new
59             # buffer in the n > 1 round.
60 4         1332 $self->{_flush_data} = "";
61 4         28 $ae_handle->{rbuf} = "";
62             } else {
63             # Calling send() on the condvar stops the TCP server
64 5         50 $cv->send();
65             }
66             },
67 2         123 on_eof => sub { $hdl->destroy },
68 9         276 );
69 7         2510 };
70 7         1907 $cv->recv();
71 7         501 return $self->{_flush_data};
72             }
73              
74             sub hashify {
75 9     9 0 6273 my ($self, $str) = @_;
76 9         204 my @lines = split m{\r?\n}, $str;
77 9         13 my $stats;
78 9         23 for (@lines) {
79 118         380 $_ =~ s{^ \s* (\S*) \s* $}{$1}x;
80 118 50       154 next unless defined;
81 118         200 my ($key, $val, $ts) = split;
82 118         233 $stats->{$key} = $val;
83             }
84 9         28 return $stats;
85             }
86              
87             sub start_statsd {
88 14     14 0 66 my ($self) = @_;
89              
90 14         10094 my $pid = fork;
91 14 50       633 if (! defined $pid) {
    100          
92 0         0 die "Fork failed: $! Aborting.";
93             }
94              
95             # Child
96             elsif ($pid == 0) {
97 7         419 my @binary = split " ", $self->{binary};
98 7         83 my $config = $self->{config};
99 7         0 exec @binary, $config, '2>&1 1>/dev/null';
100             }
101              
102             # Parent
103             else {
104 7         122 $self->{_statsd_pid} = $pid;
105             # Allow for child statsd to start up
106 7         3501177 Time::HiRes::usleep(500_000);
107             }
108             }
109              
110             sub stop_statsd {
111 7     7 0 3601 my ($self) = @_;
112              
113 7         19 my $pid = $self->{_statsd_pid};
114 7 50       31 if (! $pid) {
115 0         0 die "Statsd was never started?";
116             }
117              
118 7 50       189 if (! kill(15, $pid)) {
119 0         0 die "Failed to stop statsd (pid: $pid). "
120             . "Please do something manually ($!)";
121             }
122              
123 7         93 return 1;
124             }
125              
126             sub send_udp {
127 106     106 0 1282 my ($self, $host, $port, $payload) = @_;
128              
129 106         544 my $sock = IO::Socket::INET->new(
130             Proto => 'udp',
131             PeerAddr => $host,
132             PeerPort => $port,
133             );
134              
135 106         23505 my $len = $sock->send($payload);
136 106         4886 $sock->close();
137              
138 106         1865 return $len == length($payload);
139             }
140              
141             1;
142              
143             =pod
144              
145             =head1 NAME
146              
147             Test::Statsd - Test harness for any statsd server daemon
148              
149             =head1 DESCRIPTION
150              
151             Embeds the logic to perform integration tests of any statsd
152             daemon that can be launched from the command line.
153              
154             Usage:
155              
156             my $t = Test::Statsd->new({
157             binary => './bin/statsd',
158             config => './bin/sample-config.json'
159             });
160              
161             # Brings up the statsd server in the background
162             # with the specified configuration, and stores its pid
163             $t->start_statsd();
164              
165            
166             =cut