File Coverage

blib/lib/TestRail/Utils/Lock.pm
Criterion Covered Total %
statement 77 79 97.4
branch 15 20 75.0
condition n/a
subroutine 12 12 100.0
pod 2 2 100.0
total 106 113 93.8


line stmt bran cond sub pod time code
1             # ABSTRACT: Pick high priority cases for execution and lock them via the test results mechanism.
2             # PODNAME: TestRail::Utils::Lock
3              
4             package TestRail::Utils::Lock;
5             $TestRail::Utils::Lock::VERSION = '0.051';
6 3     3   1103 use 5.010;
  3         11  
7              
8 3     3   17 use strict;
  3         7  
  3         60  
9 3     3   15 use warnings;
  3         16  
  3         90  
10              
11 3     3   31 use Carp qw{confess cluck};
  3         7  
  3         549  
12 3     3   23 use Scalar::Util qw{blessed};
  3         6  
  3         206  
13              
14             use Types::Standard
15 3     3   24 qw( slurpy ClassName Object Str Int Bool HashRef ArrayRef Maybe Optional);
  3         7  
  3         29  
16 3     3   4930 use Type::Params qw( compile );
  3         7  
  3         22  
17              
18 3     3   765 use TestRail::API;
  3         8  
  3         60  
19 3     3   14 use TestRail::Utils;
  3         9  
  3         50  
20 3     3   1626 use TestRail::Utils::Find;
  3         11  
  3         1899  
21              
22             sub pickAndLockTest {
23 11     11 1 47488 state $check = compile( HashRef, Optional [ Maybe [Object] ] );
24 11         5311 my ( $opts, $tr ) = $check->(@_);
25 11 50       395 confess("TestRail handle must be provided as argument 2")
26             unless blessed($tr) eq 'TestRail::API';
27              
28 11         43 my ( $project, $plan, $run ) =
29             TestRail::Utils::getRunInformation( $tr, $opts );
30              
31 11         21 my $status_ids;
32              
33             # Process statuses
34             @$status_ids =
35 11         46 $tr->statusNamesToIds( $opts->{'lockname'}, 'untested', 'retest' );
36 11         57 my ( $lock_status_id, $untested_id, $retest_id ) = @$status_ids;
37              
38 11         44 my $cases = $tr->getTests( $run->{'id'} );
39              
40             #Filter by case types
41 11 100       43 if ( $opts->{'case-types'} ) {
42             my @case_types =
43 8         29 map { my $cdef = $tr->getCaseTypeByName($_); $cdef->{'id'} }
  8         35  
44 8         15 @{ $opts->{'case-types'} };
  8         20  
45             @$cases = grep {
46 8         17 my $case_type_id = $_->{'type_id'};
  48         70  
47 48         65 grep { $_ eq $case_type_id } @case_types
  48         135  
48             } @$cases;
49             }
50              
51             # Limit to only non-locked and open cases
52             @$cases = grep {
53 11         24 my $tstatus = $_->{'status_id'};
  39         55  
54 39         49 scalar( grep { $tstatus eq $_ } ( $untested_id, $retest_id ) )
  78         184  
55             } @$cases;
56 11         35 @$cases = sort { $b->{'priority_id'} <=> $a->{'priority_id'} }
  15         36  
57             @$cases; #Sort by priority DESC
58              
59             # Filter by match options
60 11         46 @$cases = TestRail::Utils::Find::findTests( $opts, @$cases );
61              
62 11         27 my ( $title, $test );
63 11         27 while (@$cases) {
64 6         13 $test = shift @$cases;
65 6         20 $title = lockTest( $test, $lock_status_id, $opts->{'hostname'}, $tr );
66 6 50       19 last if $title;
67             }
68              
69 11 100       38 if ( !$title ) {
70 5         325 warn
71             "Failed to lock case! This probably means you don't have any cases left to lock.";
72 5         103 return 0;
73             }
74              
75             return {
76 6         60 'test' => $test,
77             'path' => $title,
78             'project' => $project,
79             'plan' => $plan,
80             'run' => $run
81             };
82             }
83              
84             sub lockTest {
85 7     7 1 14 state $check = compile( HashRef, Int, Str, Object );
86 7         1677 my ( $test, $lock_status_id, $hostname, $handle ) = $check->(@_);
87              
88             my $res = $handle->createTestResults(
89             $test->{id},
90 7         193 $lock_status_id,
91             "Test Locked by $hostname.\n
92             If this result is preceded immediately by another lock statement like this, please disregard it;
93             a lock collision occurred."
94             );
95              
96             #If we've got more than 100 lock conflicts, we have big-time problems
97 7         329 my $results = $handle->getTestResults( $test->{id}, 100 );
98              
99             #Remember, we're returned results from newest to oldest...
100 7         454 my $next_one = 0;
101 7         20 foreach my $result (@$results) {
102 14 100       37 unless ( $result->{'status_id'} == $lock_status_id ) {
103              
104             #Clearly no lock conflict going on here if next_one is true
105 6 50       15 last if $next_one;
106              
107             #Otherwise just skip it until we get to the test we locked
108 0         0 next;
109             }
110              
111 8 100       24 if ( $result->{id} == $res->{'id'} ) {
112 7         12 $next_one = 1;
113 7         14 next;
114             }
115              
116 1 50       5 if ($next_one) {
117              
118             #If we got this far, a lock conflict occurred. Try the next one.
119 1         39 warn "Lock conflict detected. Try again...\n";
120 1         19 return 0;
121             }
122             }
123              
124             #Prefer full titles (match mode)
125             return defined( $test->{'full_title'} )
126             ? $test->{'full_title'}
127 6 100       53 : $test->{'title'}
    50          
128             if $next_one;
129 0           return -1;
130             }
131              
132             1;
133              
134             __END__