view release on metacpan or search on metacpan
checking prerequisites...
requires:
! LWP::Parallel::UserAgent is not installed
- run below command to install any dependent modules.
you need a internet connection for this.
perl Build installdeps
[*] if you get "Net::SSLeay" installation error while installing
'LWP::Parallel::Useragent'
= install following packages based on your Linux flavour
- For Debian based (e.g. Ubuntu ) run below command
sudo apt-get install libssl-dev
- For RPM based ( e.g RHEL, CentOS) run below command
yum -y install openssl-devel
===================================================
lib/APP/REST/ParallelMyUA.pm view on Meta::CPAN
use base qw(LWP::Parallel::UserAgent Exporter);
our @EXPORT = @LWP::Parallel::UserAgent::EXPORT_OK;
$| = 1; #make the pipe hot
$Data::Dumper::Indent = 1;
=head1 NAME
APP::REST::ParallelMyUA -
provide a subclassed UserAgent to override on_connect, on_failure and
on_return methods
=head1 VERSION
Version 0.03
=cut
our $VERSION = '0.03';
lib/APP/REST/ParallelMyUA.pm view on Meta::CPAN
#print time,"Connecting to ", $request->url, "\n";
print STDERR ".";
$entry->{tick}->{start} = time;
}
=head2 on_failure
on_failure gets called whenever a connection fails right away
(either we timed out, or failed to connect to this address before,
or it's a duplicate). Please note that non-connection based
errors, for example requests for non-existant pages, will NOT call
on_failure since the response from the server will be a well
formed HTTP response!
=cut
sub on_failure {
my ( $self, $request, $response, $entry ) = @_;
print "Failed to connect to ", $request->url, "\n\t", $response->code, ", ",
$response->message, "\n"
if $response;
lib/APP/REST/ParallelMyUA.pm view on Meta::CPAN
if ( $response->is_success ) {
#print "\n\nWoa! Request to ",$request->url," returned code ", $response->code,
# ": ", $response->message, "\n";
#print $response->content;
} else {
#print "\n\nBummer! Request to ",$request->url," returned code ", $response->code,
# ": ", $response->message, "\n";
#print $response->error_as_HTML;
}
return;
}
1;
=head1 AUTHOR
Mithun Radhakrishnan, C<< <rkmithun at cpan.org> >>
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
use Data::Dumper;
use HTTP::Request;
use Time::HiRes qw( time sleep );
use File::Path;
use Cwd;
use LWP::UserAgent;
use APP::REST::ParallelMyUA;
use constant LOG_FILE => 'rest_client.log';
use constant ERR_LOG_FILE => 'rest_client_error.log';
use constant LINE => '=' x 50;
$| = 1; #make the pipe hot
$Data::Dumper::Indent = 1;
=head1 NAME
APP::REST::RestTestSuite - Suite for testing restful web services
=head1 VERSION
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
my $suite = APP::REST::RestTestSuite->new();
$suite->execute_test_cases( $suite->get_test_cases() );
my ( $cases_in_config, $executed, $skipped, $passed, $failed ) =
$suite->get_result_summary();
#OR
use APP::REST::RestTestSuite;
# overrides the default config and log file paths
my $suite = APP::REST::RestTestSuite->new(
REST_CONFIG_FILE => <config file>,
LOG_FILE_PATH => <path>,
);
$suite->execute_test_cases( $suite->get_test_cases() );
my ( $cases_in_config, $executed, $skipped, $passed, $failed ) =
$suite->get_result_summary();
=head1 DESCRIPTION
APP::REST::RestTestSuite object is instantiated with the data in config file.
Default config file format is defined in __DATA__ and that can be overridden
by passing the config file as an argument to the class.
Default LOG file path is the current working directory of the script which
calls this module
=head1 SUBROUTINES/METHODS
=head2 new
Object Constructor
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
=cut
sub get_log_file_handle {
my ( $self, %args ) = @_;
return $self->{file}->{log_file_handle};
}
=head2 get_err_log_file_handle
=cut
sub get_err_log_file_handle {
my ( $self, %args ) = @_;
return $self->{file}->{err_log_file_handle};
}
=head2 get_config_file_handle
=cut
sub get_config_file_handle {
my ( $self, %args ) = @_;
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
}
=head2 validate_test_cases
=cut
sub validate_test_cases {
my ($self) = shift;
my $err = undef;
unless (@_) {
$err = "There is no test cases defined to execute.\n";
} elsif ( ( (@_) % 2 ) == 1 ) {
$err =
"Test cases are not properly configured in '"
. $self->get_config_file()
. "'\nDefine test cases properly.\nPlease see the README file for more info.\n";
}
return $err if ($err);
my %test_cases = @_;
my @spec = sort qw(
test_case
uri
request_content_type
request_method
request_body
response_status
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
#below two are not mandatory for a test case as of now; if required add them to above array
# response_header
# response_body
foreach my $count ( sort { $a <=> $b } keys(%test_cases) ) {
my $tc = $test_cases{$count};
my @keys = sort keys %{$tc};
no warnings;
$err .= "Test case '$tc->{test_case}' not properly defined\n"
unless ( _compare_arrays( \@spec, \@keys ) );
}
$err .= "Please see the README file to see the correct format.\n" if ($err);
return $err;
}
=head2 execute_test_cases
=cut
sub execute_test_cases {
my ($self) = shift;
#expects an hash with keys as test case number and value as hash ref with test
#specification; validate that before trying to execute them.
my $err = $self->validate_test_cases(@_);
die "ERROR: $err\n" if ($err);
my %test_cases = @_;
my $ua = LWP::UserAgent->new;
$ua->agent("RTAT/$VERSION");
$ua->timeout(90); # in seconds
$ua->default_header('Accept' => '*/*'); # to get cross platform support
my ( $config, $total, $total_response_time, $skip, $pass, $fail ) = (0) x 6;
my ( $uri, $method, $req_content_type, $req_body, $status ) = (undef) x 5;
my ( $request, $response ) = (undef) x 2;
my ( $username, $password ) = (undef) x 2;
$username = $self->{username};
$password = $self->{password};
my $fh = $self->get_log_file_handle();
my $err_fh = $self->get_err_log_file_handle();
if ( $self->{html_log_required}
&& ( $self->{html_log_required} =~ /yes/i ) )
{
print $fh
qq|<HTML> <HEAD> <TITLE>LOG for $self->{endpoint}</TITLE> </HEAD>|
. qq|<BODY><textarea rows="999999" cols="120" style="border:none;">|;
print $err_fh
qq|<HTML> <HEAD> <TITLE>ERROR LOG for $self->{endpoint}</TITLE> </HEAD>|
. qq|<BODY><textarea rows="999999" cols="120" style="border:none;">|;
}
print STDERR "\nTest Suite executed on $self->{endpoint}\n";
print $fh "\nTest Suite executed on $self->{endpoint}\n";
print $err_fh "\nTest Suite executed on $self->{endpoint}\n";
foreach my $count ( sort { $a <=> $b } keys(%test_cases) ) {
my $tc = $test_cases{$count};
$config++;
print $fh "\n", LINE, "\n";
if ( $tc->{execute} && ( $tc->{execute} =~ /no/i ) ) {
print $fh "\nSkipping Test case $count => $tc->{test_case} \n";
$skip++;
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
$tc->{response_content_type};
#my $respose_content_type = $response->{_headers}->content_type;
my $respose_content_type = $response->header('Content-Type');
unless ( defined $respose_content_type ) {
$failed = 1;
} elsif ( $expected_response_content_type !~
m/$respose_content_type/ )
{
$failed = 1;
print $err_fh "\n", LINE, "\n";
print $err_fh
"Executing Test case $count => $tc->{test_case}";
print $err_fh
"\n*********ATTENTION CONTENT TYPE ERROR ******";
print $err_fh
"\n\nExpected content_type is $expected_response_content_type\n";
print $err_fh
"content_type recieved in response is $respose_content_type\n";
print $err_fh
"\n*********ATTENTION CONTENT TYPE ERROR ******";
$self->_print_logs(
fh => $err_fh,
uri => $uri,
method => $method,
req_body => $req_body,
);
$self->_print_logs(
fh => $err_fh,
res => $response,
exec_time => $exec_time,
);
}
}
($failed) ? $fail++ : $pass++;
} else {
$fail++;
print $err_fh "\n", LINE, "\n";
print $err_fh "Executing Test case $count => $tc->{test_case}";
$self->_print_logs(
fh => $err_fh,
uri => $uri,
method => $method,
req_body => $req_body,
);
$self->_print_logs(
fh => $err_fh,
res => $response,
exec_time => $exec_time,
);
}
}
#convert milli seconds to seconds for total_exec_time
$total_response_time = sprintf( "%.2f", $total_response_time / 1000 );
my $avg_response_time =
sprintf( "%.2f", ( $total_response_time * 1000 ) / $total );
print STDERR "\nComplete test case report is in $self->{file}->{log_file}";
print STDERR
"\nFailed test case report is in $self->{file}->{err_log_file}\n\n";
print STDERR
"Response time of $total web service calls => [$total_response_time seconds]\n";
print STDERR
"Average response time of a web service => [$avg_response_time milli seconds]\n\n";
print $fh
"Response time of $total web service calls => [$total_response_time seconds]\n";
print $fh
"Average response time of a web service => [$avg_response_time milli seconds]\n\n";
if ( $self->{html_log_required}
&& ( $self->{html_log_required} =~ /yes/i ) )
{
print $fh qq|</textarea></BODY></HTML>|;
print $err_fh qq|</textarea></BODY></HTML>|;
}
$self->{test_result_log} = {
test_cases_in_config => $config,
test_cases_exececuted => $total,
test_cases_skipped => $skip,
test_cases_passed => $pass,
test_cases_failed => $fail,
};
close($fh);
close($err_fh);
}
=head2 execute_test_cases_in_parallel
=cut
sub execute_test_cases_in_parallel {
my ($self) = shift;
#Code expects an hash with keys as test case number and value as hash ref with test
#specification; validate that before trying to execute them.
my $err = $self->validate_test_cases(@_);
die "ERROR: $err\n" if ($err);
my %test_cases = @_;
# use my customized user agent for parallel invokes
my $pua = APP::REST::ParallelMyUA->new();
$pua->agent("RTAT/$VERSION");
$pua->in_order(1); # handle requests in order of registration
$pua->duplicates(0); # ignore duplicates
$pua->timeout(60); # in seconds
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
$total++;
}
print STDERR "\nRequesting [$total] web services together.\n";
foreach my $req (@reqs) {
# register all requests and wait for them to finish
if ( my $res = $pua->register($req) ) {
print STDERR $res->error_as_HTML;
}
}
print STDERR "Receiving response from web services. Please wait..!\n";
# will return once all forked web services are either completed or timeout
my $entries = $pua->wait();
print STDERR "\n\n";
foreach ( keys %$entries ) {
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
sub _init_log_file_handle {
my ( $self, %args ) = @_;
$self->_init_log_files(%args)
; #Make compatible with windows and linux logging
my $file = $self->{file};
$file->{log_file_handle} =
$self->_open_fh( FILE => $file->{log_file}, MODE => 'WRITE' );
$file->{err_log_file_handle} =
$self->_open_fh( FILE => $file->{err_log_file}, MODE => 'WRITE' );
$self->{file} = $file;
}
sub _init_read_config {
my ( $self, %args ) = @_;
my $fh = $self->get_config_file_handle();
my @buffer = ();
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
} else {
$separator = '/';
}
my $log_path = $args{LOG_FILE_PATH} || getcwd() || $ENV{PWD};
my $log_dir = $log_path . $separator . 'LOG';
eval { mkpath( $log_dir, 0, 0755 ) unless ( -d $log_dir ); };
if ($@) {
my $err = $@;
$err =~ s/line\s+\d+//g;
die qq|Unable to create LOG directory ERROR: $err\n|;
}
my $log_file = join(
$separator,
(
$log_dir,
(
$self->{html_log_required}
&& ( $self->{html_log_required} =~ /yes/i )
)
? LOG_FILE
. ".html"
: LOG_FILE
)
);
my $error_log_file = join(
$separator,
(
$log_dir,
(
$self->{html_log_required}
&& ( $self->{html_log_required} =~ /yes/i )
)
? ERR_LOG_FILE
. ".html"
: ERR_LOG_FILE
)
);
$self->{file}->{log_file} = $log_file;
$self->{file}->{err_log_file} = $error_log_file;
}
sub _open_fh {
my ( $self, %args ) = @_;
my ( $fh, $err ) = (undef) x 2;
my $file = $args{FILE};
my $mode = $args{MODE};
if ( $mode =~ m/READ/i ) {
open( $fh, '<', "$file" ) or ( $err = 'yes' );
} elsif ( $mode =~ m/WRITE/i ) {
open( $fh, '>', "$file" ) or ( $err = 'yes' );
} elsif ( $mode =~ m/APPEND/i ) {
open( $fh, '>>', "$file" ) or ( $err = 'yes' );
}
if ($err) {
die qq|\nUnable to open file '$file' for $mode\nERROR: $!\n|;
}
return $fh;
}
sub _trim($) {
return unless ( $_[0] );
lib/APP/REST/RestTestSuite.pm view on Meta::CPAN
406 : Requested representation not available for the resource.
408 : Request has timed out.
409 : State of the resource doesn't permit request.
410 : The URI used to refer to a resource.
411 : The server needs to know the size of the entity body and it should be specified in the Content Length header.
412 : Operation not completed because preconditions were not met.
413 : The representation was too large for the server to handle.
414 : The URI has more than 2k characters.
415 : Representation not supported for the resource.
416 : Requested range not satisfiable.
500 : Internal server error.
501 : Requested HTTP operation not supported.
502 : Backend service failure (data store failure).
505 : HTTP version not supported.
############################
#END_HTTP_CODE_DEF
############################
####################
#END_OF_CONFIG_FILE
####################