| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- #!/usr/bin/env perl
- # ABSTRACT: Upload your TAP results to TestRail after they've finished
- # PODNAME: testrail-report
- =head1 SYNOPSIS
- testrail-report [OPTIONS] tapfile
- prove -v sometest.t > results.tap && testrail-report [OPTIONS] results.tap
- prove -v sometest.t | testrail-report [OPTIONS]
- prove -PTestRail='http://some.testlink.install/,someUser,somePassword,someProject,someRun,0,step_results' sometest.t
- =head1 DESCRIPTION
- testrail-report - report raw TAP results to a TestRail install
- USAGE:
- =head2 PARAMETERS:
- =head3 MANDATORY PARAMETERS
- --project [someproject] : associate results (if any) with theprovided project name.
- --run [somerun] : associates results (if any) with the provided run name.
- IF none of these options are provided, you will be asked to type
- these in as needed, supposing you are not redirecting input
- (such as piping into this command).
- =head3 SEMI-OPTIONAL PARAMETERS
- --plan [someplan] : look for the provided run name within the provided plan.
- --config [someconfig] : filter run by the provided configuration.
- This option can be passed multiple times for detailed filtering.
- Test plans can have runs with the same name, but different configurations, which is understandably confusing.
- You can do the same outside of plans, and without configurations; but doing so is ill advised, and the only option from there is to use IDs.
- So, try not to do that if you want to use this tool, and want sanity in your Test management system.
- The way around this is to specify what plan and configuration you want to set results for.
- This should provide sufficient uniqueness to get to any run using names.
- =head3 CONFIG OVERRIDES
- In your $HOME (or the current directory, if your system has no concept of a home directory), put a file called .testrailrc with key=value
- syntax separated by newlines. Valid Keys are: apiurl,user,password
- =head3 CONFIG OPTIONS
- These override the config, if present. If neither are used, you will be prompted.
- --apiurl [url] : full URL to get to TestRail index document
- --password [key] : Your TestRail Password.
- --user [name] : Your TestRail User Name.
- =head3 BEHAVIOR
- --case-ok : Whether to consider each OK to correspond to a test in TestRail
- --step-results [name] : 'System Name' of a 'step_results' type field to set for your tests.
- These options are mutually exclusive. If neither is set, the
- overall result of the test will be used as the pass/fail for the test.
- =head3 RESULT OPTIONS
- --version : String describing the version of the system under test.
- =head2 PROVE PLUGIN:
- passing -PTestRail=apiurl,user,pass,project,run to prove will
- automatically upload your test results while the test is running if
- real-time results are desired.
- See L<App::Prove::Plugin::TestRail> for more information.
- =head2 REQUIREMENTS:
- Your TestRail install must have 3 custom statuses with the internal
- names 'skip', 'todo_pass', and 'todo_fail', to represent those
- states which TAP can have.
- =head2 TESTING OPTIONS:
- --mock don't do any real HTTP requests.
- =cut
- use strict;
- use warnings;
- use Getopt::Long;
- use Term::ANSIColor 2.01 qw(colorstrip);
- use Test::Rail::Parser;
- use IO::Interactive::Tiny ();
- use File::HomeDir qw{my_home};
- print "testrail-report\n----------------------\n";
- sub help {
- print "testrail-report - report raw TAP results to a TestRail install
- USAGE:
- testrail-report [OPTIONS] tapfile
- prove -v sometest.t > results.tap && testrail-report [OPTIONS] \\
- results.tap
- prove -v sometest.t | testrail-report [OPTIONS]
- prove -PTestRail='http://some.testlink.install/','someUser',\\
- 'somePassword' sometest.t
- PARAMETERS:
- [MANDATORY PARAMETERS]
- --project [someproject] : associate results (if any) with the
- provided project name.
- --run [somerun] : associates results (if any) with the provided run
- name.
- IF none of these options are provided, you will be asked to type
- these in as needed, supposing you are not redirecting input
- (such as piping into this command).
- [SEMI-OPTIONAL PARAMETERS]
- --plan [someplan] : look for the provided run name within
- the provided plan.
- --configs [someconfigs] : filter run by the provided configuration.
- This option can be passed multiple times for detailed filtering.
- Test plans can have runs with the same name, but different
- configurations, which is understandably confusing. You can do the
- same outside of plans, and without configurations; but doing so is
- ill-advised, and the only option from there is to use IDs. So, try
- not to do that if you want to use this tool, and want sanity in your
- Test Management System.
- The way around this is to specify what plan and configuration
- you want to set results for. This should provide sufficient
- uniqueness to get to any run using words.
- [CONFIG OVERRIDES]
- In your \$HOME, (or the current directory, if your system has no
- concept of a home directory) put a file called .testrailrc with
- key=value syntax separated by newlines.
- Valid Keys are: apiurl,user,password
- [CONFIG OPTIONS] - These override the config, if present.
- If neither are used, you will be prompted.
- --apiurl [url] : full URL to get to TestRail index document
- --password [key] : Your TestRail Password.
- --user [name] : Your TestRail User Name.
- [BEHAVIOR]
- --case-ok : Whether to consider each OK to correspond to
- a test in TestRail
- --step-results [name] : 'System Name' of a 'step_results' type field
- to set for your tests.
- These options are mutually exclusive. If neither is set, the
- overall result of the test will be used as the pass/fail for the test.
- [RESULT OPTIONS]
- --version : String describing the version of the system under test.
- PROVE PLUGIN:
- passing -PTestRail=apiurl,user,pass,project,run to prove will
- automatically upload your test results while the test is running if
- real-time results are desired.
- See App::Prove::Plugin::TestRail for more information.
- REQUIREMENTS:
- Your TestRail install must have 3 custom statuses with the internal
- names 'skip', 'todo_pass', and 'todo_fail', to represent those
- states which TAP can have.
- TESTING OPTIONS:
- --mock don't do any real HTTP requests.
- ";
- exit 0;
- }
- sub userInput {
- $| = 1;
- my $rt = <STDIN>;
- chomp $rt;
- return $rt;
- }
- sub parseConfig {
- my $homedir = shift;
- my $results = {};
- my $arr =[];
- open(my $fh, '<', $homedir . '/.testrailrc') or return (undef,undef,undef);#couldn't open!
- while (<$fh>) {
- chomp;
- @$arr = split(/=/,$_);
- if (scalar(@$arr) != 2) {
- warn("Could not parse $_ in tlreport config\n");
- next;
- }
- $results->{lc($arr->[0])} = $arr->[1];
- }
- close($fh);
- return ($results->{'apiurl'},$results->{'password'},$results->{'user'});
- }
- #Main loop------------
- my ($help,$apiurl,$user,$password,$project,$run,$case_per_ok,$step_results,$mock,$configs,$plan,$version);
- #parse switches
- GetOptions(
- 'run=s' => \$run,
- 'apiurl=s' => \$apiurl,
- 'password=s' => \$password,
- 'user=s' => \$user,
- 'project=s' => \$project,
- 'case-ok' => \$case_per_ok,
- 'step-results=s' => \$step_results,
- 'mock' => \$mock,
- 'config=s@' => \$configs,
- 'plan=s' => \$plan,
- 'version=s' => \$version,
- 'help' => \$help
- );
- if ($help) { help(); }
- #Parse config file if we are missing api url/key or user
- my $homedir = my_home() || '.';
- if (-e $homedir . '/.testrailrc' && (!$apiurl || !$password || !$user) ) {
- ($apiurl,$password,$user) = parseConfig($homedir);
- }
- #XXX not even close to optimized, don't slurp in the future
- #If argument is passed use it instead of stdin
- my $file = $ARGV[0];
- die "No Such File $file" if ($file && !-e $file);
- my ($fh,$fcontents,@files);
- if ($file) {
- open($fh,'<',$file);
- while (<$fh>) {
- $_ = colorstrip($_); #strip prove brain damage
- if ($_ =~ /(.*)\s\.\.$/) {
- #File marker from default prove
- unless ($_ =~ /^[ok|not ok] - /) {
- push(@files,$fcontents) if $fcontents;
- $fcontents = '';
- }
- }
- $fcontents .= $_;
- }
- close($fh);
- push(@files,$fcontents) if $fcontents;
- } else {
- #Just read STDIN, print help if no file was passed
- if (IO::Interactive::Tiny::is_interactive()) {
- print "ERROR: no file passed, and no data piped in! See --help for usage.\n";
- exit(1);
- }
- if ( !$run || !$apiurl || !$password || !$user || !$project ) {
- print "ERROR: Interactive mode not allowed when piping input. See --help for options.\n";
- exit(1);
- }
- while (<>) {
- $_ = colorstrip($_); #strip prove brain damage
- if ($_ =~ /(.*)\s\.\.$/) {
- #File marker from default prove
- unless ($_ =~ /^[ok|not ok] - /) {
- push(@files,$fcontents) if $fcontents;
- $fcontents = '';
- }
- }
- $fcontents .= $_;
- }
- help() if !$fcontents; #Nothing passed to stdin!
- push(@files,$fcontents) if $fcontents;
- }
- #Interrogate user if they didn't provide info
- if (!$apiurl) {
- print "Type the API endpoint url for your testLink install below:\n";
- $apiurl = userInput();
- }
- if (!$user) {
- print "Type your testLink user name below:\n";
- $user = userInput();
- }
- if (!$password) {
- print "Type the password for your testLink user below:\n";
- $password = userInput();
- }
- if (!$apiurl || !$password || !$user) {
- print "ERROR: api url, username and password cannot be blank.\n";
- exit 1;
- }
- #Interrogate user if they didn't provide info
- if (!$project) {
- print "Type the name of the project you are testing under:\n";
- $project = userInput();
- }
- # Interrogate user if options were not passed
- if (!$run) {
- print "Type the name of the existing run you would like to run against:\n";
- $run = userInput();
- }
- my $debug = 0;
- my $browser;
- if ($mock) {
- use Test::LWP::UserAgent::TestRailMock;
- $browser = $Test::LWP::UserAgent::TestRailMock::mockObject;
- $debug = 1;
- }
- my $result_options = undef;
- $result_options = {'version' => $version} if $version;
- my $tap;
- foreach my $phil (@files) {
- print "Processing $phil...\n";
- $tap = Test::Rail::Parser->new({
- 'tap' => $phil,
- 'apiurl' => $apiurl,
- 'user' => $user,
- 'pass' => $password,
- 'run' => $run,
- 'project' => $project,
- 'case_per_ok' => $case_per_ok,
- 'step_results' => $step_results,
- 'debug' => $debug,
- 'browser' => $browser,
- 'version' => $version,
- 'plan' => $plan,
- 'configs' => $configs,
- 'result_options' => $result_options,
- 'merge' => 1
- });
- $tap->run();
- }
- print "Done.\n";
- #all done
- 0;
- __END__
- =head1 SEE ALSO
- L<TestRail::API>
- L<App::Prove::Plugin::TestRail>
- L<TAP::Parser>
- L<File::HomeDir> for the finding of .testrailrc
- =head1 SPECIAL THANKS
- Thanks to cPanel Inc, for graciously funding the creation of this module.
|