mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
of: unittest: add program to process EXPECT messages
If unittest detects a problem it will print a warning or error message to the console. Unittest also triggers warning and error messages from other kernel code as a result of intentionally bad unittest data. This has led to confusion as to whether the triggered messages are an expected result of a test or whether there is a real problem that is independent of unittest. EXPECT messages were added to unittest to report each triggered message that is expected, resulting in verbose console output. scripts/dtc/of_unittest is a new program that processes the EXPECT messages to determine whether the triggered messages occurred and also removes the excess verbosity of the EXPECT messages. More information is available from 'scripts/dtc/of_unittest_expect --help'. Signed-off-by: Frank Rowand <frank.rowand@sony.com> Signed-off-by: Rob Herring <robh@kernel.org> Link: https://lore.kernel.org/r/20220201181413.2719955-1-frowand.list@gmail.com
This commit is contained in:
parent
4eb7b1339c
commit
8e4296c286
@ -24,7 +24,28 @@ from the unflattened device tree data structure. This interface is used by
|
||||
most of the device drivers in various use cases.
|
||||
|
||||
|
||||
2. Test-data
|
||||
2. Verbose Output (EXPECT)
|
||||
==========================
|
||||
|
||||
If unittest detects a problem it will print a warning or error message to
|
||||
the console. Unittest also triggers warning and error messages from other
|
||||
kernel code as a result of intentionally bad unittest data. This has led
|
||||
to confusion as to whether the triggered messages are an expected result
|
||||
of a test or whether there is a real problem that is independent of unittest.
|
||||
|
||||
'EXPECT \ : text' (begin) and 'EXPECT / : text' (end) messages have been
|
||||
added to unittest to report that a warning or error is expected. The
|
||||
begin is printed before triggering the warning or error, and the end is
|
||||
printed after triggering the warning or error.
|
||||
|
||||
The EXPECT messages result in very noisy console messages that are difficult
|
||||
to read. The script scripts/dtc/of_unittest_expect was created to filter
|
||||
this verbosity and highlight mismatches between triggered warnings and
|
||||
errors vs expected warnings and errors. More information is available
|
||||
from 'scripts/dtc/of_unittest_expect --help'.
|
||||
|
||||
|
||||
3. Test-data
|
||||
============
|
||||
|
||||
The Device Tree Source file (drivers/of/unittest-data/testcases.dts) contains
|
||||
@ -56,7 +77,7 @@ The assembly file is compiled into an object file (testcases.dtb.o), and is
|
||||
linked into the kernel image.
|
||||
|
||||
|
||||
2.1. Adding the test data
|
||||
3.1. Adding the test data
|
||||
-------------------------
|
||||
|
||||
Un-flattened device tree structure:
|
||||
@ -191,7 +212,7 @@ properties are updated to the live tree's node by calling the function
|
||||
update_node_properties().
|
||||
|
||||
|
||||
2.2. Removing the test data
|
||||
3.2. Removing the test data
|
||||
---------------------------
|
||||
|
||||
Once the test case execution is complete, selftest_data_remove is called in
|
||||
|
408
scripts/dtc/of_unittest_expect
Executable file
408
scripts/dtc/of_unittest_expect
Executable file
@ -0,0 +1,408 @@
|
||||
#!/usr/bin/perl
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright 2020, 2022 Sony Corporation
|
||||
#
|
||||
# Author: Frank Rowand
|
||||
|
||||
# This program is meant to be an aid to reading the verbose output of
|
||||
# on the console log that results from executing the Linux kernel
|
||||
# devicetree unittest (drivers/of/unitest.c).
|
||||
|
||||
$VUFX = "220201a";
|
||||
|
||||
use strict 'refs';
|
||||
use strict subs;
|
||||
|
||||
use Getopt::Long;
|
||||
use Text::Wrap;
|
||||
|
||||
# strip off everything before final "/"
|
||||
(undef, $script_name) = split(/^.*\//, $0);
|
||||
|
||||
# following /usr/include/sysexits.h
|
||||
$EX_OK=0;
|
||||
$EX_USAGE=64;
|
||||
|
||||
|
||||
#______________________________________________________________________________
|
||||
sub compare {
|
||||
my ($expect, $got) = @_;
|
||||
my $expect_next;
|
||||
my $expect_next_lit;
|
||||
my $got_next;
|
||||
my $type;
|
||||
|
||||
while ($expect) {
|
||||
|
||||
($expect_next, $type) = split(/<</, $expect);
|
||||
($type) = split(/>>/, $type);
|
||||
$expect =~ s/^.*?>>//; # '?' is non-greedy, minimal match
|
||||
|
||||
# literal, ignore all metacharacters when used in a regex
|
||||
$expect_next_lit = quotemeta($expect_next);
|
||||
|
||||
$got_next = $got;
|
||||
$got_next =~ s/^($expect_next_lit).*/\1/;
|
||||
$got =~ s/^$expect_next_lit//;
|
||||
|
||||
if ($expect_next ne $got_next) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($type eq "int") {
|
||||
if ($got =~ /^[+-]*[0-9]+/) {
|
||||
$got =~ s/^[+-]*[0-9]+//;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} elsif ($type eq "hex") {
|
||||
if ($got =~ /^(0x)*[0-9a-f]+/) {
|
||||
$got =~ s/^(0x)*[0-9a-f]+//;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} elsif ($type eq "") {
|
||||
if ($expect_next ne $got_next) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
$internal_err++;
|
||||
print "** ERROR: special pattern not recognized: <<$type>>, CONSOLE_LOG line: $.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# should not get here
|
||||
$internal_err++;
|
||||
print "** ERROR: $script_name internal error, at end of compare(), CONSOLE_LOG line: $.\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#______________________________________________________________________________
|
||||
sub usage {
|
||||
|
||||
# ***** when editing, be careful to not put tabs in the string printed:
|
||||
|
||||
print STDERR
|
||||
"
|
||||
usage:
|
||||
|
||||
$script_name CONSOLE_LOG
|
||||
|
||||
-h print program usage
|
||||
--help print program usage
|
||||
--hide-expect suppress output of EXPECTed lines
|
||||
--line-num report line number of CONSOLE_LOG
|
||||
--no-expect-stats do not report EXPECT statistics
|
||||
--no-strip-ts do not strip leading console timestamps
|
||||
--verbose do not suppress EXPECT begin and end lines
|
||||
--version print program version and exit
|
||||
|
||||
|
||||
Process a console log for EXPECTed test related messages to either
|
||||
highlight expected devicetree unittest related messages or suppress
|
||||
the messages. Leading console timestamps will be stripped.
|
||||
|
||||
Various unittests may trigger kernel messages from outside the
|
||||
unittest code. The unittest annotates that it expects the message
|
||||
to occur with an 'EXPECT \\ : text' (begin) before triggering the
|
||||
message, and an 'EXPECT / : text' (end) after triggering the message.
|
||||
|
||||
If an expected message does not occur, that will be reported.
|
||||
|
||||
For each expected message, the 'EXPECT \\ : text' (begin) and
|
||||
'EXPECT / : text' (end), 'text' will contain the message text.
|
||||
|
||||
If 'EXPECT \\' (begin) and 'EXPECT /' (end) lines do not contain
|
||||
matching 'text', that will be reported.
|
||||
|
||||
If EXPECT lines are nested, 'EXPECT /' (end) lines must be in the
|
||||
reverse order of the corresponding 'EXPECT \\' (begin) lines.
|
||||
|
||||
'EXPECT \\ : text' (begin) and 'EXPECT / : text' (end) lines can
|
||||
contain special patterns in 'text':
|
||||
|
||||
<<int>> matches: [+-]*[0-9]+
|
||||
<<hex>> matches: (0x)*[0-9a-f]+
|
||||
|
||||
'EXPECT \\' (begin) and 'EXPECT /' (end) lines are suppressed.
|
||||
|
||||
A prefix is added to every line of output:
|
||||
|
||||
'ok ' Line matches an enclosing EXPECT begin/end pair
|
||||
|
||||
'** ' Line reports $script_name warning or error
|
||||
|
||||
'-> ' Line reports start or end of the unittests
|
||||
|
||||
'>> ' Line reports a unittest test FAIL
|
||||
|
||||
' ' Lines that are not otherwise prefixed
|
||||
|
||||
Issues detected in CONSOLE_LOG are reported to STDOUT, not to STDERR.
|
||||
|
||||
Known Issues:
|
||||
|
||||
--line-num causes the CONSOLE_LOG line number to be printed in 4 columns.
|
||||
If CONSOLE_LOG contains more than 9999 lines then more columns will be
|
||||
used to report the line number for lines greater than 9999 (eg for
|
||||
lines 10000 - 99999, 5 columns will be used).
|
||||
";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#______________________________________________________________________________
|
||||
#______________________________________________________________________________
|
||||
|
||||
if (!GetOptions(
|
||||
"h" => \$help,
|
||||
"help" => \$help,
|
||||
"hide-expect" => \$hide_expect,
|
||||
"line-num" => \$print_line_num,
|
||||
"no-expect-stats" => \$no_expect_stats,
|
||||
"no-strip-ts" => \$no_strip_ts,
|
||||
"verbose" => \$verbose,
|
||||
"version" => \$version,
|
||||
)) {
|
||||
print STDERR "\n";
|
||||
print STDERR "ERROR processing command line options\n";
|
||||
print STDERR "\n";
|
||||
print STDERR "For help, type '$script_name --help'\n";
|
||||
print STDERR "\n";
|
||||
|
||||
exit $EX_OK;
|
||||
}
|
||||
|
||||
|
||||
if ($no_strip_ts) {
|
||||
$strip_ts = 1;
|
||||
$no_strip_ts = 0;
|
||||
} else {
|
||||
$strip_ts = 0;
|
||||
$no_strip_ts = 1;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if ($help){
|
||||
|
||||
&usage;
|
||||
|
||||
exit $EX_OK;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
if ($version) {
|
||||
print STDERR "\n$script_name $VUFX\n\n";
|
||||
print STDERR "\n";
|
||||
|
||||
exit $EX_OK;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if ($#ARGV != 0) {
|
||||
|
||||
# Limit input files to exactly one.
|
||||
#
|
||||
# 'while ($line = <ARGV>) {' in the code below supports multiple file
|
||||
# names on the command line, but the EXPECT statistics are reported
|
||||
# once for all input - it is not an expected use case to generate one
|
||||
# set of statistics for multiple input files.
|
||||
|
||||
print STDERR "\n";
|
||||
print STDERR "Required arguments: CONSOLE_LOG\n";
|
||||
print STDERR "\n";
|
||||
|
||||
exit $EX_USAGE;
|
||||
}
|
||||
|
||||
|
||||
#______________________________________________________________________________
|
||||
|
||||
# Patterns to match 'EXPECT \ : ' (begin) and 'EXPECT / : ' (end)
|
||||
#
|
||||
# $exp_* are used as regex match patterns,
|
||||
# so '\\\\' in $exp_begin matches a single '\'
|
||||
# quotemeta() does not do the right thing in this case
|
||||
#
|
||||
# $pr_fmt is the prefix that unittest prints for every message
|
||||
|
||||
$pr_fmt = "### dt-test ### ";
|
||||
$exp_begin = "${pr_fmt}EXPECT \\\\ : ";
|
||||
$exp_end = "${pr_fmt}EXPECT / : ";
|
||||
|
||||
|
||||
$line_num = "";
|
||||
$timestamp = "";
|
||||
|
||||
LINE:
|
||||
while ($line = <ARGV>) {
|
||||
|
||||
chomp $line;
|
||||
|
||||
$prefix = " "; ## 2 characters
|
||||
|
||||
|
||||
if ($strip_ts) {
|
||||
|
||||
$timestamp = $line;
|
||||
|
||||
if ($timestamp =~ /^\[\s*[0-9]+\.[0-9]*\] /) {
|
||||
($timestamp, $null) = split(/]/, $line);
|
||||
$timestamp = $timestamp . "] ";
|
||||
|
||||
} else {
|
||||
$timestamp = "";
|
||||
}
|
||||
}
|
||||
|
||||
$line =~ s/^\[\s*[0-9]+\.[0-9]*\] //;
|
||||
|
||||
|
||||
# ----- find EXPECT begin
|
||||
|
||||
if ($line =~ /^\s*$exp_begin/) {
|
||||
$data = $line;
|
||||
$data =~ s/^\s*$exp_begin//;
|
||||
push @begin, $data;
|
||||
|
||||
if ($verbose) {
|
||||
if ($print_line_num) {
|
||||
$line_num = sprintf("%4s ", $.);
|
||||
}
|
||||
printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
|
||||
}
|
||||
|
||||
next LINE;
|
||||
}
|
||||
|
||||
|
||||
# ----- find EXPECT end
|
||||
|
||||
if ($line =~ /^\s*$exp_end/) {
|
||||
$data = $line;
|
||||
$data =~ s/^\s*$exp_end//;
|
||||
|
||||
if ($verbose) {
|
||||
if ($print_line_num) {
|
||||
$line_num = sprintf("%4s ", $.);
|
||||
}
|
||||
printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
|
||||
}
|
||||
|
||||
$found = 0;
|
||||
$no_begin = 0;
|
||||
if (@found_or_begin > 0) {
|
||||
$begin = pop @found_or_begin;
|
||||
if (compare($data, $begin)) {
|
||||
$found = 1;
|
||||
}
|
||||
} elsif (@begin > 0) {
|
||||
$begin = pop @begin;
|
||||
} else {
|
||||
$no_begin = 1;
|
||||
}
|
||||
|
||||
if ($no_begin) {
|
||||
|
||||
$expect_missing_begin++;
|
||||
print "** ERROR: EXPECT end without any EXPECT begin:\n";
|
||||
print " end ---> $line\n";
|
||||
|
||||
} elsif (! $found) {
|
||||
|
||||
if ($print_line_num) {
|
||||
$line_num = sprintf("%4s ", $.);
|
||||
}
|
||||
|
||||
$expect_not_found++;
|
||||
printf "** %s%s$script_name WARNING - not found ---> %s\n",
|
||||
$line_num, $timestamp, $data;
|
||||
|
||||
} elsif (! compare($data, $begin)) {
|
||||
|
||||
$expect_missing_end++;
|
||||
print "** ERROR: EXPECT end does not match EXPECT begin:\n";
|
||||
print " begin -> $begin\n";
|
||||
print " end ---> $line\n";
|
||||
|
||||
} else {
|
||||
|
||||
$expect_found++;
|
||||
|
||||
}
|
||||
|
||||
next LINE;
|
||||
}
|
||||
|
||||
|
||||
# ----- not an EXPECT line
|
||||
|
||||
if (($line =~ /^${pr_fmt}start of unittest - you will see error messages$/) ||
|
||||
($line =~ /^${pr_fmt}end of unittest - [0-9]+ passed, [0-9]+ failed$/ ) ) {
|
||||
$prefix = "->"; # 2 characters
|
||||
} elsif ($line =~ /^${pr_fmt}FAIL /) {
|
||||
$unittest_fail++;
|
||||
$prefix = ">>"; # 2 characters
|
||||
}
|
||||
|
||||
$found = 0;
|
||||
foreach $begin (@begin) {
|
||||
if (compare($begin, $line)) {
|
||||
$found = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
$begin = shift @begin;
|
||||
while (! compare($begin, $line)) {
|
||||
push @found_or_begin, $begin;
|
||||
$begin = shift @begin;
|
||||
}
|
||||
push @found_or_begin, $line;
|
||||
|
||||
if ($hide_expect) {
|
||||
$suppress_line = 1;
|
||||
next LINE;
|
||||
}
|
||||
$prefix = "ok"; # 2 characters
|
||||
}
|
||||
|
||||
|
||||
if ($print_line_num) {
|
||||
$line_num = sprintf("%4s ", $.);
|
||||
}
|
||||
|
||||
printf "%s %s%s%s\n", $prefix, $line_num, $timestamp, $line;
|
||||
}
|
||||
|
||||
if (! $no_expect_stats) {
|
||||
print "\n";
|
||||
print "** EXPECT statistics:\n";
|
||||
print "**\n";
|
||||
printf "** EXPECT found : %4i\n", $expect_found;
|
||||
printf "** EXPECT not found : %4i\n", $expect_not_found;
|
||||
printf "** missing EXPECT begin : %4i\n", $expect_missing_begin;
|
||||
printf "** missing EXPECT end : %4i\n", $expect_missing_end;
|
||||
printf "** unittest FAIL : %4i\n", $unittest_fail;
|
||||
printf "** internal error : %4i\n", $internal_err;
|
||||
}
|
||||
|
||||
if (@begin) {
|
||||
print "** ERROR: EXPECT begin without any EXPECT end:\n";
|
||||
print " This list may be misleading.\n";
|
||||
foreach $begin (@begin) {
|
||||
print " begin ---> $begin\n";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user