Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package openQA for openSUSE:Factory checked 
in at 2026-10-16 20:10:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openQA (Old)
 and      /work/SRC/openSUSE:Factory/.openQA.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openQA"

Fri Oct 16 20:10:34 2026 rev:891 rq:1385184 version:5.1792132198.63d05d40

Changes:
--------
--- /work/SRC/openSUSE:Factory/openQA/openQA.changes    2026-10-15 
12:20:37.307277286 +0200
+++ /work/SRC/openSUSE:Factory/.openQA.new.3698736/openQA.changes       
2026-10-16 20:14:18.215803517 +0200
@@ -1,0 +2,20 @@
+Fri Oct 16 06:30:10 UTC 2026 - [email protected]
+
+- Update to version 5.1792132198.63d05d40:
+  * refactor(ui): Initialise host previous jobs table directly
+  * fix(ui): Sort host previous jobs slot by worker instance
+  * fix(ui): Align previous jobs sort columns for host
+  * chore(deps): Dependency cron 2026-10-16
+  * feat(systemd): Ignore try-reload-or-restart fails for workers
+  * chore(deps-dev): bump brace-expansion from 5.0.7 to 5.0.12 (#7949)
+  * chore(deps): bump source-map-js from 1.2.1 to 1.2.2 (#7948)
+  * chore(deps): bump postcss-selector-parser from 7.1.4 to 7.1.6 (#7947)
+  * fix(worker): Avoid concurrent result uploads
+
+-------------------------------------------------------------------
+Thu Oct 15 05:07:03 UTC 2026 - [email protected]
+
+- Update to version 5.1792040810.42404b37:
+  * chore(deps): Dependency cron 2026-10-15
+
+-------------------------------------------------------------------

Old:
----
  openQA-5.1792016843.dbd2549e.obscpio

New:
----
  openQA-5.1792132198.63d05d40.obscpio

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

Other differences:
------------------
++++++ openQA-client-test.spec ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:21.129925893 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:21.130925935 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-client
 Name:           %{short_name}-test
-Version:        5.1792016843.dbd2549e
+Version:        5.1792132198.63d05d40
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-test.spec ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:21.160927194 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:21.162927278 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA
 Name:           %{short_name}-test
-Version:        5.1792016843.dbd2549e
+Version:        5.1792132198.63d05d40
 Release:        0
 Summary:        Test package for openQA
 License:        GPL-2.0-or-later

++++++ openQA-worker-test.spec ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:21.191928496 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:21.193928580 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-worker
 Name:           %{short_name}-test
-Version:        5.1792016843.dbd2549e
+Version:        5.1792132198.63d05d40
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA.spec ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:21.225929924 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:21.227930008 +0200
@@ -104,7 +104,7 @@
 %define devel_requires %devel_no_selenium_requires chromedriver
 
 Name:           openQA
-Version:        5.1792016843.dbd2549e
+Version:        5.1792132198.63d05d40
 Release:        0
 Summary:        Framework for automated system-level testing (web-frontend, 
scheduler and tools)
 Group:          Development/Tools/Other

++++++ node_modules.obscpio ++++++
Binary files old/brace-expansion-5.0.12.tgz and new/brace-expansion-5.0.12.tgz 
differ
Binary files old/brace-expansion-5.0.7.tgz and new/brace-expansion-5.0.7.tgz 
differ
Binary files old/postcss-selector-parser-7.1.4.tgz and 
new/postcss-selector-parser-7.1.4.tgz differ
Binary files old/postcss-selector-parser-7.1.6.tgz and 
new/postcss-selector-parser-7.1.6.tgz differ
Binary files old/source-map-js-1.2.1.tgz and new/source-map-js-1.2.1.tgz differ
Binary files old/source-map-js-1.2.2.tgz and new/source-map-js-1.2.2.tgz differ

++++++ node_modules.spec.inc ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:21.968961127 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:21.971961253 +0200
@@ -48,7 +48,7 @@
 Source1047:         
https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#/astral-regex-2.0.0.tgz
 Source1048:         
https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz#/balanced-match-4.0.4.tgz
 Source1049:         
https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz#/bootstrap-5.3.8.tgz
-Source1050:         
https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz#/brace-expansion-5.0.7.tgz
+Source1050:         
https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz#/brace-expansion-5.0.12.tgz
 Source1051:         
https://registry.npmjs.org/braces/-/braces-3.0.3.tgz#/braces-3.0.3.tgz
 Source1052:         
https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz#/cacheable-2.5.0.tgz
 Source1053:         
https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#/callsites-3.1.0.tgz
@@ -203,7 +203,7 @@
 Source1202:         
https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz#/postcss-resolve-nested-selector-0.1.6.tgz
 Source1203:         
https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz#/postcss-safe-parser-7.0.1.tgz
 Source1204:         
https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz#/postcss-scss-4.0.9.tgz
-Source1205:         
https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz#/postcss-selector-parser-7.1.4.tgz
+Source1205:         
https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz#/postcss-selector-parser-7.1.6.tgz
 Source1206:         
https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#/postcss-value-parser-4.2.0.tgz
 Source1207:         
https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz#/prelude-ls-1.2.1.tgz
 Source1208:         
https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz#/prettier-3.9.6.tgz
@@ -223,7 +223,7 @@
 Source1222:         
https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#/signal-exit-4.1.0.tgz
 Source1223:         
https://registry.npmjs.org/slash/-/slash-5.1.0.tgz#/slash-5.1.0.tgz
 Source1224:         
https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#/slice-ansi-4.0.0.tgz
-Source1225:         
https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz#/source-map-js-1.2.1.tgz
+Source1225:         
https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz#/source-map-js-1.2.2.tgz
 Source1226:         
https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#/string-width-4.2.3.tgz
 Source1227:         
https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz#/string-width-8.2.2.tgz
 Source1228:         
https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#/strip-ansi-6.0.1.tgz

++++++ openQA-5.1792016843.dbd2549e.obscpio -> 
openQA-5.1792132198.63d05d40.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1792016843.dbd2549e/assets/javascripts/admin_worker.js 
new/openQA-5.1792132198.63d05d40/assets/javascripts/admin_worker.js
--- old/openQA-5.1792016843.dbd2549e/assets/javascripts/admin_worker.js 
2026-10-15 00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/assets/javascripts/admin_worker.js 
2026-10-16 08:29:58.000000000 +0200
@@ -26,7 +26,6 @@
 }
 
 function setupWorkerNeedles() {
-  setupHostPreviousJobs();
   const table = $('#previous_jobs').DataTable({
     ajax: $('#previous_jobs').data('ajax-url'),
     deferRender: true,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1792016843.dbd2549e/lib/OpenQA/WebAPI/Controller/Admin/Workers.pm 
new/openQA-5.1792132198.63d05d40/lib/OpenQA/WebAPI/Controller/Admin/Workers.pm
--- 
old/openQA-5.1792016843.dbd2549e/lib/OpenQA/WebAPI/Controller/Admin/Workers.pm  
    2026-10-15 00:27:23.000000000 +0200
+++ 
new/openQA-5.1792132198.63d05d40/lib/OpenQA/WebAPI/Controller/Admin/Workers.pm  
    2026-10-16 08:29:58.000000000 +0200
@@ -8,11 +8,12 @@
 use OpenQA::WebAPI::ServerSideDataTable;
 use Scalar::Util 'looks_like_number';
 
-use constant PREVIOUS_JOBS_COLUMNS => (
-    [qw(BUILD DISTRI VERSION FLAVOR ARCH)],
-    [qw(passed_module_count softfailed_module_count failed_module_count)],
-    qw(t_finished),
-);
+# SQL sort keys positionally aligned with the DataTable display columns of 
each view
+use constant JOB_NAME_SORT_COLUMNS => [qw(BUILD DISTRI VERSION FLAVOR ARCH)];
+use constant RESULT_SORT_COLUMNS => [qw(passed_module_count 
softfailed_module_count failed_module_count)];
+use constant PREVIOUS_JOBS_COLUMNS => (JOB_NAME_SORT_COLUMNS, 
RESULT_SORT_COLUMNS, 't_finished');
+use constant PREVIOUS_HOST_JOBS_COLUMNS =>
+  (JOB_NAME_SORT_COLUMNS, 'assigned_worker.instance', RESULT_SORT_COLUMNS, 
't_finished');
 
 sub _extend_info ($w) {
     my $info = $w->info;
@@ -157,7 +158,7 @@
     OpenQA::WebAPI::ServerSideDataTable::render_response(
         controller => $self,
         resultset => 'Jobs',
-        columns => [PREVIOUS_JOBS_COLUMNS],
+        columns => [PREVIOUS_HOST_JOBS_COLUMNS],
         initial_conds => [{assigned_worker_id => {-in => \@worker_ids}}],
         additional_params => {prefetch => [qw(children parents 
assigned_worker)]},
         prepare_data_function => \&_previous_jobs_data,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1792016843.dbd2549e/lib/OpenQA/Worker/Job.pm 
new/openQA-5.1792132198.63d05d40/lib/OpenQA/Worker/Job.pm
--- old/openQA-5.1792016843.dbd2549e/lib/OpenQA/Worker/Job.pm   2026-10-15 
00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/lib/OpenQA/Worker/Job.pm   2026-10-16 
08:29:58.000000000 +0200
@@ -697,6 +697,10 @@
 }
 
 sub _upload_results ($self, $callback) {
+    # avoid concurrent upload chains; the deferred call removes the timer set 
by the ongoing one
+    return $self->once(uploading_results_concluded => sub (@) { 
$self->_upload_results($callback) })
+      if $self->{_is_uploading_results};
+
     # ensure an ongoing timer is cancelled in case upload_results has been 
called manually
     if (my $upload_results_timer = delete $self->{_upload_results_timer}) {
         Mojo::IOLoop->remove($upload_results_timer);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1792016843.dbd2549e/package-lock.json 
new/openQA-5.1792132198.63d05d40/package-lock.json
--- old/openQA-5.1792016843.dbd2549e/package-lock.json  2026-10-15 
00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/package-lock.json  2026-10-16 
08:29:58.000000000 +0200
@@ -738,16 +738,16 @@
       }
     },
     "node_modules/brace-expansion": {
-      "version": "5.0.7",
-      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz";,
-      "integrity": 
"sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
+      "version": "5.0.12",
+      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz";,
+      "integrity": 
"sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
         "balanced-match": "^4.0.2"
       },
       "engines": {
-        "node": "18 || 20 || >=22"
+        "node": "20 || >=22"
       }
     },
     "node_modules/braces": {
@@ -2605,9 +2605,9 @@
       }
     },
     "node_modules/postcss-selector-parser": {
-      "version": "7.1.4",
-      "resolved": 
"https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz";,
-      "integrity": 
"sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==",
+      "version": "7.1.6",
+      "resolved": 
"https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz";,
+      "integrity": 
"sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -2856,9 +2856,9 @@
       }
     },
     "node_modules/source-map-js": {
-      "version": "1.2.1",
-      "resolved": 
"https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz";,
-      "integrity": 
"sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "version": "1.2.2",
+      "resolved": 
"https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz";,
+      "integrity": 
"sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
       "dev": true,
       "license": "BSD-3-Clause",
       "engines": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1792016843.dbd2549e/systemd/[email protected]
 
new/openQA-5.1792132198.63d05d40/systemd/[email protected]
--- 
old/openQA-5.1792016843.dbd2549e/systemd/[email protected]
 2026-10-15 00:27:23.000000000 +0200
+++ 
new/openQA-5.1792132198.63d05d40/systemd/[email protected]
 2026-10-16 08:29:58.000000000 +0200
@@ -3,5 +3,6 @@
 
 [Service]
 Type=oneshot
-ExecStart=/usr/bin/systemctl try-reload-or-restart 
openqa-worker-auto-restart@%i.service
+# Ignore failures: systemctl exits 1 when an idle worker deactivates mid-reload
+ExecStart=-/usr/bin/systemctl try-reload-or-restart 
openqa-worker-auto-restart@%i.service
 Slice=openqa-worker.slice
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1792016843.dbd2549e/t/24-worker-jobs.t 
new/openQA-5.1792132198.63d05d40/t/24-worker-jobs.t
--- old/openQA-5.1792016843.dbd2549e/t/24-worker-jobs.t 2026-10-15 
00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/t/24-worker-jobs.t 2026-10-16 
08:29:58.000000000 +0200
@@ -762,15 +762,26 @@
         },
         {
             json => {
+                outstanding_files => 0,
+                outstanding_images => 0,
+                upload_up_to => undef,
+                upload_up_to_current_module => undef
+            },
+            path => '/liveviewhandler/api/v1/jobs/5/upload_progress'
+        },
+        {
+            json => {
+                status => {
+                    uploading => 1,
+                    worker_id => 1
+                }
+            },
+            path => 'jobs/5/status'
+        },
+        {
+            json => {
                 status => {
                     cmd_srv_url => $engine_url,
-                    log => {},
-                    serial_log => {},
-                    serial_terminal => {},
-                    serial_terminal_user => {
-                        'data' => '',
-                        'offset' => (length $user_console_text)
-                    },
                     test_execution_paused => 0,
                     worker_hostname => '127.0.0.1',
                     worker_id => 1
@@ -780,21 +791,24 @@
         },
         {
             json => {
-                outstanding_files => 0,
-                outstanding_images => 0,
-                upload_up_to => undef,
-                upload_up_to_current_module => undef
+                status => {
+                    cmd_srv_url => $engine_url,
+                    result => {},
+                    test_execution_paused => 0,
+                    test_order => [],
+                    worker_hostname => '127.0.0.1',
+                    worker_id => 1
+                }
             },
-            path => '/liveviewhandler/api/v1/jobs/5/upload_progress'
+            path => 'jobs/5/status'
         },
-        usual_status_updates(job_id => 5),
         {
             json => undef,
             path => 'jobs/5/set_done',
             worker_id => 1,
         }
       ],
-      'expected REST-API calls happened'
+      'expected REST-API calls happened, uploads serialized by the re-entrancy 
guard'
       or always_explain $client->sent_messages;
     $client->sent_messages([]);
 
@@ -832,6 +846,89 @@
     };
 };
 
+subtest 'Avoiding concurrent result uploads' => sub {
+    my $client_mock = Test::MockModule->new('Test::FakeClient', no_auto => 1);
+    my @sent;
+    my @pending;
+    $client_mock->redefine(
+        send => sub ($self, $method, $path, %args) {
+            push @sent, $path;
+            push @pending, $args{callback} if $args{callback} && 
$args{callback} ne 'no';
+        });
+    my %timers;
+    my $next_timer_id = 1000;
+    $io_loop_mock->redefine(
+        timer => sub ($io, $delay, $cb) {
+            my $id = $next_timer_id++;
+            $timers{$id} = $cb;
+            return $id;
+        },
+        remove => sub ($io, $id) { delete $timers{$id} });
+    my $drain = sub {
+        Mojo::IOLoop->next_tick(sub { Mojo::IOLoop->stop });
+        Mojo::IOLoop->start;
+    };
+
+    subtest 'calling _upload_results while an upload is in flight defers it 
until the ongoing one concludes' => sub {
+        @sent = ();
+        @pending = ();
+        %timers = ();
+        my $job = OpenQA::Worker::Job->new($worker, $client, {id => 8, URL => 
$engine_url});
+        $job->{_engine} = {child => Test::FakeEngine->new};
+        $job->_upload_results(sub { });
+        is scalar(@pending), 1, 'ongoing upload posts jobs/8/status once and 
is in flight';
+        my $deferred_invoked = 0;
+        $job->_upload_results(sub { ++$deferred_invoked });
+        is scalar(@pending), 1, 'no second status post while an upload is in 
flight';
+        ok $job->is_uploading_results, 'job still considered uploading 
results';
+        shift(@pending)->({});
+        $drain->();
+        is scalar(@pending), 1, 'deferred upload posts status right after the 
ongoing one concluded';
+        is scalar(@sent), 2, 'status posts are serialized instead of 
concurrent';
+        shift(@pending)->({});
+        $drain->();
+        is $deferred_invoked, 1, 'callback of the deferred upload invoked 
after its upload concluded';
+        is scalar(keys %timers), 1, 'exactly one upload timer active after 
both uploads concluded';
+        ok defined $job->{_upload_results_timer}, 'job tracks the remaining 
upload timer';
+        (values %timers)[0]->();
+        is scalar(@pending), 1, 'remaining timer fires exactly one new upload';
+        is scalar(@sent), 3, 'timer-triggered upload posts status';
+        shift(@pending)->({});
+        $drain->();
+        is scalar(keys %timers), 1, 'still exactly one upload timer after the 
timer-triggered upload concluded';
+    };
+
+    subtest 'engine startup with livelog viewer registered before the backend 
runs posts status only once at a time' =>
+      sub {
+        @sent = ();
+        @pending = ();
+        %timers = ();
+        my $job = OpenQA::Worker::Job->new($worker, $client, {id => 9, URL => 
$engine_url});
+        $job->start_livelog;
+        is $job->livelog_viewers, 1, 'viewer registered before the backend 
runs';
+        is scalar(@pending), 0, 'no upload triggered while the backend is not 
running';
+        $job->{_engine} = {child => Test::FakeEngine->new};
+        Mojo::IOLoop->next_tick(
+            sub {
+                $job->_upload_results(sub { });
+            });
+        combined_like { $job->_add_livelog_viewers(0) } qr/Starting livelog/, 
'livelog started with engine';
+        is scalar(@pending), 1, 'livelog start triggers one status post';
+        $drain->();
+        is scalar(@pending), 1, 'next_tick upload is deferred, so never two 
concurrent status posts';
+        is scalar(@sent), 1, 'only the livelog upload posted status so far';
+        shift(@pending)->({});
+        $drain->();
+        is scalar(@sent), 2, 'deferred upload posts status after the ongoing 
one concluded';
+        shift(@pending)->({});
+        $drain->();
+        is scalar(keys %timers), 1, 'exactly one upload timer remains after 
the startup scenario';
+      };
+
+    $client_mock->unmock('send');
+    $io_loop_mock->unmock('timer', 'remove');
+};
+
 subtest 'handling API failures' => sub {
     is_deeply $client->websocket_connection->sent_messages, [], 'no WebSocket 
calls yet';
     is_deeply $client->sent_messages, [], 'no REST-API calls yet';
@@ -1046,7 +1143,7 @@
 
     # assume the ongoing upload has concluded: this is supposed to continue 
stopping the job which is in turn
     # supposed to trigger the final upload
-    $job->emit(uploading_results_concluded => {});
+    $job->conclude_upload_if_ongoing;
 
     wait_until_job_status_ok($job, 'stopped');
     ok $final_result_upload_invoked, 'final result upload invoked';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1792016843.dbd2549e/t/ui/15-admin-workers.t 
new/openQA-5.1792132198.63d05d40/t/ui/15-admin-workers.t
--- old/openQA-5.1792016843.dbd2549e/t/ui/15-admin-workers.t    2026-10-15 
00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/t/ui/15-admin-workers.t    2026-10-16 
08:29:58.000000000 +0200
@@ -310,5 +310,75 @@
     $w2->delete;
 };
 
+subtest 'host previous jobs table' => sub {
+    $driver->get('/admin/worker_hosts/localhost');
+    wait_for_ajax;
+    my $table = $driver->find_element_by_id('previous_host_jobs');
+    ok $table, 'host previous jobs table found';
+    my @entries = map { $_->get_text() } $driver->find_child_elements($table, 
'tbody/tr/td', 'xpath');
+    is scalar @entries, 8, 'two previous jobs shown (4 cols per row)';
+    is_deeply
+      \@entries,
+      [
+        'opensuse-13.1-NET-x86_64-Build0091-kde@64bit',
+        ':1', '', 'not yet', 
'opensuse-Factory-staging_e-x86_64-Build87.5011-minimalx@32bit (restarted)',
+        ':1', '0', '1 hour ago',
+      ],
+      'host previous jobs ordered by completion time descending by default';
+
+    $driver->find_element('#previous_host_jobs thead th:nth-child(4)')->click;
+    my @expected = (
+        'opensuse-Factory-staging_e-x86_64-Build87.5011-minimalx@32bit 
(restarted)',
+        ':1', '0', '1 hour ago', 
'opensuse-13.1-NET-x86_64-Build0091-kde@64bit',
+        ':1', '', 'not yet',
+    );
+    @entries = ();
+    wait_for {
+        @entries = map { $_->[0] } @{map_elements('#previous_host_jobs tbody 
tr td', 'e.textContent.trim()')};
+        @entries == @expected && $entries[0] =~ /Factory/ && $entries[4] =~ 
/NET/
+    }
+    'host previous jobs sorted by completion time ascending';
+    is_deeply \@entries, \@expected, 'host previous jobs sorted by completion 
time ascending after clicking column';
+};
+
+subtest 'worker previous jobs table' => sub {
+    $driver->get('/admin/workers/1');
+    wait_for_ajax;
+    my $table = $driver->find_element_by_id('previous_jobs');
+    my @entries = map { $_->get_text() } $driver->find_child_elements($table, 
'tbody/tr/td', 'xpath');
+    is_deeply \@entries,
+      [
+        'opensuse-13.1-NET-x86_64-Build0091-kde@64bit',
+        '', 'not yet', 
'opensuse-Factory-staging_e-x86_64-Build87.5011-minimalx@32bit (restarted)',
+        '0', '1 hour ago',
+      ],
+      'worker previous jobs ordered by completion time descending by default';
+};
+
+subtest 'host previous jobs slot column sorts by worker instance number' => 
sub {
+    my $w3 = $workers->create({id => 7, host => 'localhost', instance => 3});
+    my $w4 = $workers->create({id => 9, host => 'localhost', instance => 2});
+    $jobs->find(99963)->update({assigned_worker_id => $w3->id});
+    $jobs->find(99961)->update({assigned_worker_id => $w4->id});
+
+    $driver->get('/admin/worker_hosts/localhost');
+    wait_for_ajax;
+    $driver->find_element('#previous_host_jobs thead th:nth-child(2)')->click;
+    my @slots;
+    wait_for {
+        @slots
+          = map { $_->[0] } @{map_elements('#previous_host_jobs tbody tr 
td:nth-child(2)', 'e.textContent.trim()')};
+        @slots == 3 && "@slots" eq ':1 :2 :3'
+    }
+    'slot column sorted by worker instance number ascending';
+    is_deeply \@slots, [':1', ':2', ':3'],
+      'slot column sorted by worker instance number ascending rather than by 
worker id';
+
+    $jobs->find(99961)->update({assigned_worker_id => 1});
+    $jobs->find(99963)->update({assigned_worker_id => undef});
+    $w3->delete;
+    $w4->delete;
+};
+
 kill_driver();
 done_testing();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1792016843.dbd2549e/templates/webapi/admin/workers/show_host.html.ep
 
new/openQA-5.1792132198.63d05d40/templates/webapi/admin/workers/show_host.html.ep
--- 
old/openQA-5.1792016843.dbd2549e/templates/webapi/admin/workers/show_host.html.ep
   2026-10-15 00:27:23.000000000 +0200
+++ 
new/openQA-5.1792132198.63d05d40/templates/webapi/admin/workers/show_host.html.ep
   2026-10-16 08:29:58.000000000 +0200
@@ -7,7 +7,7 @@
     cancel_url = "<%= url_for("apiv1_cancel", jobid => 'REPLACEIT') %>";
     updateTimeago();
     setupResultButtons();
-    setupWorkerNeedles();
+    setupHostPreviousJobs();
 % end
 
 <div class="row">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1792016843.dbd2549e/tools/ci/autoinst.sha 
new/openQA-5.1792132198.63d05d40/tools/ci/autoinst.sha
--- old/openQA-5.1792016843.dbd2549e/tools/ci/autoinst.sha      2026-10-15 
00:27:23.000000000 +0200
+++ new/openQA-5.1792132198.63d05d40/tools/ci/autoinst.sha      2026-10-16 
08:29:58.000000000 +0200
@@ -1 +1 @@
-5.044000-3b85101553bc9ee20b29916a47d5ce879de2f2f1
\ No newline at end of file
+5.044000-50bc19e891aec51e4f61cec73e78abb6b308ce4b
\ No newline at end of file

++++++ openQA.obsinfo ++++++
--- /var/tmp/diff_new_pack.Td4Bic/_old  2026-10-16 20:14:33.064427372 +0200
+++ /var/tmp/diff_new_pack.Td4Bic/_new  2026-10-16 20:14:33.074427792 +0200
@@ -1,5 +1,5 @@
 name: openQA
-version: 5.1792016843.dbd2549e
-mtime: 1792016843
-commit: dbd2549e6c3b22679edae4c011708893dc85fc7e
+version: 5.1792132198.63d05d40
+mtime: 1792132198
+commit: 63d05d409d6cf5d2712ed3b2ea326913b7f90563
 

Reply via email to