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