| 1 | # $Id$ |
|---|
| 2 | |
|---|
| 3 | package XMPP::Bomber; |
|---|
| 4 | use Moose; |
|---|
| 5 | use XMPP::Bomber::Types; |
|---|
| 6 | |
|---|
| 7 | has 'clients' => ( |
|---|
| 8 | is => 'rw', |
|---|
| 9 | isa => 'ClientList', |
|---|
| 10 | auto_deref => 1, |
|---|
| 11 | coerce => 1, |
|---|
| 12 | required => 1, |
|---|
| 13 | ); |
|---|
| 14 | |
|---|
| 15 | has 'condvar' => ( |
|---|
| 16 | is => 'rw', |
|---|
| 17 | default => sub { AnyEvent->condvar(cb => \&child_exited) } |
|---|
| 18 | ); |
|---|
| 19 | |
|---|
| 20 | no Moose; |
|---|
| 21 | |
|---|
| 22 | use AnyEvent; |
|---|
| 23 | # use AnyEvent::Impl::Perl; |
|---|
| 24 | use Net::XMPP2; |
|---|
| 25 | use Net::XMPP2::Client; |
|---|
| 26 | use XMPP::Bomber::Account; |
|---|
| 27 | use XMPP::Bomber::Sender; |
|---|
| 28 | use XMPP::Bomber::Receiver; |
|---|
| 29 | |
|---|
| 30 | our $VERSION = '0.00001'; |
|---|
| 31 | |
|---|
| 32 | sub run |
|---|
| 33 | { |
|---|
| 34 | my ($self) = @_; |
|---|
| 35 | |
|---|
| 36 | $self->run_clients; |
|---|
| 37 | |
|---|
| 38 | wait(); |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | sub run_clients |
|---|
| 42 | { |
|---|
| 43 | my $self = shift; |
|---|
| 44 | |
|---|
| 45 | foreach my $client ($self->clients) { |
|---|
| 46 | my $pid = fork(); |
|---|
| 47 | if (! defined $pid) { |
|---|
| 48 | die "Failed to fork!"; |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | if (! $pid ) { |
|---|
| 52 | eval { |
|---|
| 53 | $client->run; |
|---|
| 54 | }; |
|---|
| 55 | exit $@ ? 1 : 0; |
|---|
| 56 | } |
|---|
| 57 | } |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | sub start_receivers |
|---|
| 61 | { |
|---|
| 62 | my $self = shift; |
|---|
| 63 | |
|---|
| 64 | my $provider = $self->receiver_provider; |
|---|
| 65 | while (my $account = $provider->create) { |
|---|
| 66 | my $receiver = XMPP::Bomber::Receiver->new( |
|---|
| 67 | hostname => $self->hostname, |
|---|
| 68 | port => $self->port, |
|---|
| 69 | domain => $self->domain, |
|---|
| 70 | account => $account |
|---|
| 71 | ); |
|---|
| 72 | |
|---|
| 73 | $receiver->start; |
|---|
| 74 | |
|---|
| 75 | AnyEvent->child( |
|---|
| 76 | pid => $receiver->pid, |
|---|
| 77 | cb => sub { $self->condvar->send($self) } |
|---|
| 78 | ); |
|---|
| 79 | push @{$self->receivers}, $receiver; |
|---|
| 80 | } |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | sub stop_receivers |
|---|
| 84 | { |
|---|
| 85 | my $self = shift; |
|---|
| 86 | my $receiver_count = $self->receiver_count; |
|---|
| 87 | foreach my $receiver ( @{ $self->receivers } ) { |
|---|
| 88 | $receiver->stop; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | sub child_exited { die "exited @_" } |
|---|
| 94 | |
|---|
| 95 | sub start_senders |
|---|
| 96 | { |
|---|
| 97 | my $self = shift; |
|---|
| 98 | |
|---|
| 99 | my $provider = $self->sender_provider; |
|---|
| 100 | while (my $account = $provider->create) { |
|---|
| 101 | my $sender = XMPP::Bomber::Sender->new( |
|---|
| 102 | hostname => $self->hostname, |
|---|
| 103 | port => $self->port, |
|---|
| 104 | domain => $self->domain, |
|---|
| 105 | content_provider => $self->content_provider, |
|---|
| 106 | receivers => $self->receivers, |
|---|
| 107 | account => $account, |
|---|
| 108 | ); |
|---|
| 109 | $sender->start; |
|---|
| 110 | |
|---|
| 111 | AnyEvent->child( |
|---|
| 112 | pid => $sender->pid, |
|---|
| 113 | cb => sub { $self->condvar->send($self) } |
|---|
| 114 | ); |
|---|
| 115 | push @{$self->senders}, $sender; |
|---|
| 116 | |
|---|
| 117 | } |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | sub stop_senders |
|---|
| 121 | { |
|---|
| 122 | my $self = shift; |
|---|
| 123 | my $sender_count = 1; |
|---|
| 124 | foreach my $sender ( @{ $self->senders } ) { |
|---|
| 125 | $sender->stop; |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | sub make_par |
|---|
| 130 | { |
|---|
| 131 | my (%args) = @_; |
|---|
| 132 | |
|---|
| 133 | my $find_cmd = sub { |
|---|
| 134 | my ($name, $default) = @_; |
|---|
| 135 | |
|---|
| 136 | my $cmd = $default; |
|---|
| 137 | if (! $cmd) { |
|---|
| 138 | foreach my $path (split(/:/, $ENV{PATH})) { |
|---|
| 139 | my $fqpath = File::Spec->catfile($path, $name); |
|---|
| 140 | if (-x $fqpath) { |
|---|
| 141 | $cmd = $fqpath; |
|---|
| 142 | last; |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | if (! $cmd || ! -x $cmd) { |
|---|
| 148 | die "Could not find a suitable '$name' executable"; |
|---|
| 149 | } |
|---|
| 150 | return $cmd; |
|---|
| 151 | }; |
|---|
| 152 | |
|---|
| 153 | my $pp = $find_cmd->('pp', $ENV{PAR_PACKER}); |
|---|
| 154 | my $xmpp_bomber = $find_cmd->('xmpp-bomber', $ENV{XMPP_BOMBER}); |
|---|
| 155 | |
|---|
| 156 | # Now pack all this stuff |
|---|
| 157 | my @modules = ( |
|---|
| 158 | 'DateTime::Locale::en', # need to add this manually |
|---|
| 159 | 'XMPP::Bomber', |
|---|
| 160 | 'XMPP::Bomber::Sender', |
|---|
| 161 | 'XMPP::Bomber::Receiver', |
|---|
| 162 | 'XMPP::Bomber::Account', |
|---|
| 163 | 'XMPP::Bomber::Role::ContentProvider', |
|---|
| 164 | 'XMPP::Bomber::Role::UserProvider', |
|---|
| 165 | 'XMPP::Bomber::UserProvider::Static', |
|---|
| 166 | 'XMPP::Bomber::UserProvider::OpenFire::Random', |
|---|
| 167 | 'XMPP::Bomber::ContentProvider::Gibberish', |
|---|
| 168 | @{ $args{extra_modules} || [] } |
|---|
| 169 | ); |
|---|
| 170 | |
|---|
| 171 | my $outfile = $args{outfile} || 'xmpp-bomber.par'; |
|---|
| 172 | my @cmd = ( |
|---|
| 173 | $pp, |
|---|
| 174 | '-I' => 'lib', |
|---|
| 175 | "-o" => $outfile, |
|---|
| 176 | (map { ("-M" => $_) } @modules ), |
|---|
| 177 | $xmpp_bomber |
|---|
| 178 | ); |
|---|
| 179 | system(@cmd); |
|---|
| 180 | if ($? != 0 || ! -e $outfile) { |
|---|
| 181 | die "Failed to execute @cmd"; |
|---|
| 182 | } |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | 1; |
|---|
| 186 | |
|---|
| 187 | __END__ |
|---|
| 188 | |
|---|
| 189 | =head1 NAME |
|---|
| 190 | |
|---|
| 191 | XMPP::Bomber - Stretch The Limit Of Your XMPP Servers |
|---|
| 192 | |
|---|
| 193 | =head1 SYNOPSIS |
|---|
| 194 | |
|---|
| 195 | use XMPP::Bomber; |
|---|
| 196 | |
|---|
| 197 | my $hostname = ...; |
|---|
| 198 | my $password = ...; |
|---|
| 199 | |
|---|
| 200 | # First, create the "senders" you want to use |
|---|
| 201 | # In this case we only want one sender, and the sender is a static one |
|---|
| 202 | my $senders = XMPP::Bomber::Default::StaticUserProvider->new( |
|---|
| 203 | users => [ |
|---|
| 204 | XMPP::Bomber::Account->new( |
|---|
| 205 | username => $opts{username}, |
|---|
| 206 | password => $opts{password}, |
|---|
| 207 | domain => $opts{domain}, |
|---|
| 208 | ) |
|---|
| 209 | ] |
|---|
| 210 | ); |
|---|
| 211 | |
|---|
| 212 | # Now, define the "receivers". |
|---|
| 213 | # We will be generating 100 users with random usernames directly into the |
|---|
| 214 | # OpenFire database |
|---|
| 215 | my $receivers = XMPP::Bomber::OpenFire::RandomUserProvider->new( |
|---|
| 216 | domain => $opts{domain}, |
|---|
| 217 | count => 100, |
|---|
| 218 | connect_info => [ |
|---|
| 219 | $opts{dsn}, |
|---|
| 220 | $opts{dbuser}, |
|---|
| 221 | $opts{dbpass}, |
|---|
| 222 | { RaiseError => 1, AutoCommit => 1 } |
|---|
| 223 | ], |
|---|
| 224 | ); |
|---|
| 225 | |
|---|
| 226 | # Define the content provider |
|---|
| 227 | my $content = XMPP::Bomber::Default::GibberishContentProvider->new( |
|---|
| 228 | max_length => 512, |
|---|
| 229 | ); |
|---|
| 230 | |
|---|
| 231 | my $bomber = XMPP::Bomber->new( |
|---|
| 232 | hostname => '192.168.0.5', |
|---|
| 233 | domain => 'endeworks.jp', |
|---|
| 234 | sender_provider => $senders, |
|---|
| 235 | receiver_provider => $receivers, |
|---|
| 236 | content_provider => $content |
|---|
| 237 | ); |
|---|
| 238 | |
|---|
| 239 | $bomber->run; |
|---|
| 240 | |
|---|
| 241 | =head1 DESCRIPTION |
|---|
| 242 | |
|---|
| 243 | This module exists solely to test the amount of messages that your XMPP |
|---|
| 244 | server can handle. It creates one or more "senders", and one or more |
|---|
| 245 | "receivers". There's also a |
|---|
| 246 | |
|---|
| 247 | You can specify how these se |
|---|
| 248 | |
|---|
| 249 | =head1 |
|---|
| 250 | |
|---|
| 251 | |
|---|
| 252 | =cut |
|---|