Bug 6015 : Improving load_testing
[koha.git] / misc / load_testing / benchmark_circulation.pl
1 #!/usr/bin/perl
2 # This script implements a basic benchmarking and regression testing
3 # utility for Koha
4
5 use strict;
6 use warnings;
7 BEGIN {
8     # find Koha's Perl modules
9     # test carefully before changing this
10     use FindBin;
11     eval { require "$FindBin::Bin/kohalib.pl" };
12 }
13
14 use HTTPD::Bench::ApacheBench;
15 use LWP::UserAgent;
16 use Data::Dumper;
17 use HTTP::Cookies;
18 use C4::Context;
19 use C4::Debug;
20
21 my $baseurl= $ARGV[0] || "http://am123/cgi-bin/koha/";
22 my $max_tries = 200;
23 my $concurrency = 30;
24 my $user = $ARGV[1] ||'hdl';
25 my $password = $ARGV[2] || 'hdl';
26
27 # Authenticate via our handy dandy RESTful services
28 # and grab a cookie
29 my $ua = LWP::UserAgent->new();
30 my $cookie_jar = HTTP::Cookies->new();
31 my $cookie;
32 $ua->cookie_jar($cookie_jar);
33 my $resp = $ua->post( "$baseurl"."/svc/authentication" , {userid =>$user, password => $password} );
34 if( $resp->is_success ) {
35     $cookie_jar->extract_cookies( $resp );
36     $cookie = $cookie_jar->as_string;
37     print "Authentication successful\n";
38     print "Auth:\n $resp->content" if $debug;
39 }
40
41 # remove some unnecessary garbage from the cookie
42 $cookie =~ s/ path_spec; discard; version=0//;
43 $cookie =~ s/Set-Cookie3: //;
44
45 # Get some data to work with
46 my $dbh=C4::Context->dbh();
47 my $sth = $dbh->prepare("select max(borrowernumber) from borrowers");
48 $sth->execute;
49 my ($borrowernumber_max) = $sth->fetchrow;
50
51 $sth = $dbh->prepare("select max(biblionumber) from biblio");
52 $sth->execute;
53 my ($biblionumber_max) = $sth->fetchrow;
54
55 $sth = $dbh->prepare("select max(itemnumber) from items");
56 $sth->execute;
57 my ($itemnumber_max) = $sth->fetchrow;
58
59 $|=1;
60 #
61 # the global benchmark we do at the end...
62 #
63 my $b = HTTPD::Bench::ApacheBench->new;
64 $b->concurrency( $concurrency );
65 #
66 # mainpage : (very) low RDBMS dependency
67 #
68 my $b0 = HTTPD::Bench::ApacheBench->new;
69 $b0->concurrency( $concurrency );
70
71 my @mainpage;
72 print "--------------\n";
73 print "Koha circulation benchmarking utility\n";
74 print "--------------\n";
75 print "Benchmarking with $max_tries occurences of each operation and $concurrency concurrent sessions \n";
76 print "Load testing staff client dashboard page";
77 for (my $i=1;$i<=$max_tries;$i++) {
78     push @mainpage,"$baseurl/mainpage.pl";
79 }
80 my $run0 = HTTPD::Bench::ApacheBench::Run->new
81     ({ urls => \@mainpage,
82        cookies => [$cookie],
83     });
84 $b0->add_run($run0);
85 $b->add_run($run0);
86
87 # send HTTP request sequences to server and time responses
88 my $ro = $b0->execute;
89 # calculate hits/sec
90 print ("\t".$b0->total_time."ms\t".(1000*$b0->total_requests/$b0->total_time)." pages/sec\n");
91 print "ALERT : ".$b0->total_responses_failed." failures\n" if $b0->total_responses_failed;
92
93 #
94 # biblios
95 #
96 my $b1 = HTTPD::Bench::ApacheBench->new;
97 $b1->concurrency( $concurrency );
98
99 my @biblios;
100 print "Load testing catalog detail page";
101 for (my $i=1;$i<=$max_tries;$i++) {
102     my $rand_biblionumber = int(rand($biblionumber_max)+1);
103     push @biblios,"$baseurl/catalogue/detail.pl?biblionumber=$rand_biblionumber";
104 }
105 my $run1 = HTTPD::Bench::ApacheBench::Run->new
106     ({ urls => \@biblios,
107     });
108 $b1->add_run($run1);
109 $b->add_run($run1);
110
111 # send HTTP request sequences to server and time responses
112 $ro = $b1->execute;
113 # calculate hits/sec
114 print ("\t".$b1->total_time."ms\t".(1000*$b1->total_requests/$b1->total_time)." biblios/sec\n");
115 print "ALERT : ".$b1->total_responses_failed." failures\n" if $b1->total_responses_failed;
116
117 #
118 # borrowers
119 #
120 my $b2 = HTTPD::Bench::ApacheBench->new;
121 $b2->concurrency( $concurrency );
122
123 my @borrowers;
124 print "Load testing patron detail page";
125 for (my $i=1;$i<=$max_tries;$i++) {
126     my $rand_borrowernumber = int(rand($borrowernumber_max)+1);
127 #     print "$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber\n";
128     push @borrowers,"$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber";
129 }
130 my $run2 = HTTPD::Bench::ApacheBench::Run->new
131     ({ urls => \@borrowers,
132        cookies => [$cookie],
133     });
134 $b2->add_run($run2);
135 $b->add_run($run2);
136
137 # send HTTP request sequences to server and time responses
138 $ro = $b2->execute;
139 # calculate hits/sec
140 print ("\t".$b2->total_time."ms\t".(1000*$b2->total_requests/$b2->total_time)." borrowers/sec\n");
141
142 my $b2 = HTTPD::Bench::ApacheBench->new;
143 $b2->concurrency( $concurrency );
144 print "Load testing patron search page";
145 for (my $i=1;$i<=$max_tries;$i++) {
146 #     print "$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber\n";
147     push @borrowers,"$baseurl/members/member.pl?member=jean";
148 }
149 $b2->add_run($run2);
150 $b->add_run($run2);
151
152 # send HTTP request sequences to server and time responses
153 $ro = $b2->execute;
154
155 print ("\t".$b2->total_time."ms\t".(1000*$b2->total_requests/$b2->total_time)." borrowers/sec\n");
156
157 my $b2 = HTTPD::Bench::ApacheBench->new;
158 $b2->concurrency( $concurrency );
159
160 print "Load testing patron search page";
161 for (my $i=1;$i<=$max_tries;$i++) {
162 #     print "$baseurl/members/moremember.pl?borrowernumber=$rand_borrowernumber\n";
163     push @borrowers,"$baseurl/members/member.pl?quicksearch=1&surname=A";
164 }
165 $b2->add_run($run2);
166 $b->add_run($run2);
167
168 # send HTTP request sequences to server and time responses
169 $ro = $b2->execute;
170 print ("\t".$b2->total_time."ms\t".(1000*$b2->total_requests/$b2->total_time)." borrowers/sec\n");
171 #
172 # issue (& then return) books
173 #
174 my $b3 = HTTPD::Bench::ApacheBench->new;
175 $b3->concurrency( $concurrency );
176 my $b4 = HTTPD::Bench::ApacheBench->new;
177 $b4->concurrency( $concurrency );
178
179 my @issues;
180 my @returns;
181 print "Load testing circulation transaction (checkouts)";
182 $sth = $dbh->prepare("SELECT barcode FROM items WHERE itemnumber=?");
183 my $sth2 = $dbh->prepare("SELECT borrowernumber FROM borrowers WHERE borrowernumber=?");
184 for (my $i=1;$i<=$max_tries;$i++) {
185     my $rand_borrowernumber;
186     # check that the borrowernumber exist
187     until ($rand_borrowernumber) {
188         $rand_borrowernumber = int(rand($borrowernumber_max)+1);
189         $sth2->execute($rand_borrowernumber);
190         ($rand_borrowernumber) = $sth2->fetchrow;
191     }
192     # find a barcode & check it exists
193     my $rand_barcode;
194     until ($rand_barcode) {
195         my $rand_itemnumber = int(rand($itemnumber_max)+1);
196         $sth->execute($rand_itemnumber);
197         ($rand_barcode) = $sth->fetchrow();
198     }
199     print "borrowernumber=$rand_borrowernumber&barcode=$rand_barcode\n";
200     push @issues,"$baseurl/circ/circulation.pl?borrowernumber=$rand_borrowernumber&barcode=$rand_barcode&issueconfirmed=1";
201     push @returns,"$baseurl/circ/returns.pl?barcode=$rand_barcode";
202 }
203 my $run3 = HTTPD::Bench::ApacheBench::Run->new
204     ({ urls => \@issues,
205        cookies => [$cookie],
206     });
207 $b3->add_run($run3);
208 $b->add_run($run3);
209
210 # send HTTP request sequences to server and time responses
211 $ro = $b3->execute;
212 # calculate hits/sec
213 print ("\t".$b3->total_time."ms\t".(1000*$b3->total_requests/$b3->total_time)." checkouts/sec\n");
214
215 print "Load testing circulation transaction (checkins)";
216 my $run4 = HTTPD::Bench::ApacheBench::Run->new
217     ({ urls => \@returns,
218        cookies => [$cookie],
219     });
220 $b4->add_run($run4);
221 $b->add_run($run4);
222
223 # send HTTP request sequences to server and time responses
224 $ro = $b4->execute;
225 # calculate hits/sec
226 print ("\t".$b4->total_time."ms\t".(1000*$b4->total_requests/$b4->total_time)." checkins/sec\n");
227
228 print "Load testing all transactions at once";
229 $ro = $b->execute;
230 print ("\t".$b->total_time."ms\t".(1000*$b->total_requests/$b->total_time)." operations/sec\n");