build_automation/cloudberry/scripts/parse-results.pl (111 lines of code) (raw):

#!/usr/bin/env perl # -------------------------------------------------------------------- # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to You under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of the # License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # -------------------------------------------------------------------- # # Script: parse_results.pl # Description: Processes Cloudberry test output to extract statistics # and results. # Analyzes test log files to determine: # 1. Overall test status (pass/fail) # 2. Total number of tests run # 3. Number of passed, failed, and ignored tests # 4. Names of failed and ignored tests # 5. Validates test counts for consistency # Results are written to a file for shell script processing. # # Arguments: # log-file Path to test log file (required) # # Input File Format: # Expects test log files containing one of the following summary formats: # - "All X tests passed." # - "Y of X tests failed." # - "X of Y tests passed, Z failed test(s) ignored." # - "X of Y tests failed, Z of these failures ignored." # # And failed or ignored test entries in format: # - "test_name ... FAILED" # - "test_name ... failed (ignored)" # # Output File (test_results.txt): # Environment variable format: # STATUS=passed|failed # TOTAL_TESTS=<number> # FAILED_TESTS=<number> # PASSED_TESTS=<number> # IGNORED_TESTS=<number> # FAILED_TEST_NAMES=<comma-separated-list> # IGNORED_TEST_NAMES=<comma-separated-list> # # Prerequisites: # - Read access to input log file # - Write access to current directory # - Perl 5.x or higher # # Exit Codes: # 0 - All tests passed, or only ignored failures occurred # 1 - Some non-ignored tests failed # 2 - Parse error or cannot access files # # Example Usage: # ./parse_results.pl test_output.log # # Error Handling: # - Validates input file existence and readability # - Verifies failed and ignored test counts match found entries # - Reports parsing errors with detailed messages # # -------------------------------------------------------------------- use strict; use warnings; # Exit codes use constant { SUCCESS => 0, TEST_FAILURE => 1, PARSE_ERROR => 2 }; # Get log file path from command line argument my $file = $ARGV[0] or die "Usage: $0 LOG_FILE\n"; print "Parsing test results from: $file\n"; # Check if file exists and is readable unless (-e $file) { print "Error: File does not exist: $file\n"; exit PARSE_ERROR; } unless (-r $file) { print "Error: File is not readable: $file\n"; exit PARSE_ERROR; } # Open and parse the log file open(my $fh, '<', $file) or do { print "Cannot open log file: $! (looking in $file)\n"; exit PARSE_ERROR; }; # Initialize variables my ($status, $total_tests, $failed_tests, $ignored_tests, $passed_tests) = ('', 0, 0, 0, 0); my @failed_test_list = (); my @ignored_test_list = (); while (<$fh>) { # Match the summary lines if (/All (\d+) tests passed\./) { $status = 'passed'; $total_tests = $1; $passed_tests = $1; } elsif (/(\d+) of (\d+) tests passed, (\d+) failed test\(s\) ignored\./) { $status = 'passed'; $passed_tests = $1; $total_tests = $2; $ignored_tests = $3; } elsif (/(\d+) of (\d+) tests failed\./) { $status = 'failed'; $failed_tests = $1; $total_tests = $2; $passed_tests = $2 - $1; } elsif (/(\d+) of (\d+) tests failed, (\d+) of these failures ignored\./) { $status = 'failed'; $failed_tests = $1 - $3; $ignored_tests = $3; $total_tests = $2; $passed_tests = $2 - $1; } # Capture failed tests if (/^(?:\s+|test\s+)(\S+)\s+\.\.\.\s+FAILED\s+/) { push @failed_test_list, $1; } # Capture ignored tests if (/^(?:\s+|test\s+)(\S+)\s+\.\.\.\s+failed \(ignored\)/) { push @ignored_test_list, $1; } } # Close the log file close $fh; # Validate failed test count matches found test names if ($status eq 'failed' && scalar(@failed_test_list) != $failed_tests) { print "Error: Found $failed_tests failed tests in summary but found " . scalar(@failed_test_list) . " failed test names\n"; print "Failed test names found:\n"; foreach my $test (@failed_test_list) { print " - $test\n"; } exit PARSE_ERROR; } # Validate ignored test count matches found test names if ($ignored_tests != scalar(@ignored_test_list)) { print "Error: Found $ignored_tests ignored tests in summary but found " . scalar(@ignored_test_list) . " ignored test names\n"; print "Ignored test names found:\n"; foreach my $test (@ignored_test_list) { print " - $test\n"; } exit PARSE_ERROR; } # Write results to the results file open my $result_fh, '>', 'test_results.txt' or die "Cannot write to results file: $!\n"; print $result_fh "STATUS=$status\n"; print $result_fh "TOTAL_TESTS=$total_tests\n"; print $result_fh "PASSED_TESTS=$passed_tests\n"; print $result_fh "FAILED_TESTS=$failed_tests\n"; print $result_fh "IGNORED_TESTS=$ignored_tests\n"; if (@failed_test_list) { print $result_fh "FAILED_TEST_NAMES=" . join(',', @failed_test_list) . "\n"; } if (@ignored_test_list) { print $result_fh "IGNORED_TEST_NAMES=" . join(',', @ignored_test_list) . "\n"; } close $result_fh; # Print to stdout for logging print "Test Results:\n"; print "Status: $status\n"; print "Total Tests: $total_tests\n"; print "Failed Tests: $failed_tests\n"; print "Ignored Tests: $ignored_tests\n"; print "Passed Tests: $passed_tests\n"; if (@failed_test_list) { print "Failed Test Names:\n"; foreach my $test (@failed_test_list) { print " - $test\n"; } } if (@ignored_test_list) { print "Ignored Test Names:\n"; foreach my $test (@ignored_test_list) { print " - $test\n"; } } # Exit with appropriate code if ($status eq 'passed') { exit SUCCESS; } elsif ($status eq 'failed') { exit TEST_FAILURE; } else { exit PARSE_ERROR; }