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-07-18 22:24:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new.24530 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Sat Jul 18 22:24:40 2026 rev:868 rq:1366461 version:5.1784324412.123ebeb6 Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2026-07-17 01:45:49.742000270 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new.24530/openQA.changes 2026-07-18 22:25:37.043350645 +0200 @@ -1,0 +2,10 @@ +Fri Jul 17 22:54:52 UTC 2026 - [email protected] + +- Update to version 5.1784324412.123ebeb6: + * fix: avoid foreign key error in screenshot_links + * fix(test): Drop test for token equality + * fix: Call open_sqlite_database with correct arguments + * chore(deps): Dependency cron 2026-07-17 + * feat: Improve scalability of dependency tree computation + +------------------------------------------------------------------- Old: ---- openQA-5.1784178984.04ce3617.obscpio New: ---- openQA-5.1784324412.123ebeb6.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA-client-test.spec ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:40.299460610 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:40.311461015 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-client Name: %{short_name}-test -Version: 5.1784178984.04ce3617 +Version: 5.1784324412.123ebeb6 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-devel-test.spec ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:40.555469256 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:40.559469391 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-devel Name: %{short_name}-test -Version: 5.1784178984.04ce3617 +Version: 5.1784324412.123ebeb6 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA-test.spec ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:40.627471688 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:40.631471823 +0200 @@ -18,7 +18,7 @@ %define short_name openQA Name: %{short_name}-test -Version: 5.1784178984.04ce3617 +Version: 5.1784324412.123ebeb6 Release: 0 Summary: Test package for openQA License: GPL-2.0-or-later ++++++ openQA-worker-test.spec ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:40.667473039 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:40.671473174 +0200 @@ -18,7 +18,7 @@ %define short_name openQA-worker Name: %{short_name}-test -Version: 5.1784178984.04ce3617 +Version: 5.1784324412.123ebeb6 Release: 0 Summary: Test package for %{short_name} License: GPL-2.0-or-later ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:40.723474930 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:40.727475065 +0200 @@ -104,7 +104,7 @@ %define devel_requires %devel_no_selenium_requires chromedriver Name: openQA -Version: 5.1784178984.04ce3617 +Version: 5.1784324412.123ebeb6 Release: 0 Summary: Framework for automated system-level testing (web-frontend, scheduler and tools) Group: Development/Tools/Other ++++++ openQA-5.1784178984.04ce3617.obscpio -> openQA-5.1784324412.123ebeb6.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/lib/OpenQA/CacheService/DB.pm new/openQA-5.1784324412.123ebeb6/lib/OpenQA/CacheService/DB.pm --- old/openQA-5.1784178984.04ce3617/lib/OpenQA/CacheService/DB.pm 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/lib/OpenQA/CacheService/DB.pm 2026-07-17 23:40:12.000000000 +0200 @@ -38,6 +38,6 @@ return $sqlite; } -sub open_default_sqlite_database ($log, $location) { open_sqlite_database($location, db_file($location)) } +sub open_default_sqlite_database ($log, $location) { open_sqlite_database($log, db_file($location)) } 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/lib/OpenQA/Schema/Result/Jobs.pm new/openQA-5.1784324412.123ebeb6/lib/OpenQA/Schema/Result/Jobs.pm --- old/openQA-5.1784178984.04ce3617/lib/OpenQA/Schema/Result/Jobs.pm 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/lib/OpenQA/Schema/Result/Jobs.pm 2026-07-17 23:40:12.000000000 +0200 @@ -2046,8 +2046,20 @@ } sub latest_job ($self) { - return $self unless my $clone = $self->clone; - return $clone->latest_job; + my $latest = $self->{_latest}; + return $latest if defined $latest; + my $self_id = $self->id; + my $schema = $self->result_source->schema; + my $sth = $schema->storage->dbh->prepare(' + with recursive clone_id as ( + select ? as clone_id + union all + select jobs.clone_id as clone_id from jobs join clone_id on clone_id.clone_id = jobs.id where jobs.clone_id is not null) + select clone_id from clone_id order by clone_id desc limit 1;'); + $sth->bind_param(1, $self_id, SQL_BIGINT); + $sth->execute; + my $latest_id = $sth->fetchrow_array; + $self->{_latest} = $latest_id == $self_id ? $self : $schema->resultset('Jobs')->find($latest_id); } sub handle_retry ($self) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/lib/OpenQA/Schema/ResultSet/Screenshots.pm new/openQA-5.1784324412.123ebeb6/lib/OpenQA/Schema/ResultSet/Screenshots.pm --- old/openQA-5.1784178984.04ce3617/lib/OpenQA/Schema/ResultSet/Screenshots.pm 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/lib/OpenQA/Schema/ResultSet/Screenshots.pm 2026-07-17 23:40:12.000000000 +0200 @@ -7,8 +7,9 @@ use Mojo::Base 'DBIx::Class::ResultSet', -signatures; use Mojo::File qw(path); -use OpenQA::Log qw(log_trace log_error); +use OpenQA::Log qw(log_trace log_debug log_error); use OpenQA::Utils qw(imagesdir); +use Feature::Compat::Try; sub create_screenshot ($self, $img) { my $dbh = $self->result_source->schema->storage->dbh; @@ -22,14 +23,31 @@ # insert the symlinks into the DB sub populate_images_to_job ($self, $imgs, $job_id) { - my %ids; + my $schema = $self->result_source->schema; + my $screenshot_links_rs = $schema->resultset('ScreenshotLinks'); + for my $img (@$imgs) { log_trace "creating $img"; - my $res = $self->create_screenshot($img)->fetchrow_arrayref; - $ids{$img} = $res ? $res->[0] : $self->find({filename => $img})->id; + try { + $schema->txn_do( + sub { + my $res = $self->create_screenshot($img)->fetchrow_arrayref; + my $screenshot_id = $res ? $res->[0] : $self->find({filename => $img})->id; + $screenshot_links_rs->create({screenshot_id => $screenshot_id, job_id => $job_id}); + }); + } + catch ($err) { + if ($err =~ /screenshot_links_fk_job_id/) { + log_debug "Job $job_id has been deleted, skipping screenshot links"; + } + elsif ($err =~ /screenshot_links_fk_screenshot_id/) { + log_debug "Screenshot $img has been deleted, skipping screenshot link"; + } + else { + die $err; + } + } } - my @data = map { [$_, $job_id] } values %ids; - $self->result_source->schema->resultset('ScreenshotLinks')->populate([[qw(screenshot_id job_id)], @data]); } # scans the image directories for untracked screenshots and deletes them diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/lib/OpenQA/WebAPI/Controller/Test.pm new/openQA-5.1784324412.123ebeb6/lib/OpenQA/WebAPI/Controller/Test.pm --- old/openQA-5.1784178984.04ce3617/lib/OpenQA/WebAPI/Controller/Test.pm 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/lib/OpenQA/WebAPI/Controller/Test.pm 2026-07-17 23:40:12.000000000 +0200 @@ -1173,9 +1173,9 @@ # show only the latest child jobs but still require the cloned job to be an actual child if ($as_child_of) { - my $clone = $job->clone; - if ($clone && $clone->is_child_of($as_child_of)) { - return _add_job($dependency_data, $clone, $as_child_of, $preferred_depth); + my $latest_job = $job->latest_job; + if ($latest_job != $job && $latest_job->is_child_of($as_child_of)) { + return _add_job($dependency_data, $latest_job, $as_child_of, $preferred_depth); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/t/42-screenshots.t new/openQA-5.1784324412.123ebeb6/t/42-screenshots.t --- old/openQA-5.1784178984.04ce3617/t/42-screenshots.t 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/t/42-screenshots.t 2026-07-17 23:40:12.000000000 +0200 @@ -269,4 +269,53 @@ is $error_count, 0, 'deletion happened without errors (1)'; }; +subtest 'populate_images_to_job handling of deleted/non-existent jobs' => sub { + use Test::MockModule; + my $mock_screenshots = Test::MockModule->new('OpenQA::Schema::ResultSet::Screenshots'); + $mock_screenshots->redefine(log_debug => sub { }); + + my $mock_rs = Test::MockModule->new('DBIx::Class::ResultSet'); + $mock_rs->redefine( + create => sub { + my ($self, @args) = @_; + if ($self->result_source->source_name eq 'ScreenshotLinks') { + my $job_id = $args[0]->{job_id}; + if ($job_id == 123456 || $job_id == 99927) { + die 'DBIx::Class::Storage::DBI::_dbh_execute_for_fetch(): ' + . 'execute_for_fetch() aborted with \'ERROR: insert or update on table "screenshot_links" ' + . 'violates foreign key constraint "screenshot_links_fk_job_id"\''; + } + if ($job_id == 88888) { + die 'DBIx::Class::Storage::DBI::_dbh_execute_for_fetch(): ' + . 'execute_for_fetch() aborted with \'ERROR: insert or update on table "screenshot_links" ' + . 'violates foreign key constraint "screenshot_links_fk_screenshot_id"\''; + } + if ($job_id == 77777) { + die 'DBIx::Class::Storage::DBI::_dbh_execute_for_fetch(): some other error'; + } + } + return $mock_rs->original('create')->($self, @args); + }); + + lives_ok { $screenshots->populate_images_to_job(['foo'], 123456) } + 'does not crash when job does not exist'; + + lives_ok { $screenshots->populate_images_to_job(['foo'], 99927) } + 'handles race condition and does not crash when job is deleted during populate'; + + lives_ok { $screenshots->populate_images_to_job(['foo'], 88888) } + 'handles race condition and does not crash when screenshot is deleted during populate'; + + dies_ok { $screenshots->populate_images_to_job(['foo'], 77777) } + 're-throws unexpected exceptions'; + + my $job = $jobs->create({TEST => 'dummy_for_cov'}); + lives_ok { $screenshots->populate_images_to_job(['foo'], $job->id) } + 'can successfully create screenshot link'; + $job->delete; + + $mock_rs->unmock_all; + $mock_screenshots->unmock_all; +}; + done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/t/ui/02-csrf.t new/openQA-5.1784324412.123ebeb6/t/ui/02-csrf.t --- old/openQA-5.1784178984.04ce3617/t/ui/02-csrf.t 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/t/ui/02-csrf.t 2026-07-17 23:40:12.000000000 +0200 @@ -31,8 +31,6 @@ ok $token =~ /[0-9a-z]{40}/, 'csrf token in meta tag'; ok $t->tx->res->dom->at('meta[name=csrf-param]')->attr('content') eq 'csrf_token', 'csrf param in meta tag'; -is $token, $t->tx->res->dom->at('form input[name=csrf_token]')->{value}, 'token is the same in form'; - # test cancel with and without CSRF token $t->post_ok('/api/v1/jobs/99928/cancel' => form => {csrf_token => 'foobar'})->status_is(403); $t->post_ok('/api/v1/jobs/99928/cancel' => {'X-CSRF-Token' => $token} => form => {})->status_is(200); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/t/ui/16-tests_dependencies.t new/openQA-5.1784324412.123ebeb6/t/ui/16-tests_dependencies.t --- old/openQA-5.1784178984.04ce3617/t/ui/16-tests_dependencies.t 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/t/ui/16-tests_dependencies.t 2026-07-17 23:40:12.000000000 +0200 @@ -109,7 +109,11 @@ always_explain $t->tx->res->json unless $t->success; %cluster = (cluster_99963 => [99963, 99961]); - @edges = ({from => 99937, to => 99938}, {from => 99961, to => 99927}, {from => 99938, to => 99963}); + @edges = ( + {from => 99937, to => 99945}, + {from => 99937, to => 99938}, + {from => 99961, to => 99927}, + {from => 99938, to => 99963}); @nodes = ( { @basic_node, @@ -130,6 +134,16 @@ }, { @basic_node, + id => 99945, + label => 'textmode@32bit', + result => PASSED, + state => DONE, + name => node_name('13.1-DVD-i586-Build0091-textmode@32bit', 1, 1, 99937, 2), + chained => ['kde'], + parallel => [], + }, + { + @basic_node, id => 99963, label => 'kde@64bit', result => NONE, @@ -227,8 +241,8 @@ is scalar @child_elements, $expected_count, $test_name; }; $check_element_quandity->('.cluster', 1, 'one cluster present'); - $check_element_quandity->('.edgePath', 3, 'three edges present'); - $check_element_quandity->('.node', 5, 'five nodes present'); + $check_element_quandity->('.edgePath', 4, 'three edges present'); + $check_element_quandity->('.node', 6, 'five nodes present'); like get_tooltip(99938), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-5.1784178984.04ce3617/tools/ci/autoinst.sha new/openQA-5.1784324412.123ebeb6/tools/ci/autoinst.sha --- old/openQA-5.1784178984.04ce3617/tools/ci/autoinst.sha 2026-07-16 07:16:24.000000000 +0200 +++ new/openQA-5.1784324412.123ebeb6/tools/ci/autoinst.sha 2026-07-17 23:40:12.000000000 +0200 @@ -1 +1 @@ -791afcb11e0cc9cb996b1b13be4a0bf8af3f0155 \ No newline at end of file +703db922d4e3ddc6ec80cddccc127c719bf6558a \ No newline at end of file ++++++ openQA.obsinfo ++++++ --- /var/tmp/diff_new_pack.7boIFF/_old 2026-07-18 22:25:55.371969639 +0200 +++ /var/tmp/diff_new_pack.7boIFF/_new 2026-07-18 22:25:55.371969639 +0200 @@ -1,5 +1,5 @@ name: openQA -version: 5.1784178984.04ce3617 -mtime: 1784178984 -commit: 04ce3617510cf57f12f06b63c33688b64a151663 +version: 5.1784324412.123ebeb6 +mtime: 1784324412 +commit: 123ebeb6f53202b19240394804dd5fb49d199d88
