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.052';
6 3     3   971 use 5.010;
  3         11  
7              
8 3     3   14 use strict;
  3         7  
  3         60  
9 3     3   12 use warnings;
  3         6  
  3         135  
10              
11 3     3   19 use Carp qw{confess cluck};
  3         3  
  3         170  
12 3     3   16 use Scalar::Util qw{blessed};
  3         13  
  3         175  
13              
14             use Types::Standard
15 3     3   20 qw( slurpy ClassName Object Str Int Bool HashRef ArrayRef Maybe Optional);
  3         7  
  3         31  
16 3     3   4367 use Type::Params qw( compile );
  3         6  
  3         21  
17              
18 3     3   676 use TestRail::API;
  3         6  
  3         56  
19 3     3   12 use TestRail::Utils;
  3         5  
  3         43  
20 3     3   1686 use TestRail::Utils::Find;
  3         11  
  3         1651  
21              
22             sub pickAndLockTest {
23 11     11 1 34941 state $check = compile( HashRef, Optional [ Maybe [Object] ] );
24 11         4487 my ( $opts, $tr ) = $check->(@_);
25 11 50       325 confess("TestRail handle must be provided as argument 2")
26             unless blessed($tr) eq 'TestRail::API';
27              
28 11         44 my ( $project, $plan, $run ) =
29             TestRail::Utils::getRunInformation( $tr, $opts );
30              
31 11         19 my $status_ids;
32              
33             # Process statuses
34             @$status_ids =
35 11         46 $tr->statusNamesToIds( $opts->{'lockname'}, 'untested', 'retest' );
36 11         50 my ( $lock_status_id, $untested_id, $retest_id ) = @$status_ids;
37              
38 11         35 my $cases = $tr->getTests( $run->{'id'} );
39              
40             #Filter by case types
41 11 100       41 if ( $opts->{'case-types'} ) {
42             my @case_types =
43 8         28 map { my $cdef = $tr->getCaseTypeByName($_); $cdef->{'id'} }
  8         26  
44 8         9 @{ $opts->{'case-types'} };
  8         19  
45             @$cases = grep {
46 8         18 my $case_type_id = $_->{'type_id'};
  48         62  
47 48         51 grep { $_ eq $case_type_id } @case_types
  48         106  
48             } @$cases;
49             }
50              
51             # Limit to only non-locked and open cases
52             @$cases = grep {
53 11         19 my $tstatus = $_->{'status_id'};
  39         48  
54 39         49 scalar( grep { $tstatus eq $_ } ( $untested_id, $retest_id ) )
  78         138  
55             } @$cases;
56 11         37 @$cases = sort { $b->{'priority_id'} <=> $a->{'priority_id'} }
  15         31  
57             @$cases; #Sort by priority DESC
58              
59             # Filter by match options
60 11         40 @$cases = TestRail::Utils::Find::findTests( $opts, @$cases );
61              
62 11         23 my ( $title, $test );
63 11         25 while (@$cases) {
64 6         13 $test = shift @$cases;
65 6         16 $title = lockTest( $test, $lock_status_id, $opts->{'hostname'}, $tr );
66 6 50       14 last if $title;
67             }
68              
69 11 100       23 if ( !$title ) {
70 5         301 warn
71             "Failed to lock case! This probably means you don't have any cases left to lock.";
72 5         107 return 0;
73             }
74              
75             return {
76 6         68 'test' => $test,
77             'path' => $title,
78             'project' => $project,
79             'plan' => $plan,
80             'run' => $run
81             };
82             }
83              
84             sub lockTest {
85 7     7 1 12 state $check = compile( HashRef, Int, Str, Object );
86 7         1396 my ( $test, $lock_status_id, $hostname, $handle ) = $check->(@_);
87              
88             my $res = $handle->createTestResults(
89             $test->{id},
90 7         167 $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         260 my $results = $handle->getTestResults( $test->{id}, 100 );
98              
99             #Remember, we're returned results from newest to oldest...
100 7         9 my $next_one = 0;
101 7         15 foreach my $result (@$results) {
102 14 100       30 unless ( $result->{'status_id'} == $lock_status_id ) {
103              
104             #Clearly no lock conflict going on here if next_one is true
105 6 50       13 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       19 if ( $result->{id} == $res->{'id'} ) {
112 7         8 $next_one = 1;
113 7         13 next;
114             }
115              
116 1 50       36 if ($next_one) {
117              
118             #If we got this far, a lock conflict occurred. Try the next one.
119 1         33 warn "Lock conflict detected. Try again...\n";
120 1         15 return 0;
121             }
122             }
123              
124             #Prefer full titles (match mode)
125             return defined( $test->{'full_title'} )
126             ? $test->{'full_title'}
127 6 100       41 : $test->{'title'}
    50          
128             if $next_one;
129 0           return -1;
130             }
131              
132             1;
133              
134             __END__