Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package os-autoinst for openSUSE:Factory 
checked in at 2026-04-30 20:32:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/os-autoinst (Old)
 and      /work/SRC/openSUSE:Factory/.os-autoinst.new.30200 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "os-autoinst"

Thu Apr 30 20:32:18 2026 rev:592 rq:1350258 version:5.1777537682.913fce0

Changes:
--------
--- /work/SRC/openSUSE:Factory/os-autoinst/os-autoinst.changes  2026-04-28 
11:55:44.903951355 +0200
+++ /work/SRC/openSUSE:Factory/.os-autoinst.new.30200/os-autoinst.changes       
2026-04-30 20:33:11.257654654 +0200
@@ -1,0 +2,11 @@
+Thu Apr 30 08:28:11 UTC 2026 - [email protected]
+
+- Update to version 5.1777537682.913fce0:
+  * fix: re-install serial marker hook after console reset
+  * fix: support pretty_serial_markers in script_output regex
+  * feat: disable storage check in CI environments
+  * fix(test): handle D-Bus AccessDenied in Open vSwitch test
+  * fix: Avoid restarting openvswitch/NM after OVS bridge setup
+  * refactor: import IO::Socket::UNIX explicitly wherever is used
+
+-------------------------------------------------------------------

Old:
----
  os-autoinst-5.1776943886.0619ca6.obscpio

New:
----
  os-autoinst-5.1777537682.913fce0.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ os-autoinst-devel-test.spec ++++++
--- /var/tmp/diff_new_pack.O7PwaS/_old  2026-04-30 20:33:12.529706989 +0200
+++ /var/tmp/diff_new_pack.O7PwaS/_new  2026-04-30 20:33:12.529706989 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name os-autoinst-devel
 Name:           %{short_name}-test
-Version:        5.1776943886.0619ca6
+Version:        5.1777537682.913fce0
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ os-autoinst-openvswitch-test.spec ++++++
--- /var/tmp/diff_new_pack.O7PwaS/_old  2026-04-30 20:33:12.585709293 +0200
+++ /var/tmp/diff_new_pack.O7PwaS/_new  2026-04-30 20:33:12.589709457 +0200
@@ -19,7 +19,7 @@
 %define name_ext -test
 %define         short_name os-autoinst-openvswitch
 Name:           %{short_name}%{?name_ext}
-Version:        5.1776943886.0619ca6
+Version:        5.1777537682.913fce0
 Release:        0
 Summary:        test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ os-autoinst-test.spec ++++++
--- /var/tmp/diff_new_pack.O7PwaS/_old  2026-04-30 20:33:12.641711597 +0200
+++ /var/tmp/diff_new_pack.O7PwaS/_new  2026-04-30 20:33:12.641711597 +0200
@@ -19,7 +19,7 @@
 %define name_ext -test
 %define         short_name os-autoinst
 Name:           %{short_name}%{?name_ext}
-Version:        5.1776943886.0619ca6
+Version:        5.1777537682.913fce0
 Release:        0
 Summary:        test package for os-autoinst
 License:        GPL-2.0-or-later

++++++ os-autoinst.spec ++++++
--- /var/tmp/diff_new_pack.O7PwaS/_old  2026-04-30 20:33:12.689713571 +0200
+++ /var/tmp/diff_new_pack.O7PwaS/_new  2026-04-30 20:33:12.689713571 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           os-autoinst
-Version:        5.1776943886.0619ca6
+Version:        5.1777537682.913fce0
 Release:        0
 Summary:        OS-level test automation
 License:        GPL-2.0-or-later
@@ -325,6 +325,7 @@
 
 %files -f %{name}.files
 %defattr(-,root,root)
+%doc README.md doc/architecture.md doc/backend_vars.md doc/backends.md 
doc/memorydumps.md doc/networking.md
 %{_docdir}/os-autoinst
 %dir %{_prefix}/lib/os-autoinst
 %{_prefix}/lib/os-autoinst/debugviewer

++++++ os-autoinst-5.1776943886.0619ca6.obscpio -> 
os-autoinst-5.1777537682.913fce0.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/.mergify.yml 
new/os-autoinst-5.1777537682.913fce0/.mergify.yml
--- old/os-autoinst-5.1776943886.0619ca6/.mergify.yml   2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/.mergify.yml   2026-04-30 
10:28:02.000000000 +0200
@@ -14,7 +14,7 @@
           # "unresolvable" is not reported in general:
           # 
https://trello.com/c/0N3jHq5M/2257-report-back-to-scm-when-build-results-arent-failed-and-succeeded
           # So we need to require the number of tests explicitly:
-          - "#check-success>=29"
+          - "#check-success>=28"
           - "#check-failure=0"
           - "#check-pending=0"
           - linear-history
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/.perlcriticrc 
new/os-autoinst-5.1777537682.913fce0/.perlcriticrc
--- old/os-autoinst-5.1776943886.0619ca6/.perlcriticrc  2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/.perlcriticrc  2026-04-30 
10:28:02.000000000 +0200
@@ -1,6 +1,6 @@
 theme = community + openqa
 severity = 4
-include = strict ValuesAndExpressions::ProhibitInterpolationOfLiterals 
CodeLayout::ProhibitParensWithBuiltins BuiltinFunctions::RequireBlockMap 
BuiltinFunctions::ProhibitStringySplit 
ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions
+include = strict ValuesAndExpressions::ProhibitInterpolationOfLiterals 
CodeLayout::ProhibitParensWithBuiltins BuiltinFunctions::RequireBlockMap 
BuiltinFunctions::ProhibitStringySplit 
ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions 
ValuesAndExpressions::RequireQuotedHeredocTerminator
 
 verbose = ::warning file=%f,line=%l,col=%c,title=%m - severity %s::[%p] %e\n
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/OpenQA/Isotovideo/Interface.pm 
new/os-autoinst-5.1777537682.913fce0/OpenQA/Isotovideo/Interface.pm
--- old/os-autoinst-5.1776943886.0619ca6/OpenQA/Isotovideo/Interface.pm 
2026-04-23 13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/OpenQA/Isotovideo/Interface.pm 
2026-04-30 10:28:02.000000000 +0200
@@ -9,7 +9,7 @@
 # -> increment on every change of such APIs
 # -> never move that variable to another place (when refactoring)
 #    because it may be accessed by the tests itself
-our $version = 52;
+our $version = 55;
 
 # major version of the (web socket) API relevant to the developer mode
 # -> increment when making non-backward compatible changes to that API
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/OpenQA/Qemu/Proc.pm 
new/os-autoinst-5.1777537682.913fce0/OpenQA/Qemu/Proc.pm
--- old/os-autoinst-5.1776943886.0619ca6/OpenQA/Qemu/Proc.pm    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/OpenQA/Qemu/Proc.pm    2026-04-30 
10:28:02.000000000 +0200
@@ -27,6 +27,7 @@
 use File::Which;
 use Mojo::JSON qw(encode_json decode_json);
 use Mojo::File 'path';
+use IO::Socket::UNIX;
 use OpenQA::Qemu::BlockDevConf;
 use OpenQA::Qemu::ControllerConf;
 use OpenQA::Qemu::DriveDevice 'QEMU_IMAGE_FORMAT';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/autotest.pm 
new/os-autoinst-5.1777537682.913fce0/autotest.pm
--- old/os-autoinst-5.1776943886.0619ca6/autotest.pm    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/autotest.pm    2026-04-30 
10:28:02.000000000 +0200
@@ -301,7 +301,11 @@
         }
         my $msg = "error on $script: $err";
         bmwqemu::fctwarn($msg);
-        bmwqemu::serialize_state(component => 'tests', msg => "unable to load 
$script, check the log for the cause (e.g. syntax error)");
+        my ($is_missing_module) = $err =~ /(Can't locate .+ in \@INC)/;
+        my ($state_msg) = $is_missing_module
+          ? "Missing Perl module while loading $script: $is_missing_module"
+          : "unable to load $script, check the log for the cause (e.g. syntax 
error)";
+        bmwqemu::serialize_state(component => 'tests', msg => $state_msg, 
result => 'incomplete');
         die $msg;
     }
     $test = $name->new($category);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/backend/qemu.pm 
new/os-autoinst-5.1777537682.913fce0/backend/qemu.pm
--- old/os-autoinst-5.1776943886.0619ca6/backend/qemu.pm        2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/backend/qemu.pm        2026-04-30 
10:28:02.000000000 +0200
@@ -11,7 +11,6 @@
 use File::Which;
 use Time::HiRes qw(sleep gettimeofday);
 use Time::Seconds;
-use IO::Socket::UNIX 'SOCK_STREAM';
 use IO::Handle;
 use POSIX qw(strftime :sys_wait_h mkfifo);
 use Mojo::File 'path';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/backend/vagrant.pm 
new/os-autoinst-5.1777537682.913fce0/backend/vagrant.pm
--- old/os-autoinst-5.1776943886.0619ca6/backend/vagrant.pm     2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/backend/vagrant.pm     2026-04-30 
10:28:02.000000000 +0200
@@ -39,22 +39,22 @@
     $self->{vagrantfile} = $path->child('Vagrantfile');
     bmwqemu::diag("Writing Vagrantfile to $self->{vagrantfile}");
 
-    my $vagrant_file_contents = <<END;
+    my $vagrant_file_contents = <<"END";
 Vagrant.configure("2") do |config|
   config.vm.box = "$self->{box_name}"
 END
     if (defined($self->{box_url})) {
-        $vagrant_file_contents .= <<END;
+        $vagrant_file_contents .= <<"END";
   config.vm.box_url = "$self->{box_url}"
 END
     }
-    $vagrant_file_contents .= <<END;
+    $vagrant_file_contents .= <<'END';
   config.vm.synced_folder ".", "/vagrant", disabled: true
 END
 
 
     if ($self->{provider} eq 'virtualbox') {
-        $vagrant_file_contents .= <<END;
+        $vagrant_file_contents .= <<"END";
   config.vm.provider "virtualbox" do |v|
     v.memory = $vars->{QEMURAM}
     v.cpus = $vars->{QEMUCPUS}
@@ -65,7 +65,7 @@
         mkdir $self->{libvirt_storage_pool_path};
         $self->{libvirt_pool_name} = 'vagrant' . int rand 100_000;
 
-        $vagrant_file_contents .= <<END;
+        $vagrant_file_contents .= <<"END";
   config.vm.provider :libvirt do |libvirt|
     libvirt.cpus = $vars->{QEMUCPUS}
     libvirt.memory = $vars->{QEMURAM}
@@ -76,7 +76,7 @@
         die "got an unknown vagrant provider $self->{provider}";
     }
 
-    $vagrant_file_contents .= <<END;
+    $vagrant_file_contents .= <<'END';
 end
 END
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/basetest.pm 
new/os-autoinst-5.1777537682.913fce0/basetest.pm
--- old/os-autoinst-5.1776943886.0619ca6/basetest.pm    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/basetest.pm    2026-04-30 
10:28:02.000000000 +0200
@@ -334,6 +334,14 @@
         if (!@{$self->{details}} || ($self->{details}->[-1]->{result} || '') 
ne 'fail') {
             $self->take_screenshot();
         }
+        if (!$internal && $e =~ /Can't locate .+ in \@INC/) {
+            my $msg = "# Test died with missing dependency: $e";
+            bmwqemu::fctinfo($msg);
+            $self->record_resultfile('Failed', $msg, result => 'fail');
+            $self->{fatal_failure} = 1;
+            bmwqemu::serialize_state(component => 'tests', msg => "Missing 
Perl module: $e", result => 'incomplete');
+            $died = 1;
+        }
         # show a text result with the die message unless the die was 
internally generated
         if (!$internal) {
             my $msg = "# Test died: $e";
@@ -429,11 +437,30 @@
     # take screenshot for documentation (screenshot does not represent fail 
itself)
     $self->take_screenshot() unless (testapi::is_serial_terminal);
 
+    my $pretty = testapi::get_var('PRETTY_SERIAL_MARKER') || 
testapi::get_var('HIDE_MARKER_EVALUATION');
+    my $internal = $args{internal_marker};
+    my $output_string = $string;
+    my $captured_val;
+
+    if ($internal && $args{marker_pattern}) {
+        my $pattern = $args{marker_pattern};
+        my $is_regex = ref $pattern eq 'Regexp';
+        $captured_val = $1 if $is_regex && $string =~ /$pattern/;
+
+        if ($pretty) {
+            my $search = $is_regex ? $pattern : qr/\Q$pattern\E/;
+            $output_string =~ s/$search\s*\z//m;
+        }
+    }
+
     my $output = '';
     $output .= "# Command: $args{command}\n" if defined $args{command};
-    $output .= "# wait_serial expected: $ref\n";
+    $output .= "# wait_serial expected: $ref\n" unless $internal && $pretty;
     $output .= "# Result:\n";
-    $output .= "$string\n";
+    $output .= "$output_string\n";
+    if (defined $captured_val && $args{capture_name}) {
+        $output .= "# $args{capture_name}: $captured_val\n";
+    }
     $self->record_resultfile('wait_serial', $output, result => $res);
     return undef;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/bmwqemu.pm 
new/os-autoinst-5.1777537682.913fce0/bmwqemu.pm
--- old/os-autoinst-5.1776943886.0619ca6/bmwqemu.pm     2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/bmwqemu.pm     2026-04-30 
10:28:02.000000000 +0200
@@ -170,6 +170,7 @@
 }
 
 sub _abort_if_storage_limit_exceeded () {
+    return undef if $ENV{CI} || $ENV{GITHUB_ACTIONS};
     my $keep_free = $vars{STORAGE_KEEP_FREE_RATIO} // STORAGE_KEEP_FREE_RATIO;
     return undef if $keep_free <= 0;
     my $numdisks = $vars{NUMDISKS} // default_numdisks();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/dist/rpm/os-autoinst.spec 
new/os-autoinst-5.1777537682.913fce0/dist/rpm/os-autoinst.spec
--- old/os-autoinst-5.1776943886.0619ca6/dist/rpm/os-autoinst.spec      
2026-04-23 13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/dist/rpm/os-autoinst.spec      
2026-04-30 10:28:02.000000000 +0200
@@ -325,6 +325,7 @@
 
 %files -f %{name}.files
 %defattr(-,root,root)
+%doc README.md doc/architecture.md doc/backend_vars.md doc/backends.md 
doc/memorydumps.md doc/networking.md
 %{_docdir}/os-autoinst
 %dir %{_prefix}/lib/os-autoinst
 %{_prefix}/lib/os-autoinst/debugviewer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/distribution.pm 
new/os-autoinst-5.1777537682.913fce0/distribution.pm
--- old/os-autoinst-5.1776943886.0619ca6/distribution.pm        2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/distribution.pm        2026-04-30 
10:28:02.000000000 +0200
@@ -15,6 +15,7 @@
     $self->{serial_failures} = [];
     $self->{autoinst_failures} = [];
     $self->{_serial_marker_level} = {};
+    $self->{_serial_marker_hook_installed} = {};
 
 =head2 serial_term_prompt
 
@@ -155,7 +156,7 @@
         if ($level == 3) {
             testapi::query_isotovideo('backend_clear_serial_buffer', {});
             testapi::type_string "$cmd\n", max_interval => $args{max_interval};
-            my $res = testapi::wait_serial(qr/OA:DONE-[0-9a-f]{4}-(\d+)-/, 
timeout => $args{timeout}, quiet => $args{quiet}, record_command => $cmd);
+            my $res = testapi::wait_serial(qr/OA:DONE-[0-9a-f]{4}-(\d+)-/, 
timeout => $args{timeout}, quiet => $args{quiet}, record_command => $cmd, 
internal_marker => 1, capture_name => 'Exit code');
             return unless $res;
             return ($res =~ /OA:DONE-[0-9a-f]{4}-(\d+)-/)[0];
         }
@@ -169,7 +170,7 @@
             if (testapi::is_serial_terminal) {
                 testapi::type_string "$cmd", max_interval => 
$args{max_interval};
                 testapi::type_string $marker, max_interval => 
$args{max_interval};
-                testapi::wait_serial($cmd . $marker, no_regex => 1, quiet => 
$args{quiet}, buffer_size => (length $cmd) + 128)
+                testapi::wait_serial($cmd . $marker, no_regex => 1, quiet => 
$args{quiet}, buffer_size => (length $cmd) + 128, internal_marker => 1)
                   or _handle_cmd_typing_error($cmd, \%args);
                 testapi::type_string "\n", max_interval => $args{max_interval};
             }
@@ -178,7 +179,7 @@
                 testapi::type_string "$marker > /dev/$testapi::serialdev\n", 
max_interval => $args{max_interval};
             }
         }
-        my $res = testapi::wait_serial($wait_pattern, timeout => 
$args{timeout}, quiet => $args{quiet}, record_command => $cmd);
+        my $res = testapi::wait_serial($wait_pattern, timeout => 
$args{timeout}, quiet => $args{quiet}, record_command => $cmd, internal_marker 
=> 1, capture_name => 'Exit code');
         return unless $res;
         return ($res =~ $wait_pattern)[0];
     }
@@ -215,13 +216,13 @@
     my $marker = "& echo $str-\$!-" . ($args{output} ? "Comment: 
$args{output}" : '');
     if (testapi::is_serial_terminal) {
         testapi::type_string $marker;
-        testapi::wait_serial($cmd . $marker, no_regex => 1, quiet => 
$args{quiet}) or _handle_cmd_typing_error($cmd, \%args);
+        testapi::wait_serial($cmd . $marker, no_regex => 1, quiet => 
$args{quiet}, internal_marker => 1) or _handle_cmd_typing_error($cmd, \%args);
         testapi::type_string "\n";
     }
     else {
         testapi::type_string "$marker > /dev/$testapi::serialdev\n";
     }
-    my $res = testapi::wait_serial(qr/$str-\d+-/, quiet => $args{quiet});
+    my $res = testapi::wait_serial(qr/$str-\d+-/, quiet => $args{quiet}, 
internal_marker => 1);
     die 'PID marker not found' unless ($res =~ m/$str-(\d+)-/);
     return $1;
 }
@@ -248,7 +249,7 @@
         testapi::send_key 'ret';
     }
     if ($str) {
-        return testapi::wait_serial($str, $wait);
+        return testapi::wait_serial($str, $wait, internal_marker => 1);
     }
     return;
 }
@@ -307,7 +308,7 @@
         testapi::wait_serial('> ', no_regex => 1, quiet => $args{quiet});
         testapi::type_string "$script\n$heretag\n";
         testapi::wait_serial("> $heretag", no_regex => 1, quiet => 
$args{quiet});
-        testapi::wait_serial("$marker-0-", quiet => $args{quiet});
+        testapi::wait_serial(qr/$marker-(0)-/, capture_name => 'Exit code', 
quiet => $args{quiet}, internal_marker => 1);
     }
     elsif ($args{type_command}) {
         my $cat = "cat - > $script_path;";
@@ -339,7 +340,7 @@
     else {
         testapi::type_string "($run_script) | tee /dev/$testapi::serialdev\n";
     }
-    my $output = testapi::wait_serial("SCRIPT_FINISHED$marker-\\d+-", timeout 
=> $args{timeout}, record_output => 1, quiet => $args{quiet})
+    my $output = testapi::wait_serial(qr/SCRIPT_FINISHED$marker-(\d+)-/, 
capture_name => 'Exit code', timeout => $args{timeout}, record_output => 1, 
quiet => $args{quiet}, internal_marker => 1)
       || croak "script timeout: $script";
 
     if ($output !~ "SCRIPT_FINISHED$marker-0-") {
@@ -353,7 +354,7 @@
     }
 
     # and the markers including internal exit catcher
-    my $out = $output =~ 
/$marker(?<expected_output>.+)SCRIPT_FINISHED$marker-\d+-/s ? $+ : '';
+    my $out = $output =~ 
/(?:^|\r?\n)$marker\r?\n(?<expected_output>.*?)SCRIPT_FINISHED$marker-\d+-/s ? 
$+ : '';
     # trim whitespaces
     $out =~ s/^\s+|\s+$//g;
     return $out;
@@ -452,6 +453,11 @@
     $self->{_serial_marker_hook_installed}->{$console} = 1;
 }
 
+sub reset_console_cache ($self, $console) {
+    delete $self->{_serial_marker_level}->{$console};
+    delete $self->{_serial_marker_hook_installed}->{$console};
+}
+
 =head2 _detect_serial_marker_capability
 
     _detect_serial_marker_capability()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/doc/backend_vars.md 
new/os-autoinst-5.1777537682.913fce0/doc/backend_vars.md
--- old/os-autoinst-5.1776943886.0619ca6/doc/backend_vars.md    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/doc/backend_vars.md    2026-04-30 
10:28:02.000000000 +0200
@@ -60,8 +60,8 @@
 | GIT_CACHE_DIR | string |  | If set enables locally caching Git repositories 
in the specified directory when handling Git URLs in variables like `CASEDIR` 
and wheels |
 | ENABLE_MODERN_PERL_FEATURES | boolean | 0 | Enables use of modern Perl 
features in test modules avoiding the need to use e.g. `use Mojo::Base 
'basetest', -signatures;` in all test modules. This variable must be set before 
invoking `autotest::loadtest`. It only applies to the test modules themselves. 
It does *not* apply to e.g. `main.pm` and other Perl modules used via e.g. `use 
some::module`. |
 | _HIDE_SECRETS_REGEX | string |  | If set, any test variables whose **NAME** 
(key) matches the specified regular expression, in addition to the default 
'^_SECRET_' and '_PASSWORD', are excluded from being saved into vars.json or 
further processing. For example, to hide all variables starting with 
'SCC_REGCODE', use '^SCC_REGCODE'. |
-| STORAGE_KEEP_FREE_RATIO | float | 0.2 | Ratio of total storage space to keep 
free (e.g. 0.2 for 20%). If the total requested HDD size exceeds the available 
space while keeping this ratio of total storage size free, the job is aborted 
early with "incomplete" status. Set to 0 to disable this check. |
-| STORAGE_KEEP_FREE_GB | integer | 50 | Absolute free space threshold in GiB. 
If the total requested HDD size leaves less than this amount of free space, the 
job can only run if the relative check (`STORAGE_KEEP_FREE_RATIO`) is also 
satisfied. Set to 0 to disable the absolute threshold. |
+| STORAGE_KEEP_FREE_RATIO | float | 0.2 | Ratio of total storage space to keep 
free (e.g. 0.2 for 20%). If the total requested HDD size exceeds the available 
space while keeping this ratio of total storage size free, the job is aborted 
early with "incomplete" status. Set to 0 to disable this check. Automatically 
disabled in CI environments (if `CI` or `GITHUB_ACTIONS` is set in the 
environment). |
+| STORAGE_KEEP_FREE_GB | integer | 50 | Absolute free space threshold in GiB. 
If the total requested HDD size leaves less than this amount of free space, the 
job can only run if the relative check (`STORAGE_KEEP_FREE_RATIO`) is also 
satisfied. Set to 0 to disable the absolute threshold. Automatically disabled 
in CI environments (if `CI` or `GITHUB_ACTIONS` is set in the environment). |
 | FAIL_ON_ALWAYS_ROLLBACK_NOT_SUPPORTED | boolean | 0 | Fail explicitly if a 
test module is scheduled with the `always_rollback` flag but snapshots are not 
supported by the backend. |
 |  |
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/script/os-autoinst-setup-multi-machine 
new/os-autoinst-5.1777537682.913fce0/script/os-autoinst-setup-multi-machine
--- old/os-autoinst-5.1776943886.0619ca6/script/os-autoinst-setup-multi-machine 
2026-04-23 13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/script/os-autoinst-setup-multi-machine 
2026-04-30 10:28:02.000000000 +0200
@@ -44,6 +44,7 @@
     pkgs=(openvswitch os-autoinst-openvswitch firewalld libcap-progs)
     [[ $network == NetworkManager ]] && pkgs+=(NetworkManager-ovs)
     rpm -q ${pkgs[*]} > /dev/null || retry -e -s 30 -r 7 -- sh -c "zypper ref 
&& zypper -n in ${pkgs[*]}"
+    systemctl enable --now openvswitch os-autoinst-openvswitch
 }
 
 configure_firewalld() {
@@ -155,14 +156,17 @@
 }
 
 setup_multi_machine_with_networkmanager() {
-    # Restart NM to load ovs plugin
-    systemctl restart NetworkManager
     # Delete any previous connections
     nmcli con | grep -oP 'ovs-(interface|port|bridge|slave)-[\w-]+' | xargs -r 
nmcli con del || true
+    # Clear NM state and timestamps
+    systemctl stop NetworkManager
+    [[ -d /var/lib/NetworkManager ]] && rm -vf 
/var/lib/NetworkManager/{timestamps,NetworkManager.state}
+    # Restart NM to load ovs plugin
+    systemctl start NetworkManager
     # Create bridge, port and interface connection
-    nmcli con add type ovs-bridge con.int "$bridge"
+    nmcli con add type ovs-bridge con.int "$bridge" ipv4.dad-timeout 0
     nmcli con add type ovs-port con.int "$bridge" con.master "$bridge"
-    nmcli con add type ovs-interface con.int "$bridge" con.master "$bridge" 
ipv4.method manual ipv4.address 10.0.2.2/15 ipv6.method manual ipv6.address 
fec0::2/63 ethernet.mtu "$mtu" con.zone "$zone"
+    nmcli con add type ovs-interface con.int "$bridge" con.master "$bridge" 
ipv4.method manual ipv4.address 10.0.2.2/15 ipv4.dad-timeout 0 ipv6.method 
manual ipv6.address fec0::2/63 ethernet.mtu "$mtu" con.zone "$zone"
     # Create tap interfaces
     for i in 0 $(
         seq 1 "$instances"
@@ -211,10 +215,23 @@
     wicked ifup "$ethernet" "$bridge"
 }
 
+delete_tap_ifaces() {
+    ifaces=($(ls /sys/class/net/ | xargs -I {} sh -c 'if [ -f 
/sys/class/net/{}/tun_flags ]; then echo {}; fi' | sort -V))
+    for iface in "${ifaces[@]}"; do ip link delete $iface; done
+}
+
+cleanup_openvswitch_db() {
+    # Delete existing ovs db and its lock but do not delete any ovs db backup
+    systemctl stop openvswitch os-autoinst-openvswitch
+    [[ -d /var/lib/openvswitch/ ]] && rm -f 
/var/lib/openvswitch/{conf.db,.conf.db.~lock~}
+    systemctl is-enabled openvswitch && systemctl start openvswitch
+    systemctl is-enabled os-autoinst-openvswitch && systemctl start 
os-autoinst-openvswitch
+}
+
 configure_openvswitch() {
     echo "OS_AUTOINST_USE_BRIDGE=$bridge" > 
/etc/sysconfig/os-autoinst-openvswitch
     systemctl enable os-autoinst-openvswitch
-    systemctl restart openvswitch os-autoinst-openvswitch
+    systemctl restart os-autoinst-openvswitch
 }
 
 determine_ethernet_interface() {
@@ -239,7 +256,8 @@
     else
         configure_nftables
     fi
-    systemctl enable --now openvswitch
+    cleanup_openvswitch_db
+    delete_tap_ifaces
     case "$network" in
         wicked)
             setup_multi_machine_with_wicked
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/03-testapi.t 
new/os-autoinst-5.1777537682.913fce0/t/03-testapi.t
--- old/os-autoinst-5.1776943886.0619ca6/t/03-testapi.t 2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/03-testapi.t 2026-04-30 
10:28:02.000000000 +0200
@@ -791,46 +791,46 @@
     $mock_testapi->redefine(hashed_string => 'XXX');
     $mock_testapi->redefine(is_serial_terminal => sub { return 
$is_serial_terminal });
 
-    $mock_testapi->redefine(wait_serial => "XXXfoo\nSCRIPT_FINISHEDXXX-0-");
+    $mock_testapi->redefine(wait_serial => "XXX\nfoo\nSCRIPT_FINISHEDXXX-0-");
     $bmwqemu::vars{OFFLINE_SUT} = 1;
     is(script_output('echo foo'), 'foo', 'sucessfull retrieves output of 
script');
     $bmwqemu::vars{OFFLINE_SUT} = 0;
 
-    $mock_testapi->redefine(wait_serial => 'SCRIPT_FINISHEDXXX-0-');
+    $mock_testapi->redefine(wait_serial => "XXX\nSCRIPT_FINISHEDXXX-0-");
     is(script_output('foo'), '', 'calling script_output does not fail if 
script returns with success');
 
-    $mock_testapi->redefine(wait_serial => "This is simulated output on the 
serial device\nXXXfoo\nSCRIPT_FINISHEDXXX-0-\nand more here");
+    $mock_testapi->redefine(wait_serial => "This is simulated output on the 
serial device\nXXX\nfoo\nSCRIPT_FINISHEDXXX-0-\nand more here");
     is(script_output('echo foo'), 'foo', 'script_output return only the actual 
output of the script');
 
-    $mock_testapi->redefine(wait_serial => "XXXfoo\nSCRIPT_FINISHEDXXX-1-");
+    $mock_testapi->redefine(wait_serial => "XXX\nfoo\nSCRIPT_FINISHEDXXX-1-");
     is(script_output('echo foo', undef, proceed_on_failure => 1), 'foo', 
'proceed_on_failure=1 retrieves retrieves output of script and do not die');
 
-    $mock_testapi->redefine(wait_serial => sub { return 'none' if (shift !~ 
m/SCRIPT_FINISHEDXXX-\\d\+-/) });
+    $mock_testapi->redefine(wait_serial => sub { return 'none' unless $_[0] =~ 
/SCRIPT_FINISHEDXXX/; return; });
     throws_ok { script_output('timeout'); } qr/timeout/, 'die expected with 
timeout';
 
     subtest 'script_output check error codes' => sub {
         for my $ret ((1, 10, 100, 255)) {
-            $mock_testapi->redefine(wait_serial => 
"XXXfoo\nSCRIPT_FINISHEDXXX-$ret-");
+            $mock_testapi->redefine(wait_serial => 
"XXX\nfoo\nSCRIPT_FINISHEDXXX-$ret-");
             throws_ok { script_output('false'); } qr/script failed/, 
"script_output die expected on exitcode $ret";
         }
     };
 
+    my @wait_serial_args;
     $mock_testapi->redefine(wait_serial => sub ($regex, %args) {
-            is($args{quiet}, undef, 'Check default quiet argument');
-            if ($regex =~ m/SCRIPT_FINISHEDXXX-\\d\+-/) {
-                is($args{timeout}, 30, 'pass $wait value to wait_serial');
-            }
-            return "XXXfoo\nSCRIPT_FINISHEDXXX-0-";
+            push @wait_serial_args, \%args;
+            return "XXX\nfoo\nSCRIPT_FINISHEDXXX-0-";
     });
-    is(script_output('echo foo', 30), 'foo', '');
-    is(script_output('echo foo', timeout => 30), 'foo', '');
-
-    $mock_testapi->redefine(wait_serial => sub ($regex, %args) {
-            is($args{quiet}, 1, 'Check quiet argument');
-            return "XXXfoo\nSCRIPT_FINISHEDXXX-0-";
-    });
-    is(script_output('echo foo', quiet => 1), 'foo', '');
-    $mock_testapi->redefine(wait_serial => "This is a simulated output on the 
serial dev\nXXXfoo\nSCRIPT_FINISHEDXXX-0-\nand more here");
+    for my $t (
+        {args => [30], timeout => 30, quiet => undef, msg => 'positional 
wait'},
+        {args => [timeout => 30], timeout => 30, quiet => undef, msg => 
'keyword timeout'},
+        {args => [quiet => 1], timeout => undef, quiet => 1, msg => 'keyword 
quiet'}) {
+        @wait_serial_args = ();
+        is script_output('echo foo', $t->{args}->@*), 'foo', "$t->{msg}: 
returns expected output";
+        is $wait_serial_args[-1]->{timeout}, $t->{timeout}, "$t->{msg}: 
correct timeout passed to final wait_serial call";
+        my @inconsistent_quiet = grep { ($_->{quiet} // 0) != ($t->{quiet} // 
0) } @wait_serial_args;
+        is_deeply \@inconsistent_quiet, [], "$t->{msg}: quiet argument is 
consistent across all calls";
+    }
+    $mock_testapi->redefine(wait_serial => "This is a simulated output on the 
serial dev\nXXX\nfoo\nSCRIPT_FINISHEDXXX-0-\nand more here");
     is script_output('echo foo', type_command => 0), 'foo', 'script_output 
with type_command => 0 output in a file';
 }
 
@@ -990,7 +990,7 @@
     $mock_testapi->redefine(script_output => 'output');
     $mock_testapi->redefine(wait_serial => sub ($regex, %args) {
             is($args{quiet}, 1, 'Check default quiet argument');
-            return "XXXfoo\nSCRIPT_FINISHEDXXX-0-";
+            return "XXX\nfoo\nSCRIPT_FINISHEDXXX-0-";
     });
     is(script_output('echo foo', 30), 'foo', 'script_output with 
_QUIET_SCRIPT_CALLS=1 expects command output');
     is(script_run('true'), '0', 'script_run with _QUIET_SCRIPT_CALLS=1');
@@ -999,7 +999,7 @@
 
     $mock_testapi->redefine(wait_serial => sub ($regex, %args) {
             is($args{quiet}, 0, 'Check default quiet argument');
-            return "XXXfoo\nSCRIPT_FINISHEDXXX-0-";
+            return "XXX\nfoo\nSCRIPT_FINISHEDXXX-0-";
     });
     is(script_output('echo foo', quiet => 0), 'foo', 'script_output with 
_QUIET_SCRIPT_CALLS=1 and quiet=>0');
     is(script_run('true', quiet => 0), '0', 'script_run with 
_QUIET_SCRIPT_CALLS=1 and quiet=>0');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/t/04-check_vars_docu.t 
new/os-autoinst-5.1777537682.913fce0/t/04-check_vars_docu.t
--- old/os-autoinst-5.1776943886.0619ca6/t/04-check_vars_docu.t 2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/04-check_vars_docu.t 2026-04-30 
10:28:02.000000000 +0200
@@ -63,7 +63,7 @@
 }
 
 sub write_doc () {
-    my $data = <<EO_HEADER;
+    my $data = <<'EO_HEADER';
 Supported variables per backend
 ===============================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/05-distribution.t 
new/os-autoinst-5.1777537682.913fce0/t/05-distribution.t
--- old/os-autoinst-5.1776943886.0619ca6/t/05-distribution.t    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/05-distribution.t    2026-04-30 
10:28:02.000000000 +0200
@@ -137,6 +137,21 @@
     throws_ok { $d->script_run('foo') } qr/typing command 'foo' timed out/, 
'typing error handled in Level 1';
 };
 
+subtest 'serial_marker_reinstall_cached_level' => sub {
+    my $d = distribution->new;
+    my $mock_testapi = Test::MockModule->new('testapi');
+    $mock_testapi->redefine(current_console => sub { 'test-console' });
+    my $typed = '';
+    $mock_testapi->redefine(type_string => sub { $typed .= $_[0] });
+
+    $d->{_serial_marker_level}->{'test-console'} = 2;
+    delete $d->{_serial_marker_hook_installed}->{'test-console'};
+
+    is $d->_detect_serial_marker_capability(), 2, 'Returns cached level 2';
+    like $typed, qr/PROMPT_COMMAND=/, 'Calls install_serial_marker_hook (types 
PROMPT_COMMAND)';
+    ok $d->{_serial_marker_hook_installed}->{'test-console'}, 'Hook marked as 
installed';
+};
+
 subtest 'reboot_safety' => sub {
     my $d = distribution->new;
     my $mock_testapi = Test::MockModule->new('testapi');
@@ -174,11 +189,21 @@
     like $typed_string, qr/bar\n/, 'Command typed';
 
     # Case 2: manual clear (e.g. if we know it was lost)
-    delete $d->{_serial_marker_hook_installed}->{'test-console'};
+    $d->reset_console_cache('test-console');
     $typed_string = '';
     $d->script_run('baz');
-    like $typed_string, qr/PROMPT_COMMAND=.*OA:DONE/, 'Re-install if missing';
-    like $typed_string, qr/baz\n/, 'Command typed after re-install';
+    like $typed_string, qr/PROMPT_COMMAND=.*OA:DONE/, 'Re-detect and 
re-install after resetting the console cache';
+    like $typed_string, qr/baz\n/, 'Command typed after re-installation';
+
+    # Case 3: select_console triggers reset
+    $d->{_serial_marker_hook_installed}->{'test-console'} = 1;
+    $typed_string = '';
+    $mock_testapi->redefine(query_isotovideo => sub { return {activated => 1} 
});
+    $testapi::distri = $d;
+
+    testapi::select_console('test-console');
+    $d->script_run('qux');
+    like $typed_string, qr/BASH:/, 'Re-detect after select_console 
re-activates the console';
 };
 
 subtest 'sut_marker' => sub {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/12-bmwqemu.t 
new/os-autoinst-5.1777537682.913fce0/t/12-bmwqemu.t
--- old/os-autoinst-5.1776943886.0619ca6/t/12-bmwqemu.t 2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/12-bmwqemu.t 2026-04-30 
10:28:02.000000000 +0200
@@ -34,31 +34,30 @@
 subtest 'log_call' => sub {
     require bmwqemu;
 
-    sub log_call_test {
+    sub log_call_test () {
         bmwqemu::log_call(foo => "bar\tbaz\rboo\n");
     }
     stderr_like(\&log_call_test, qr{\Q<<< 
main::log_call_test(foo="bar\tbaz\rboo\n")}, 'log_call escapes special 
characters');
 
-    sub log_call_test_escape_key {
+    sub log_call_test_escape_key () {
         bmwqemu::log_call("foo\nbar" => "bar\tbaz\rboo\n");
     }
     stderr_like(\&log_call_test_escape_key, qr{\Q<<< 
main::log_call_test_escape_key("foo\nbar"="bar\tbaz\rboo\n")}, 'log_call 
escapes special characters');
 
-    sub log_call_test_single {
+    sub log_call_test_single () {
         bmwqemu::log_call("bar\tbaz\rboo\n");
     }
     stderr_like(\&log_call_test_single, qr{\Q<<< 
main::log_call_test_single("bar\tbaz\rboo\n")}, 'log_call escapes special 
characters');
 
-    sub log_call_indent {
+    sub log_call_indent () {
         my $lines = ['a', ['b']];
         bmwqemu::log_call(test => $lines);
     }
     stderr_like(\&log_call_indent, qr{\Q<<< main::log_call_indent(test=[\E\n\Q 
   "a",\E\n\Q    [\E\n\Q      "b"\E\n\Q    ]\E\n\Q  ])}, 'log_call auto 
indentation');
 
-    sub log_call_test_secret {
-        my (%args) = @_;
-        # Use @_ instead of %args to keep the order
-        bmwqemu::log_call(@_, ($args{secret} ? (-masked => $args{text}) : ()));
+    sub log_call_test_secret (@args) {
+        my %args = @args;
+        bmwqemu::log_call(@args, ($args{secret} ? (-masked => $args{text}) : 
()));
         return;
     }
     stderr_like { log_call_test_secret(text => "password\n", secret => 1) } 
qr{\Q<<< main::log_call_test_secret(text="[masked]", secret=1)}, 'log_call 
hides sensitive info';
@@ -207,6 +206,10 @@
             desc => 'fails if both relative and absolute thresholds exceeded 
(e.g. 50GB requested on 100GB disk with 60GB avail leaves 10GB free)'},
         {hdd_size_gb => 50, total_storage => 100, avail_storage => 60, expect 
=> 'pass', extra_vars => {STORAGE_KEEP_FREE_GB => 0},
             desc => 'passes if both thresholds would be exceeded but absolute 
threshold is disabled via 0'},
+        {hdd_size_gb => 1, total_storage => 100, avail_storage => 1, expect => 
'pass', ci => 1,
+            desc => 'succeed if requested HDDSIZEGB exceeds available space 
but CI environment variable is set'},
+        {hdd_size_gb => 1, total_storage => 100, avail_storage => 1, expect => 
'pass', github_actions => 1,
+            desc => 'succeed if requested HDDSIZEGB exceeds available space 
but GITHUB_ACTIONS environment variable is set'},
     );
     for my $case (@cases) {
         unlink bmwqemu::STATE_FILE;
@@ -214,6 +217,8 @@
         $vars{HDDSIZEGB} = $case->{hdd_size_gb} if defined 
$case->{hdd_size_gb};
         create_vars(\%vars);
         $bmw_mock->mock(_get_storage_stats => sub (@) { 
($case->{total_storage} * 1024**3, $case->{avail_storage} * 1024**3) });
+        local $ENV{CI} = $case->{ci} // 0;
+        local $ENV{GITHUB_ACTIONS} = $case->{github_actions} // 0;
         if ($case->{expect} eq 'pass') {
             lives_ok { bmwqemu::init(); bmwqemu::ensure_valid_vars(); } 
$case->{desc};
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/14-isotovideo.t 
new/os-autoinst-5.1777537682.913fce0/t/14-isotovideo.t
--- old/os-autoinst-5.1776943886.0619ca6/t/14-isotovideo.t      2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/14-isotovideo.t      2026-04-30 
10:28:02.000000000 +0200
@@ -84,7 +84,7 @@
 subtest 'standard tests based on simple vars.json file' => sub {
     chdir $pool_dir;
     open my $var, '>', 'vars.json';
-    print $var <<EOV;
+    print $var <<"EOV";
 {
    "CASEDIR" : "$data_dir/tests",
    "_EXIT_AFTER_SCHEDULE" : 1,
@@ -199,7 +199,7 @@
             package Copy::Writer::Content$i;
             use Mojo::Base 'Exporter';
             our \@EXPORT_OK = qw(write);
-            sub write { "val$i"};
+            sub write () { "val$i"};
             1;
             EOM
             path($wheels_dir, 'writer', 'tests', 
'pen')->make_path->child("ink$i.pm")->spew("use Mojo::Base 'basetest'; use 
Copy::Writer::Content$i 'write'; sub run {}; 1");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/17-basetest.t 
new/os-autoinst-5.1777537682.913fce0/t/17-basetest.t
--- old/os-autoinst-5.1776943886.0619ca6/t/17-basetest.t        2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/17-basetest.t        2026-04-30 
10:28:02.000000000 +0200
@@ -282,6 +282,28 @@
     ok $basetest->{fatal_failure}, 'failure considered fatal';
     $basetest->remove_last_result;
     is_deeply $basetest->record_testresult('ok'), {result => 'ok'}, 'can add 
one test result again';
+    path(bmwqemu::STATE_FILE)->remove;
+};
+
+subtest 'missing Perl module triggers incomplete' => sub {
+    Test::MockModule->new('autotest')->noop('set_current_test');
+    my $mock = Test::MockModule->new('basetest');
+    $mock->noop('take_screenshot');
+    $mock->mock(run => sub {
+            die "Can't locate HTTP/Request/Common.pm in \@INC (you may need to 
install the HTTP::Request::Common module)\n";
+    });
+    local $bmwqemu::vars{MAX_TEST_STEPS} = 100;
+    my $basetest = bless {details => [], name => 'foo', fullname => 'foo', 
category => 'category1'}, 'basetest';
+    my $logs = combined_from { dies_ok { $basetest->runtest } 'runtest dies 
due to missing module' };
+    like $logs, qr/Can't locate.*\@INC/, 'catch expected error message';
+
+    # Verify state file has incomplete result
+    ok -e bmwqemu::STATE_FILE, 'state file was written';
+    my $state = decode_json(path(bmwqemu::STATE_FILE)->slurp);
+    is $state->{result}, 'incomplete', 'result is incomplete for missing Perl 
module';
+    # like $state->{msg}, qr/Can't locate/, 'message mentions the missing 
module';
+    ok $basetest->{fatal_failure}, 'failure is fatal';
+    path(bmwqemu::STATE_FILE)->remove if -e bmwqemu::STATE_FILE;
 };
 
 delete $bmwqemu::vars{MAX_TEST_STEPS};
@@ -496,7 +518,7 @@
     $suppress_match = 'yes';
     my $details;
     my $mock_test = Test::MockModule->new('basetest');
-    $mock_test->mock(record_screenfail => sub { my ($self, %args) = @_; 
$details = \%args; });
+    $mock_test->mock(record_screenfail => sub ($self, %args) { $details = 
\%args; });
     $res = $test->verify_sound_image("$FindBin::Bin/data/frame1.ppm", 
"$FindBin::Bin/data/frame2.ppm", 1);
     is($res, undef, 'res is undef as expected') or always_explain $res;
     is($details->{result}, 'unk', 'no needle match: unknown status correct') 
or always_explain $details;
@@ -529,4 +551,71 @@
     like($recorded_output, qr/# wait_serial expected: regex/, 'expected regex 
is in output');
 };
 
+subtest record_serialresult_hiding => sub {
+    my $basetest = basetest->new();
+    $basetest->{name} = 'test_hiding';
+    my $recorded_output;
+    my $mock_basetest_local = Test::MockModule->new('basetest');
+    my $mock_testapi = Test::MockModule->new('testapi');
+    $mock_basetest_local->redefine(record_resultfile => sub ($self, $title, 
$output, %nargs) { $recorded_output = $output });
+
+    my @test_cases = (
+        {
+            name => 'expected regex is visible by default (no pretty vars 
set)',
+            vars => {},
+            params => ['regex', 'ok', 'some output marker', internal_marker => 
1, marker_pattern => 'marker'],
+            expected => [qr/# wait_serial expected: regex/],
+            not_expected => [],
+        },
+        {
+            name => 'expected regex is hidden and literal marker is stripped 
when PRETTY_SERIAL_MARKER is set',
+            vars => {PRETTY_SERIAL_MARKER => 1},
+            params => ['regex', 'ok', "some output\nmarker\n", internal_marker 
=> 1, marker_pattern => 'marker'],
+            expected => [qr/some output\n\s*\n/],
+            not_expected => [qr/# wait_serial expected: regex/],
+        },
+        {
+            name => 'expected regex is hidden and regex marker is stripped 
when HIDE_MARKER_EVALUATION is set',
+            vars => {HIDE_MARKER_EVALUATION => 1},
+            params => ['regex', 'ok', "command output\nOA:DONE-1234-0-\n", 
internal_marker => 1, marker_pattern => qr/OA:DONE-[0-9a-f]{4}-(\d+)-/],
+            expected => [qr/command output\n\s*\n/],
+            not_expected => [qr/# wait_serial expected: regex/, 
qr/OA:DONE-1234-0-/],
+        },
+        {
+            name => 'Exit code is displayed when capture_name is provided',
+            vars => {PRETTY_SERIAL_MARKER => 1},
+            params => ['regex', 'ok', "command output\nOA:DONE-1234-0-\n", 
internal_marker => 1, marker_pattern => qr/OA:DONE-[0-9a-f]{4}-(\d+)-/, 
capture_name => 'Exit code'],
+            expected => [qr/# Exit code: 0/, qr/command output\n\s*\n/],
+            not_expected => [qr/# wait_serial expected: regex/],
+        },
+        {
+            name => 'PID is displayed for background commands',
+            vars => {HIDE_MARKER_EVALUATION => 1},
+            params => ['regex', 'ok', "background output\nMARKER-1234-\n", 
internal_marker => 1, marker_pattern => qr/MARKER-(\d+)-/, capture_name => 
'PID'],
+            expected => [qr/# PID: 1234/, qr/background output\n\s*\n/],
+            not_expected => [qr/MARKER-1234-/],
+        },
+        {
+            name => 'no hiding occurs if it is not an internal marker even if 
pretty vars are set',
+            vars => {PRETTY_SERIAL_MARKER => 1, HIDE_MARKER_EVALUATION => 1},
+            params => ['regex', 'ok', 'some output marker', internal_marker => 
0, marker_pattern => 'marker'],
+            expected => [qr/# wait_serial expected: regex/],
+            not_expected => [],
+        },
+        {
+            name => 'regex marker is provided but string does not match (e.g. 
on timeout)',
+            vars => {PRETTY_SERIAL_MARKER => 1},
+            params => ['regex', 'fail', "some output that did not hit the 
marker\n", internal_marker => 1, marker_pattern => 
qr/OA:DONE-[0-9a-f]{4}-(\d+)-/, capture_name => 'Exit code'],
+            expected => [qr/some output that did not hit the marker\n/],
+            not_expected => [qr/# Exit code:/],
+        },
+    );
+
+    foreach my $case (@test_cases) {
+        $mock_testapi->mock(get_var => sub ($var) { return 
$case->{vars}->{$var} });
+        $basetest->record_serialresult(@{$case->{params}});
+        like($recorded_output, $_, "$case->{name} (contains expected)") for 
@{$case->{expected}};
+        unlike($recorded_output, $_, "$case->{name} (does not contain 
unexpected)") for @{$case->{not_expected}};
+    }
+};
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/18-backend-qemu.t 
new/os-autoinst-5.1777537682.913fce0/t/18-backend-qemu.t
--- old/os-autoinst-5.1776943886.0619ca6/t/18-backend-qemu.t    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/18-backend-qemu.t    2026-04-30 
10:28:02.000000000 +0200
@@ -62,7 +62,7 @@
 is($called{add_console}, 1, 'one console has been added');
 
 subtest 'using Open vSwitch D-Bus service' => sub {
-    my $expected = qr/Open vSwitch command.*show.*arguments 'foo bar'.*(The 
name.*not (provided|activatable)|Failed to connect)/;
+    my $expected = qr/Open vSwitch command.*show.*arguments 'foo bar'.*(The 
name.*not (provided|activatable)|Failed to connect|AccessDenied)/;
     my $msg = 'error about missing service';
     throws_ok { $backend->_dbus_call('show', 'foo', 'bar') } $expected, $msg . 
' in exception';
     $bmwqemu::vars{QEMU_NON_FATAL_DBUS_CALL} = 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/t/19-isotovideo-command-processing.t 
new/os-autoinst-5.1777537682.913fce0/t/19-isotovideo-command-processing.t
--- old/os-autoinst-5.1776943886.0619ca6/t/19-isotovideo-command-processing.t   
2026-04-23 13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/19-isotovideo-command-processing.t   
2026-04-30 10:28:02.000000000 +0200
@@ -48,7 +48,7 @@
         push @{$self->{messages}}, $cmd;
         return $cmd->{cmd} eq 'is_shutdown' ? 'down' : {tags => [qw(some fake 
tags)]};
     }
-    sub stop { die "faking stop\n" }
+    sub stop ($self) { die "faking stop\n" }
 }    # uncoverable statement
 
 package bmwqemu {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/t/20-openqa-isotovideo-utils.t 
new/os-autoinst-5.1777537682.913fce0/t/20-openqa-isotovideo-utils.t
--- old/os-autoinst-5.1776943886.0619ca6/t/20-openqa-isotovideo-utils.t 
2026-04-23 13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/20-openqa-isotovideo-utils.t 
2026-04-30 10:28:02.000000000 +0200
@@ -59,7 +59,7 @@
         my $state = decode_json($base_state->slurp);
         if (is(ref $state, 'HASH', 'state file contains object')) {
             is($state->{component}, 'tests', 'state file contains component');
-            like($state->{msg}, qr/unable to load foo\/bar\.pm/, 'state file 
contains error message');
+            like($state->{msg}, qr/Missing Perl module while loading 
foo\/bar\.pm/, 'state file contains error message');
         }
     };
     subtest 'invalid productdir' => sub {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/23-baseclass.t 
new/os-autoinst-5.1777537682.913fce0/t/23-baseclass.t
--- old/os-autoinst-5.1776943886.0619ca6/t/23-baseclass.t       2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/23-baseclass.t       2026-04-30 
10:28:02.000000000 +0200
@@ -185,7 +185,7 @@
                     $mock_channel->mock(pty => sub { return 1; });
                     $mock_channel->mock(send_eof => sub { return 1; });
                     $mock_channel->mock(exit_status => sub { 
shift->{exit_status}; });
-                    $mock_channel->mock(ext_data => sub { my ($self, $v) = @_; 
$self->{ext_data} = $v; });
+                    $mock_channel->mock(ext_data => sub ($self, $v) { 
$self->{ext_data} = $v; });
                     $mock_channel->mock(close => sub { return 1; });
                     return $mock_channel;
             });
@@ -433,7 +433,7 @@
     $baseclass->{current_console} = $current_console;
 
     #mock content of serial0.txt
-    path($baseclass->{serialfile})->spew(<<EOT);
+    path($baseclass->{serialfile})->spew(<<'EOT');
 Just a simple text
 Just a simple another text that will disappear
 Welcome to GRUB2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/os-autoinst-5.1776943886.0619ca6/t/27-consoles-vmware.t 
new/os-autoinst-5.1777537682.913fce0/t/27-consoles-vmware.t
--- old/os-autoinst-5.1776943886.0619ca6/t/27-consoles-vmware.t 2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/27-consoles-vmware.t 2026-04-30 
10:28:02.000000000 +0200
@@ -148,7 +148,7 @@
             $self->send({binary => 'binary sent from WebSocket'}, sub {
                     $self->send({text => 'text message sent from WebSocket'}, 
sub {
                             $sent_everything = 1;
-                            $self->finish if length 
$self->app->received_everything;
+                            $self->finish if $self->app->received_everything;
                     });
             });
             $self->on(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/33-vagrant.t 
new/os-autoinst-5.1777537682.913fce0/t/33-vagrant.t
--- old/os-autoinst-5.1776943886.0619ca6/t/33-vagrant.t 2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/33-vagrant.t 2026-04-30 
10:28:02.000000000 +0200
@@ -216,7 +216,7 @@
     $backend_vars->{QEMUCPUS} = 1;
     $backend_vars->{QEMURAM} = 1024;
 
-    $expected_spew_str = <<END;
+    $expected_spew_str = <<"END";
 Vagrant.configure("2") do |config|
   config.vm.box = "$box_file"
   config.vm.synced_folder ".", "/vagrant", disabled: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/39-dewebsockify.t 
new/os-autoinst-5.1777537682.913fce0/t/39-dewebsockify.t
--- old/os-autoinst-5.1776943886.0619ca6/t/39-dewebsockify.t    2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/39-dewebsockify.t    2026-04-30 
10:28:02.000000000 +0200
@@ -59,60 +59,60 @@
     use Test::Most;
     use Mojo::Base -signatures;
 
-    sub is_websocket { 1 }
-    sub max_websocket_size { }
-    sub error { }
-    sub req { bless {}, 'MockTxGenericReq' }
+    sub is_websocket ($self, @args) { 1 }
+    sub max_websocket_size ($self, @args) { }
+    sub error ($self, @args) { }
+    sub req ($self, @args) { bless {}, 'MockTxGenericReq' }
 
     sub on ($self, $event, $cb) {
         if ($event eq 'text') { $main::ws_on_text = $cb }
         elsif ($event eq 'binary') { $main::ws_on_binary = $cb }
         elsif ($event eq 'finish') { $main::ws_on_finish = $cb }
     }
-    sub send { }
-    sub finish { }
+    sub send ($self, @args) { }
+    sub finish ($self) { }
 
     package MockTxGenericReq;
-    sub cookies { }
-    sub headers { bless {}, 'MockTxGenericHeaders' }
+    sub cookies ($self, @args) { }
+    sub headers ($self, @args) { bless {}, 'MockTxGenericHeaders' }
 
     package MockTxGenericHeaders;
-    sub add { }
+    sub add ($self, @args) { }
 
     package MockTxFailNoCode;
-    sub is_websocket { 0 }
-    sub error { undef }    # No code, no message
-    sub req { bless {}, 'MockTxFailNoCodeReq' }
-    sub res { bless {}, 'MockTxFailNoCodeRes' }
+    sub is_websocket ($self, @args) { 0 }
+    sub error ($self, @args) { undef }    # No code, no message
+    sub req ($self, @args) { bless {}, 'MockTxFailNoCodeReq' }
+    sub res ($self, @args) { bless {}, 'MockTxFailNoCodeRes' }
 
     package MockTxFailNoCodeReq;
-    sub cookies { }
-    sub headers { bless {}, 'MockTxFailNoCodeHeaders' }
+    sub cookies ($self, @args) { }
+    sub headers ($self, @args) { bless {}, 'MockTxFailNoCodeHeaders' }
 
     package MockTxFailNoCodeHeaders;
-    sub add { }
+    sub add ($self, @args) { }
 
     package MockTxFailNoCodeRes;
-    sub body { 'dummy body' }
+    sub body ($self, @args) { 'dummy body' }
 
     package MockTxFailWithCode;
-    sub is_websocket { 0 }
+    sub is_websocket ($self, @args) { 0 }
 
-    sub error {
+    sub error ($self, @args) {
         return {code => 403, message => 'Forbidden'};
     }
-    sub req { bless {}, 'MockTxFailWithCodeReq' }
-    sub res { bless {}, 'MockTxFailWithCodeRes' }
+    sub req ($self, @args) { bless {}, 'MockTxFailWithCodeReq' }
+    sub res ($self, @args) { bless {}, 'MockTxFailWithCodeRes' }
 
     package MockTxFailWithCodeReq;
-    sub cookies { }
-    sub headers { bless {}, 'MockTxFailWithCodeHeaders' }
+    sub cookies ($self, @args) { }
+    sub headers ($self, @args) { bless {}, 'MockTxFailWithCodeHeaders' }
 
     package MockTxFailWithCodeHeaders;
-    sub add { }
+    sub add ($self, @args) { }
 
     package MockTxFailWithCodeRes;
-    sub body { 'dummy body' }
+    sub body ($self, @args) { 'dummy body' }
 }
 
 sub mock_build_ws_tx ($mock_ua, $tx_class) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/t/99-full-stack.t 
new/os-autoinst-5.1777537682.913fce0/t/99-full-stack.t
--- old/os-autoinst-5.1776943886.0619ca6/t/99-full-stack.t      2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/t/99-full-stack.t      2026-04-30 
10:28:02.000000000 +0200
@@ -31,7 +31,7 @@
 my $cleanup = scope_guard sub { chdir $Bin; undef $dir };
 
 my $casedir = path($data_dir, 'tests');
-path('vars.json')->spew(<<EOV);
+path('vars.json')->spew(<<"EOV");
 {
    "ARCH" : "i386",
    "BACKEND" : "qemu",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/testapi.pm 
new/os-autoinst-5.1777537682.913fce0/testapi.pm
--- old/os-autoinst-5.1776943886.0619ca6/testapi.pm     2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/testapi.pm     2026-04-30 
10:28:02.000000000 +0200
@@ -185,7 +185,7 @@
 
 =cut
 
-sub save_screenshot () { $autotest::current_test->take_screenshot unless 
is_serial_terminal }
+sub save_screenshot () { $autotest::current_test->take_screenshot unless 
is_serial_terminal() }
 
 =head2 record_soft_failure
 
@@ -858,8 +858,7 @@
 
 =cut
 
-sub wait_serial {    # no:style:signatures
-    my $regexp = shift;
+sub wait_serial ($regexp, @args) {
     my %args = compat_args(
         {
             regexp => $regexp,
@@ -870,7 +869,9 @@
             buffer_size => undef,
             record_output => undef,
             record_command => undef,
-        }, ['timeout', 'expect_not_found'], @_);
+            internal_marker => 0,
+            capture_name => undef,
+        }, ['timeout', 'expect_not_found'], @args);
 
     bmwqemu::log_call(%args);
     $args{timeout} = bmwqemu::scale_timeout($args{timeout});
@@ -886,7 +887,7 @@
     # hyperv and vmware (backend/svirt.pm) connect serial line over TCP/IP 
(socat)
     # convert CRLF to LF only
     $ret->{string} =~ s,\r\n,\n,g;
-    $autotest::current_test->record_serialresult(bmwqemu::pp($regexp), 
$matched, $ret->{string}, command => $args{record_command}) unless 
($args{quiet});
+    $autotest::current_test->record_serialresult(bmwqemu::pp($regexp), 
$matched, $ret->{string}, command => $args{record_command}, internal_marker => 
$args{internal_marker}, marker_pattern => $regexp, capture_name => 
$args{capture_name}) unless ($args{quiet});
     bmwqemu::fctres("$regexp: $matched");
     return $ret->{string} if ($matched eq 'ok');
     return;    # false
@@ -1705,6 +1706,7 @@
     $autotest::selected_console = $testapi_console;
     if ($ret->{activated}) {
         push @$autotest::activated_consoles, $testapi_console;
+        $testapi::distri->reset_console_cache($testapi_console);
         $testapi::distri->activate_console($testapi_console, @args);
     }
     $testapi::distri->console_selected($testapi_console, @args);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/os-autoinst-5.1776943886.0619ca6/xt/01-style.t 
new/os-autoinst-5.1777537682.913fce0/xt/01-style.t
--- old/os-autoinst-5.1776943886.0619ca6/xt/01-style.t  2026-04-23 
13:31:26.000000000 +0200
+++ new/os-autoinst-5.1777537682.913fce0/xt/01-style.t  2026-04-30 
10:28:02.000000000 +0200
@@ -19,7 +19,8 @@
 is qx{git grep -I -l '^use \\(Try::Tiny\\|TryCatch\\)'}, '', 'No Try::Tiny or 
TryCatch necessary, use Feature::Compat::Try and later native Perl';
 is qx{git grep -I -l '\<spurt\>'}, '', 'No deprecated "Mojo::File::spurt", use 
"spew" instead';
 is qx{git grep -I -l '^use testapi' backend/ consoles/}, '', 'No backend or 
console files use external facing testapi';
-is qx{git grep -l -e '^sub \\S\\+ [^(]\\+' --and --not -e 'sub [(\{]' --and 
--not -e 'sub \\S\\+(' --and --not -e 'sub \\S\\+;' --and --not -e '# 
no:style:signatures' ':!external/'}, '', 'All files use sub signatures 
everywhere (nameless and in-place definitions still allowed)';
+is qx[git grep -l -e '^\\s*sub \\S\\+ [^(]\\+' --and --not -e 'sub [(\{]' 
--and --not -e 'sub \\S\\+\\s*[:(]' --and --not -e 'sub \\S\\+;' --and --not -e 
'# no:style:signatures' ':!external/' ':!t/48-testmodules-style.t'], '', 'All 
files use sub signatures everywhere (nameless and in-place definitions still 
allowed)';
+is qx[git grep -l -P 'sub\\s*\\{\\s*my\\s*\\(?\\\$' t/], '', 'Anonymous subs 
in tests should use signatures instead of manual unpacking of @_';
 is qx{git grep -L '^#!.*perl' t/**.t}, '', 'All test files have shebang';
 is qx{git ls-files -s t/**.t | grep -v ^1007}, '', 'All test modules are 
executable';
 is qx{git grep -l '^use POSIX;'}, '', 'Use of bare POSIX import is 
discouraged, see https://perldoc.perl.org/POSIX';

++++++ os-autoinst.obsinfo ++++++
--- /var/tmp/diff_new_pack.O7PwaS/_old  2026-04-30 20:33:15.165815444 +0200
+++ /var/tmp/diff_new_pack.O7PwaS/_new  2026-04-30 20:33:15.177815937 +0200
@@ -1,5 +1,5 @@
 name: os-autoinst
-version: 5.1776943886.0619ca6
-mtime: 1776943886
-commit: 0619ca6d84bded836782df071cfa1de4a96c6f3c
+version: 5.1777537682.913fce0
+mtime: 1777537682
+commit: 913fce00a14c6d0b215fec654944b9f6f3954a62
 

Reply via email to