APP-REST-RestTestSuite

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN


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
####################



( run in 0.686 second using v1.01-cache-2.11-cpan-49f99fa48dc )