Hello community, here is the log from the commit of package openQA for openSUSE:Factory checked in at 2018-05-08 13:37:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openQA (Old) and /work/SRC/openSUSE:Factory/.openQA.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openQA" Tue May 8 13:37:22 2018 rev:19 rq:604660 version:4.5.1525548058.3f6bb61a Changes: -------- --- /work/SRC/openSUSE:Factory/openQA/openQA.changes 2018-04-27 16:08:48.735413244 +0200 +++ /work/SRC/openSUSE:Factory/.openQA.new/openQA.changes 2018-05-08 13:37:22.537475917 +0200 @@ -1,0 +2,40 @@ +Sat May 05 19:21:21 UTC 2018 - [email protected] + +- Update to version 4.5.1525548058.3f6bb61a: + * Avoid appending multiple runs with --nocleanup (#1644) + * Limit number of tasks for limit_assets and limit_results_and_logs GRU tasks + * Add test for GRU enqueue limit option + * Update apparmor profile for worker (#1645) + * GRU: Add support to limit enqueuing by task + * Update unit tests for TAP parser + * Mark test suite as failed if test steps have failed + * Add information about openQA internal results + * Update TAP format documentation + * Remove dots from filename + * Ensure that the details description is set + * Use a single result to contain all the test steps + * Update changes to TAP format + * Temporary version of the parser for TAP still failing + * Log a warning when step data is not found + * Allow LTP parser to load files that contain special characters + * Replace extra dots in the filenames (#1642) + * Increase the required coverage to 88.8 + * Do not fail a pull request if there are unexpected changes + * Use same width for each colored dep status span + * Show parent and child deps on job page in nice tbl + * Enhance unit tests for GRU TTL + * Set 2 days of ttl for limit_assets and limit_results_and_logs when posting isos + * Add unit test for GRU task TTL + * GRU: Add TTL for Minion jobs + * Use a smaller font for the 'ago time' to fix rendering (#1635) + * Prefetch comment counts for /tests + * Update bootstrap to 4.1.1 and fontawesome to 5.0.10 + * Do not load full application to generate assetpack data (#1628) + * Improve the duplication tests (#1627) + * Hide categories when filtering test details + * Ensure needles directory exists in 18-tests-details.t + * Require 'Selenium::Remote::WDKeys' in CPAN file + * Add test for filtering test details + * Allow filtering test details + +------------------------------------------------------------------- Old: ---- openQA-4.5.1524586233.92db89bc.tar.xz New: ---- openQA-4.5.1525548058.3f6bb61a.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openQA.spec ++++++ --- /var/tmp/diff_new_pack.L34UYI/_old 2018-05-08 13:37:23.309448055 +0200 +++ /var/tmp/diff_new_pack.L34UYI/_new 2018-05-08 13:37:23.309448055 +0200 @@ -36,7 +36,7 @@ # runtime requirements that also the testsuite needs %define t_requires perl(DBD::Pg) perl(DBIx::Class) perl(Config::IniFiles) perl(SQL::Translator) perl(Date::Format) perl(File::Copy::Recursive) perl(DateTime::Format::Pg) perl(Net::OpenID::Consumer) perl(Mojolicious::Plugin::RenderFile) perl(Mojolicious::Plugin::AssetPack) perl(aliased) perl(Config::Tiny) perl(DBIx::Class::DynamicDefault) perl(DBIx::Class::Schema::Config) perl(DBIx::Class::Storage::Statistics) perl(IO::Socket::SSL) perl(Data::Dump) perl(DBIx::Class::OptimisticLocking) perl(Text::Markdown) perl(Net::DBus) perl(IPC::Run) perl(Archive::Extract) perl(CSS::Minifier::XS) perl(JavaScript::Minifier::XS) perl(Time::ParseDate) perl(Sort::Versions) perl(Mojo::RabbitMQ::Client) perl(BSD::Resource) perl(Cpanel::JSON::XS) perl(Pod::POM) perl(Mojo::IOLoop::ReadWriteProcess) perl(Minion) perl(Mojo::Pg) Name: openQA -Version: 4.5.1524586233.92db89bc +Version: 4.5.1525548058.3f6bb61a Release: 0 Summary: The openQA web-frontend, scheduler and tools License: GPL-2.0+ ++++++ cache.txz ++++++ Binary files /var/tmp/diff_new_pack.L34UYI/_old and /var/tmp/diff_new_pack.L34UYI/_new differ ++++++ openQA-4.5.1524586233.92db89bc.tar.xz -> openQA-4.5.1525548058.3f6bb61a.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/assets/assetpack.def new/openQA-4.5.1525548058.3f6bb61a/assets/assetpack.def --- old/openQA-4.5.1524586233.92db89bc/assets/assetpack.def 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/assets/assetpack.def 2018-05-05 21:20:58.000000000 +0200 @@ -1,102 +1,103 @@ ! bootstrap.css # download the fonts < https://cdn.datatables.net/1.10.16/css/dataTables.bootstrap4.css -< https://use.fontawesome.com/releases/v5.0.0/css/all.css -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-brands-400.eot -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-brands-400.woff2 -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-brands-400.ttf -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-brands-400.svg -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-regular-400.eot -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-regular-400.woff2 -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-regular-400.ttf -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-regular-400.svg -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-solid-900.eot -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-solid-900.woff2 -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-solid-900.ttf -<< https://use.fontawesome.com/releases/v5.0.0/webfonts/fa-solid-900.svg +< https://use.fontawesome.com/releases/v5.0.10/css/all.css +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-brands-400.eot +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-brands-400.woff2 +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-brands-400.ttf +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-brands-400.svg +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-regular-400.eot +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-regular-400.woff2 +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-regular-400.ttf +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-regular-400.svg +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-solid-900.eot +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-solid-900.woff2 +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-solid-900.ttf +<< https://use.fontawesome.com/releases/v5.0.10/webfonts/fa-solid-900.svg < stylesheets/openqa.scss < https://raw.githubusercontent.com/bootstrapthemesco/bootstrap-4-multi-dropdown-navbar/beta2.0/css/bootstrap-4-navbar.css < https://cdnjs.cloudflare.com/ajax/libs/chosen/1.7.0/chosen.css -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/bootstrap.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_functions.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_variables.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_mixins.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_breakpoints.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_hover.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_image.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_badge.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_resize.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_screen-reader.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_size.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_reset-text.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_text-emphasis.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_text-hide.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_text-truncate.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_visibility.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_alert.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_buttons.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_caret.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_pagination.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_lists.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_list-group.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_nav-divider.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_forms.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_table-row.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_background-variant.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_border-radius.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_box-shadow.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_gradients.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_transition.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_clearfix.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_grid-framework.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_grid.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/mixins/_float.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_root.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_reboot.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_type.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_images.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_code.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_grid.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_tables.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_forms.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_buttons.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_transitions.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_dropdown.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_button-group.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_input-group.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_custom-forms.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_nav.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_navbar.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_card.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_breadcrumb.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_pagination.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_badge.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_jumbotron.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_alert.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_progress.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_media.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_list-group.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_close.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_modal.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_tooltip.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_popover.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_carousel.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_utilities.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_align.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_background.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_borders.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_clearfix.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_display.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_embed.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_flex.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_float.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_position.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_screenreaders.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_sizing.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_spacing.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_text.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/utilities/_visibility.scss -<< https://raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/_print.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/bootstrap.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_functions.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_variables.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_mixins.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_breakpoints.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_hover.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_image.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_badge.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_resize.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_screen-reader.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_size.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_reset-text.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_text-emphasis.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_text-hide.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_text-truncate.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_visibility.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_alert.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_buttons.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_caret.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_pagination.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_lists.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_list-group.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_nav-divider.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_forms.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_table-row.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_background-variant.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_border-radius.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_box-shadow.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_gradients.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_transition.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_clearfix.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_grid-framework.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_grid.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/mixins/_float.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_root.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_reboot.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_type.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_images.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_code.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_grid.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_tables.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_forms.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_buttons.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_transitions.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_dropdown.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_button-group.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_input-group.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_custom-forms.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_nav.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_navbar.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_card.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_breadcrumb.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_pagination.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_badge.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_jumbotron.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_alert.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_progress.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_media.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_list-group.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_close.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_modal.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_tooltip.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_popover.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_carousel.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_utilities.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_align.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_background.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_borders.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_clearfix.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_display.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_embed.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_flex.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_float.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_position.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_screenreaders.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_shadows.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_sizing.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_spacing.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_text.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/utilities/_visibility.scss +<< https://raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/_print.scss < https://raw.githubusercontent.com/sorich87/bootstrap-tour/6a1028fb562f9aa68c451f0901f8cfeb43cad140/build/css/bootstrap-tour.css ! codemirror.css diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/assets/javascripts/test_result.js new/openQA-4.5.1525548058.3f6bb61a/assets/javascripts/test_result.js --- old/openQA-4.5.1524586233.92db89bc/assets/javascripts/test_result.js 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/assets/javascripts/test_result.js 2018-05-05 21:20:58.000000000 +0200 @@ -101,7 +101,10 @@ success: function(data) { previewSuccess(data, force); } - }).fail(function() { setCurrentPreview(null); }); + }).fail(function() { + console.warn('Failed to load data from: '+link.data("url")); + setCurrentPreview(null); + }); } else { // hide @@ -290,4 +293,53 @@ pauseLiveView(); } }); + + // setup result filter, define function to apply filter changes + var detailsFilter = $('.details-filter'); + var detailsNameFilter = $('#details-name-filter'); + var detailsFailedOnlyFilter = $('#details-only-failed-filter'); + var resultsTable = $('#results'); + var anyFilterEnabled = false; + var applyFilterChanges = function(event) { + // determine enabled filter + anyFilterEnabled = !detailsFilter.hasClass('hidden'); + if (anyFilterEnabled) { + var nameFilter = detailsNameFilter.val(); + var nameFilterEnabled = nameFilter.length !== 0; + var failedOnlyFilterEnabled = detailsFailedOnlyFilter.prop('checked'); + anyFilterEnabled = nameFilterEnabled || failedOnlyFilterEnabled; + } + + // show everything if no filter present + if (!anyFilterEnabled) { + resultsTable.find('tbody tr').show(); + return; + } + + // hide all categories + resultsTable.find('tbody tr td[colspan="3"]').parent('tr').hide(); + + // show/hide table rows considering filter + $.each(resultsTable.find('tbody .result'), function(index, td) { + var tdElement = $(td); + var trElement = tdElement.parent('tr'); + var stepMaches = ( + (!nameFilterEnabled + || trElement.find('td.component').text().indexOf(nameFilter) >= 0) + && (!failedOnlyFilterEnabled + || tdElement.hasClass('resultfailed') + || tdElement.hasClass('resultsoftfailed')) + ); + trElement[stepMaches ? 'show' : 'hide'](); + }); + }; + detailsNameFilter.keyup(applyFilterChanges); + detailsFailedOnlyFilter.change(applyFilterChanges); + + // setup filter toggle + $('.details-filter-toggle').on('click', function(event) { + event.preventDefault(); + detailsFilter.toggleClass('hidden'); + applyFilterChanges(); + }); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/openqa.scss new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/openqa.scss --- old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/openqa.scss 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/openqa.scss 2018-05-05 21:20:58.000000000 +0200 @@ -4,7 +4,7 @@ @import "openqa_theme.scss"; // include Bootstrap 4 -@import "../cache/raw.githubusercontent.com/twbs/bootstrap/v4.0.0/scss/bootstrap.scss"; +@import "../cache/raw.githubusercontent.com/twbs/bootstrap/v4.1.1/scss/bootstrap.scss"; // include custom css for various aspects of the pages @import "overall.scss"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/overview.scss new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/overview.scss --- old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/overview.scss 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/overview.scss 2018-05-05 21:20:58.000000000 +0200 @@ -10,6 +10,11 @@ background-color: #bbb; } +/* dotted underline looks strange with default font size */ +.h4 { + .smaller-font { font-size: 90%; } +} + #filter-panel, #live-log-panel, #live-terminal-panel { .card-header { cursor: pointer; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/test-details.scss new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/test-details.scss --- old/openQA-4.5.1524586233.92db89bc/assets/stylesheets/test-details.scss 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/assets/stylesheets/test-details.scss 2018-05-05 21:20:58.000000000 +0200 @@ -198,3 +198,35 @@ color: green; } } + +// filter for test details +.details-filter { + &.hidden { + display: none; + } + & > div { + margin-top: auto; + margin-bottom: auto; + } + .form-control { + display: inline-block !important; + width: auto !important; + } + label { + margin-bottom: 0px; + } + .result-filter-container { + text-align: right; + } +} +.details-filter-toggle { + display: inline-block; + float: right; + margin-top: -50px; +} + +.dependency_result { + width: 14em; + display: inline-block; + text-align: center; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/codecov.yml new/openQA-4.5.1525548058.3f6bb61a/codecov.yml --- old/openQA-4.5.1524586233.92db89bc/codecov.yml 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/codecov.yml 2018-05-05 21:20:58.000000000 +0200 @@ -10,12 +10,10 @@ - 95.0 round: down status: - changes: - default: - branches: null + changes: no project: default: - target: 87.8 + target: 88.8 threshold: 0.1 patch: default: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/cpanfile new/openQA-4.5.1525548058.3f6bb61a/cpanfile --- old/openQA-4.5.1524586233.92db89bc/cpanfile 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/cpanfile 2018-05-05 21:20:58.000000000 +0200 @@ -96,6 +96,7 @@ requires 'Perl::Critic'; requires 'Perl::Tidy', '>= 20180101, != 20180219'; requires 'Selenium::Remote::Driver', '>= 1.23'; + requires 'Selenium::Remote::WDKeys'; requires 'Test::Compile'; requires 'Test::Fatal'; requires 'Test::MockModule'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/docs/ExternalResults.asciidoc new/openQA-4.5.1525548058.3f6bb61a/docs/ExternalResults.asciidoc --- old/openQA-4.5.1524586233.92db89bc/docs/ExternalResults.asciidoc 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-4.5.1525548058.3f6bb61a/docs/ExternalResults.asciidoc 2018-05-05 21:20:58.000000000 +0200 @@ -0,0 +1,130 @@ + +[[installing]] += openQA test harness result processing +:toc: left +:toclevels: 6 +:author: openQA developers + +== Introduction +:parser-formats: <<parser-formats,parsers>> +:api-endpoint: <<webapi-endpoint,Web Api endpoint>> + +From time to time, a test developer might want to use openQA to execute a test +suite from a different test harness than openQA, but still use openQA to setup test +scenarios and prepare the environment for a test suite run; for this case openQA has +the hability to process logs from external harnesses, and display the results integrated +within the job results of the webUI. + +One could say that a Test Harness is supported if its output is compatible with +the available {parser-format}, such as LTP, and also xUnit or JUnit, but this can +be easily extended to include more formats, such as RSpec or TAP. + +The requirements to use this functionality, are quite simple: + +* The test harness must produce a compatible format with supported {parser-format}. +* The test results can be uploaded via +testapi::parse_extra_log+ within an openQA tests. +* The test results can also be uploaded via web {api-endpoint}. + +openQA will store these results in its own internal format for easier presentation, +but still will allow the original file to be downloaded. + +== Usage + +If a test developer wishes to use the functional interface, after finishing the +execution of the the testing too, calling +testapi::parse_extra_log+ with the +location to a the file generated. + +=== openQA test distribution + +From within a common openQA test distribution, a developer can use +parse_extra_log+ +to upload a text file that contains a supported test output: + +[source,perl] +------------------------------------------------------------------------------- +script_run('prove --verbose --formatter=TAP::Formatter::JUnit t/28-logging.t > junit-logging.xml'); +parse_extra_log('XUnit','junit-logging.xml'); +------------------------------------------------------------------------------- + +[[parser-formats]] +== Available parser formats + +Current parser formats: + +* OpenQA::Parser::Format::TAP, +* OpenQA::Parser::Format::JUnit +* OpenQA::Parser::Format::LTP +* OpenQA::Parser::Format::XUnit, + +== Extending the parser + +=== OOP Interface + +The parser is a base class that acts as a serializer/deserializer for the elements +inside of it, it allows to be extended so new formats can be easily added. + +The base class is exposing 4 Mojo::Collections available, according to what openQA +would require to map the results correctly, 1 extra collection is provided for +arbitrary data that can be exposed. The collections represents respectively: +test results, test definition and test output. + +=== Structured data + +In structured data mode, elements of the collections are objects. They can be +of any type, even though subclassing or objects of type of +OpenQA::Parser::Result+ +are prefered. + +One thing to keep in mind, is that in case deeply nested objects need to be parsed +like hash of hashes, array of hashes, they would need to subclass +OpenQA::Parser::Result+ +or +OpenQA::Parser::Results+ respectively. + +As an example, JUnit format can be parsed this way: + +[source,perl] +------------------------------------------------------------------------------- +use OpenQA::Parser::Format::JUnit; + +my $parser_result = OpenQA::Parser::Format::JUnit->new->load("file.xml"); + +# Now we can access to parsed tests as seen by openQA: + +$parser_result->tests->each(sub { + + my $test = shift; + print "Test name: ".$test->name; + +}); + +my @all = $parser_result->tests->each; +my @tests = $parser->tests->search(name => qr/1_running_upstream_tests/); +my $first = $parser->tests->search(name => qr/1_running_upstream_tests/)->first(); + +my $binary_data = $parser->serialize(); + +# Now, we can also store $binary_data and retrieve it later. + +my $new_parser_from_binary = OpenQA::Parser::Format::JUnit->new->deserialize($binary_data); + +# thus this works as expected: +$new_parser_from_binary->tests->each( sub { + + my $test = shift; + print "Test name: ".$test->name; + +}); + +# We can also serialize all to JSON + +my $json_serialization = $parser->to_json; + +# save it and access it later + +my $from_json = OpenQA::Parser::Format::JUnit->from_json($json_serialization); +------------------------------------------------------------------------------- + +=== openQA internal test result storage + +It is important to know that openQA's internal mapping for test results works operating almost +entirely on the filesystem, leaving only the test modules to be registered into the database, this +leads to the following relation: A test module's name is used to create a file with details +(details-$testmodule.json), that will contain a reference to step details, which is a collection of +references to files, using a field "text" as tie in, and expecting a filename. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/docs/index.asciidoc new/openQA-4.5.1525548058.3f6bb61a/docs/index.asciidoc --- old/openQA-4.5.1524586233.92db89bc/docs/index.asciidoc 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/docs/index.asciidoc 2018-05-05 21:20:58.000000000 +0200 @@ -13,6 +13,7 @@ include::Installing.asciidoc[] include::UsersGuide.asciidoc[] include::WritingTests.asciidoc[] +include::ExternalResults.asciidoc[] include::Pitfalls.asciidoc[] include::Networking.asciidoc[] include::Contributing.asciidoc[] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/JUnit.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/JUnit.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/JUnit.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/JUnit.pm 2018-05-05 21:20:58.000000000 +0200 @@ -100,8 +100,9 @@ $result->{result} = 'fail' if $tc_result eq 'fail'; my $details = {result => $tc_result}; - - my $text_fn = "$ts_category-$ts_name-$num.txt"; + my $text_fn = "$ts_category-$ts_name-$num"; + $text_fn =~ s/[\/.]/_/g; + $text_fn .= '.txt'; my $content = "# $tc->{name}\n"; for my $out ($tc->children('system-out, system-err, failure')->each) { $content .= "# " . $out->tag . ": \n\n"; @@ -165,13 +166,16 @@ results the respective test that generated it (inside the C<test()> attribute). See also L<OpenQA::Parser::Result::OpenQA>. +JUnit format is specific for slenkins tests. If you wish to use generic JUnit format, +use XUnit format instead. + =head1 ATTRIBUTES OpenQA::Parser::Format::JUnit inherits all attributes from L<OpenQA::Parser::Format::Base>. =head1 METHODS -OpenQA::Parser::Format::Base inherits all methods from L<OpenQA::Parser::Format::Base>, it only overrides +OpenQA::Parser::Format::JUnit inherits all methods from L<OpenQA::Parser::Format::Base>, it only overrides C<parse()> to generate a tree of results. =cut diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/LTP.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/LTP.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/LTP.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/LTP.pm 2018-05-05 21:20:58.000000000 +0200 @@ -19,7 +19,7 @@ # The parser results will be a collection of OpenQA::Parser::Result::LTP::Test use Mojo::Base 'OpenQA::Parser::Format::JUnit'; use Carp qw(croak confess); -use Mojo::JSON 'decode_json'; +use Cpanel::JSON::XS (); use Storable 'dclone'; has include_results => 1; @@ -29,7 +29,7 @@ sub parse { my ($self, $json) = @_; confess "No JSON given/loaded" unless $json; - my $decoded_json = decode_json $json; + my $decoded_json = Cpanel::JSON::XS->new->utf8(0)->decode($json); # may be optional since format result_array:v2 $self->generated_tests_extra->add(OpenQA::Parser::Result::LTP::Environment->new($decoded_json->{environment})) @@ -46,7 +46,7 @@ # may be optional since format result_array:v2 $result->{environment} = OpenQA::Parser::Result::LTP::Environment->new($result->{environment}) if $res->{environment}; - + $t_name =~ s/[\/.]/_/g; # dots in the filename confuse the web api routes $result->{name} = $t_name; my $details diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/TAP.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/TAP.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/TAP.pm 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/TAP.pm 2018-05-05 21:20:58.000000000 +0200 @@ -0,0 +1,168 @@ +# Copyright (C) 2018 SUSE LLC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, see <http://www.gnu.org/licenses/>. + +package OpenQA::Parser::Format::TAP; +# Translates to TAP -> openQA internal +use Mojo::Base 'OpenQA::Parser::Format::Base'; +use Carp qw(croak confess); +use OpenQA::Parser::Result::OpenQA; +use TAP::Parser; + +has [qw(test steps)]; + +sub parse { + my ($self, $TAP) = @_; + confess "No TAP given/loaded" unless $TAP; + my $tap = TAP::Parser->new({tap => $TAP}); + confess "Failed " . $tap->parse_errors if $tap->parse_errors; + my $test = { + flags => {}, + category => "TAP", + name => 'Extra test from TAP', + }; + my $details; + + $self->steps( + OpenQA::Parser::Result->new( + { + details => [], + dents => 0, + result => 'passed' + })); + my $m = 0; + while (my $res = $tap->next) { + my $result = $res; + if ($result->raw =~ m/^(.*\.(:?tap|t)) \.{2}/g) { + # most cases, teh output of a prove run will contain + # "/t/$filename.tap .." as name of the file + # use this to get the filename + $test->{name} = $1; + $test->{name} =~ s/[\/.]/_/g; + $self->test(OpenQA::Parser::Result->new($test)); + $self->_add_test($self->test); + next; + } + else { + confess "A valid TAP starts with filename.tap, and got: '@{[$result->raw]}'" unless $self->test; + } + + # For the time being only load known types + # Tests are supported and comments too + # stick for now to only test results. + next if $result->type eq 'plan'; # Skip plans for now + next if $result->type ne 'test'; + + my $t_filename = "TAP-@{[$test->{name}]}-$m.txt"; + my $t_description = $result->description; + $t_description =~ s/^- //; + $details = { + text => $t_filename, + title => $t_description, + result => ($result->is_actual_ok) ? 'ok' : 'fail', + }; + $self->steps->{result} = 'fail' if !$result->is_actual_ok; #Mark the suite as failed if it was not ok. + + # Ensure that text files are going to be written + # With the content that is relevant + my $data = {%$result, %$details}; + push @{$self->steps->{details}}, $data; + $self->_add_output( + { + file => $t_filename, + content => $res->raw + }); + ++$m; + } + $self->steps->{name} = $self->tests->first->{name}; + $self->steps->{test} = $self->tests->first; + $self->generated_tests_results->add(OpenQA::Parser::Result::OpenQA->new($self->steps)); +} + +=encoding utf-8 + +=head1 NAME + +OpenQA::Parser::Format::TAP - TAP file parser + +=head1 SYNOPSIS + + use OpenQA::Parser::Format::TAP; + + my $parser = OpenQA::Parser::Format::TAP->new()->load('test.tap'); + + # Alternative interface + use OpenQA::Parser qw(parser p); + + my $parser = p( TAP => 'test.tap' ); + + my $result_collection = $parser->results(); + my $test_collection = $parser->tests(); + my $output_collection = $parser->output(); + + my $arrayref = $result_collection->to_array; + + $parser->results->remove(0); + + my $passed_results = $parser->results->search( result => qr/ok/ ); + my $size = $passed_results->size; + +=head1 DESCRIPTION + +OpenQA::Parser::Format::TAP is the parser for Test Anything Protocol format. +The parser is making use of the C<tests()>, C<results()> and C<output()> collections. + +The parser will store the information from each test step along with the test step details. + +=head1 ATTRIBUTES + +OpenQA::Parser::Format::TAP inherits all attributes from L<OpenQA::Parser::Format::Base> and implements +the following attributes. + +=head2 test + +Holds an instance of C<OpenQA::Parser::Result> containing the details of the current test being parsed. + +=head2 steps + +Contains a list of the test lines provided by the TAP::Parser it is then combined and added as test results +via C<OpenQA::Parser::Format::Base::generated_tests_results>. + +=head1 METHODS + +OpenQA::Parser::Format::TAP inherits all methods from L<OpenQA::Parser::Format::Base>, it only overrides +C<parse()> to generate a simple tree of results. + +=head1 CAVEATS + +TAP parser will treat each file as a test case, with N steps, as such it expects C<filename.t ..> +or C<filename.tap ..> as the first line in the file to be parsed, further parsing will not be done +until this requirement is met. + +=over 4 + +=item SUBTESTS + +Currently TAP::Harness does not properly parse subtests, therefore they are not supported by this TAP parser, + +=item NOT SUPPORTED ELEMENTS + +As this is a simple implementation elements from C<Comments>, C<Plans>, C<Directives> and C<Bails> are not supported, therefore +are discarded by the parser. + +=back + +=cut + +!!42; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/XUnit.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/XUnit.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Parser/Format/XUnit.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Parser/Format/XUnit.pm 2018-05-05 21:20:58.000000000 +0200 @@ -83,7 +83,9 @@ $tc_result = 'fail' if ($tc->{failures} && $tc->{failures} > 0) || ($tc->{errors} && $tc->{errors} > 0); - my $text_fn = "$ts_category-$ts_name-$num.txt"; + my $text_fn = "$ts_category-$ts_name-$num"; + $text_fn =~ s/[\/.]/_/g; + $text_fn .= '.txt'; my $content = "# Test messages "; $content .= "# $tc->{name}\n" if $tc->{name}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Schema/Result/Jobs.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Schema/Result/Jobs.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Schema/Result/Jobs.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Schema/Result/Jobs.pm 2018-05-05 21:20:58.000000000 +0200 @@ -675,7 +675,8 @@ # i.e. to preven cloned parent to clone its children ## now go and clone and recreate test dependencies - parents first - my $parents = $self->parents->search( + my $parents = $self->search_for( + 'parents', { dependency => { -in => @@ -685,6 +686,7 @@ { join => 'parent', }); + while (my $pd = $parents->next) { my $p = $pd->parent; if (!exists $jobs_map->{$p->id}) { @@ -732,7 +734,8 @@ } ## go and clone and recreate test dependencies - running children tests, this cover also asset dependencies (use CHAINED dep) - my $children = $self->children->search( + my $children = $self->search_for( + 'children', { dependency => { -in => @@ -1932,6 +1935,11 @@ }; } +sub search_for { + my ($self, $result_set, $condition, $attrs) = @_; + return $self->$result_set->search($condition, $attrs); +} + 1; # vim: set sw=4 et: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Utils.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Utils.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Utils.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Utils.pm 2018-05-05 21:20:58.000000000 +0200 @@ -834,6 +834,9 @@ log_debug("Reading information from " . encode_json($step)); $step->{text_data} = $file->slurp; } + else { + log_debug("Cannot read file: $file"); + } } push(@details, $step); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Controller/API/V1/Iso.pm 2018-05-05 21:20:58.000000000 +0200 @@ -510,8 +510,8 @@ @successful_job_ids = (); }; - $self->gru->enqueue(limit_assets => [] => {priority => 10}); - $self->gru->enqueue(limit_results_and_logs => [] => {priority => 5}); + $self->gru->enqueue(limit_assets => [] => {priority => 10, ttl => 172800, limit => 1}); + $self->gru->enqueue(limit_results_and_logs => [] => {priority => 5, ttl => 172800, limit => 1}); $self->emit_event('openqa_iso_create', $args); for my $succjob (@successful_job_ids) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Controller/Test.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Controller/Test.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Controller/Test.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Controller/Test.pm 2018-05-05 21:20:58.000000000 +0200 @@ -115,6 +115,21 @@ $self->stash(scheduled => \@scheduled); } +sub prefetch_comment_counts { + my ($self, $job_ids) = @_; + + my $comments = $self->db->resultset("Comments")->search( + {'me.job_id' => {in => $job_ids}}, + { + select => ['job_id', {count => 'job_id', -as => 'count'}], + group_by => [qw(job_id)]}); + my $comment_count; + while (my $count = $comments->next) { + $comment_count->{$count->job_id} = $count->get_column('count'); + } + return $comment_count; +} + sub list_ajax { my ($self) = @_; my $assetid = $self->param('assetid'); @@ -154,6 +169,9 @@ order_by => ['me.t_finished DESC, me.id DESC'], prefetch => [qw(children parents)], })->all; + + my $comment_count = $self->prefetch_comment_counts(\@ids); + # need to use all as the order is too complex for a cursor for my $job (@jobs) { push( @@ -173,7 +191,7 @@ testtime => $job->t_finished . 'Z', result => $job->result, group => $job->group_id, - comment_count => $job->comments->count, + comment_count => $comment_count->{$job->id} // 0, state => $job->state }); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Plugin/Gru.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Plugin/Gru.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI/Plugin/Gru.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI/Plugin/Gru.pm 2018-05-05 21:20:58.000000000 +0200 @@ -90,6 +90,13 @@ my $args = shift // []; my $options = shift // {}; my $jobs = shift // []; + my $ttl = $options->{ttl} ? $options->{ttl} : undef; + my $limit = $options->{limit} ? $options->{limit} : undef; + + if (defined $limit) { + my $res = $self->app->minion->backend->list_jobs(0, undef, {tasks => [$task], states => ['inactive']}); + return undef if defined $res && exists $res->{total} && $res->{total} >= $limit; + } $args = [$args] if ref $args eq 'HASH'; @@ -105,7 +112,10 @@ }); $self->app->minion->enqueue( - $task => $args => {priority => $options->{priority} // 0, delay => $delay, notes => {gru_id => $gru->id}}); + $task => $args => { + priority => $options->{priority} // 0, + delay => $delay, + notes => {gru_id => $gru->id, (ttl => $ttl) x !!(defined $ttl)}}); } package OpenQA::WebAPI::Plugin::Gru::Command::gru; @@ -134,6 +144,16 @@ sub execute_job { my ($self, $job) = @_; + my $ttl = $job->info->{notes}{ttl}; + my $elapsed = time - $job->info->{created}; + my $ttl_error = 'TTL Expired'; + + return + exists $job->info->{notes}{gru_id} ? + $job->fail({error => $ttl_error}) && $self->fail_gru($job->info->{notes}{gru_id} => $ttl_error) + : $job->fail({error => $ttl_error}) + if (defined $ttl && $elapsed > $ttl); + my $buffer; my $err; { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/WebAPI.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/WebAPI.pm 2018-05-05 21:20:58.000000000 +0200 @@ -99,6 +99,8 @@ # Load plugins push @{$self->plugins->namespaces}, 'OpenQA::WebAPI::Plugin'; + +# XXX: In case the following line is moved in another location, script/generate-packed-assets needs to be adapted as well $self->plugin(AssetPack => {pipes => [qw(Sass Css JavaScript Fetch OpenQA::WebAPI::AssetPipe Combine)]}); foreach my $plugin (qw(Helpers CSRF REST HashedParams Gru)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Worker/Jobs.pm new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Worker/Jobs.pm --- old/openQA-4.5.1524586233.92db89bc/lib/OpenQA/Worker/Jobs.pm 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/lib/OpenQA/Worker/Jobs.pm 2018-05-05 21:20:58.000000000 +0200 @@ -524,7 +524,13 @@ # update settings with worker-specific stuff copy_job_settings($job, $worker_settings); - + if ($pooldir) { + my $fd; + print $fd, "" if open($fd, '>', "$pooldir/worker-log.txt") or log_error "could not open worker log $!"; + foreach my $file (qw(serial0.txt autoinst-log.txt serial_terminal.txt)) { + unlink("$pooldir/$file") or log_error "Could not unlink '$file': $!"; + } + } my $name = $job->{settings}->{NAME}; log_info(sprintf('got job %d: %s', $job->{id}, $name)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/profiles/apparmor.d/usr.share.openqa.script.worker new/openQA-4.5.1525548058.3f6bb61a/profiles/apparmor.d/usr.share.openqa.script.worker --- old/openQA-4.5.1524586233.92db89bc/profiles/apparmor.d/usr.share.openqa.script.worker 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/profiles/apparmor.d/usr.share.openqa.script.worker 2018-05-05 21:20:58.000000000 +0200 @@ -1,4 +1,4 @@ -# Last Modified: Tue May 9 11:58:28 2017 +# Last Modified: Thu May 3 18:32:11 2018 #include <tunables/global> # ------------------------------------------------------------------ @@ -20,6 +20,7 @@ #include <abstractions/nameservice> #include <abstractions/openssl> #include <abstractions/perl> + #include <abstractions/python> capability sys_ptrace, @@ -41,24 +42,27 @@ /etc/udev/udev.conf r, /etc/vde2/vdecmd r, /proc/*/auxv r, + /proc/*/cmdline r, /proc/*/mountinfo r, /proc/*/net/psched r, /proc/*/stat r, /proc/*/status r, /proc/filesystems r, - /sys/**/ r, /proc/meminfo r, /proc/sys/vm/overcommit_memory r, /run/nscd/group r, /run/openqa/vde.ctl/* rw, /run/udev/queue.bin r, + /sys/**/ r, /sys/bus/ r, /sys/bus/usb/devices/ r, /sys/class/ r, + /sys/devices/system/node/node0/meminfo r, /sys/firmware/devicetree/base/ r, /tmp/* rwk, /usr/bin/Xvnc rCx, /usr/bin/cat rix, + /usr/bin/chattr rix, /usr/bin/cksum rix, /usr/bin/cp rix, /usr/bin/date rix, @@ -68,6 +72,8 @@ /usr/bin/flock rix, /usr/bin/git rix, /usr/bin/gzip rix, + /usr/bin/head rix, + /usr/bin/icewm-default rix, /usr/bin/ionice rix, /usr/bin/ipmitool rix, /usr/bin/isotovideo rix, @@ -76,6 +82,7 @@ /usr/bin/nice rix, /usr/bin/optipng rix, /usr/bin/pwd rix, + /usr/bin/python3.* ix, /usr/bin/qemu-img rix, /usr/bin/qemu-kvm rix, /usr/bin/qemu-system-* rix, @@ -90,6 +97,7 @@ /usr/bin/uname rix, /usr/bin/unixcmd rix, /usr/bin/x3270 cx, + /usr/bin/xterm-console rix, /usr/lib*/qemu/block-curl.so rix, /usr/lib*/qemu/block-iscsi.so mr, /usr/lib*/qemu/block-rbd.so mr, @@ -98,9 +106,9 @@ /usr/lib/os-autoinst/videoencoder rix, /usr/lib/utempter/utempter rix, /usr/sbin/ipmiconsole rix, + /usr/share/openqa/lib/** r, /usr/share/openqa/lib/DBIx/Class/Timestamps.pm r, /usr/share/openqa/lib/OpenQA/** r, - /usr/share/openqa/lib/** r, /usr/share/openqa/script/worker r, /usr/share/qemu/* r, /usr/share/qemu/keymaps/* r, @@ -110,6 +118,7 @@ /var/lib/openqa/pool/*/ r, /var/lib/openqa/pool/*/** rwk, /var/lib/openqa/share/* r, + /var/lib/openqa/share/factory/hdd/ r, /var/lib/openqa/share/factory/hdd/* r, /var/lib/openqa/share/factory/hdd/fixed/* r, /var/lib/openqa/share/factory/iso/* r, @@ -140,6 +149,7 @@ /proc/** r, /sys/devices/** r, /usr/bin/lscpu mr, + } profile /usr/bin/x3270 { @@ -157,8 +167,11 @@ /proc/*/fd/ r, /proc/filesystems r, /proc/meminfo r, + /usr/bin/head rix, + /usr/bin/icewm rix, /usr/bin/ssh rix, /usr/bin/x3270 mr, + /usr/bin/xterm-console rix, /var/lib/openqa/pool/*/known_hosts w, /var/lib/openqa/pool/1/x3scr.*.txt w, /var/lib/openqa/pool/1/x3trc.* w, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/script/generate-packed-assets new/openQA-4.5.1525548058.3f6bb61a/script/generate-packed-assets --- old/openQA-4.5.1524586233.92db89bc/script/generate-packed-assets 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/script/generate-packed-assets 2018-05-05 21:20:58.000000000 +0200 @@ -42,33 +42,12 @@ set -e -DIR=$(mktemp -d -t openqa.XXXXXXXXXX) -function finish { - rm -rf "$DIR" -} -trap finish EXIT -mkdir "$DIR/tmp" +# Get Assetpack pipes from WebAPI.pm +ASSETPACK_PLUGINS=$(grep 'AssetPack' lib/OpenQA/WebAPI.pm | awk -F '[()]' '{print $3}') +[ -z "$ASSETPACK_PLUGINS" ] && echo "Can't get AssetPack pipes" && exit 1 -touch "$DIR/openqa.ini" -cp etc/openqa/database.ini $DIR - -# for locking -mkdir -p $DIR/openqa/db - -export OPENQA_BASEDIR=$DIR -export OPENQA_LOGFILE="$DIR/logfile" -export MOJO_TMPDIR="$DIR/tmp" -export OPENQA_DATABASE=test -export OPENQA_TEST_IPC=1 - -DBDIR=$(mktemp -d) -./t/test_postgresql $DBDIR -export TEST_PG="DBI:Pg:dbname=openqa_test;host=$DBDIR" - -# 'version' is the smallest codepath we can hit to produce the assets -./script/openqa eval '1+0' -m test > /dev/null -./script/openqa eval '1+0' -m development > /dev/null - -# asset/cache is now generated -pg_ctl -D $DBDIR stop +BUILD_CACHE="plugin AssetPack => { pipes => [qw(${ASSETPACK_PLUGINS})]} and app->asset->process()" +BUILD_CACHE_OPTS='-Ilib/ -MMojolicious::Lite -MOpenQA::WebAPI::AssetPipe' +MOJO_MODE=test perl $BUILD_CACHE_OPTS -e "$BUILD_CACHE" > /dev/null +MOJO_MODE=development perl $BUILD_CACHE_OPTS -e "$BUILD_CACHE" > /dev/null diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/05-scheduler-dependencies.t new/openQA-4.5.1525548058.3f6bb61a/t/05-scheduler-dependencies.t --- old/openQA-4.5.1524586233.92db89bc/t/05-scheduler-dependencies.t 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/t/05-scheduler-dependencies.t 2018-05-05 21:20:58.000000000 +0200 @@ -774,29 +774,31 @@ %settingsC = (%settings, TEST => '360-C'); %settingsD = (%settings, TEST => '360-D'); -$jobA = _job_create(\%settingsA); -$jobB = _job_create(\%settingsB, undef, [$jobA->id]); -$jobC = _job_create(\%settingsC, [$jobB->id], [$jobA->id]); -$jobD = _job_create(\%settingsD, [$jobB->id], [$jobA->id]); - -# hack jobs to appear done to scheduler -_jobs_update_state([$jobA], OpenQA::Schema::Result::Jobs::DONE, OpenQA::Schema::Result::Jobs::PASSED); -_jobs_update_state([$jobB, $jobC, $jobD], OpenQA::Schema::Result::Jobs::DONE, OpenQA::Schema::Result::Jobs::FAILED); - -$jobA2 = $jobA->auto_duplicate; -$_->discard_changes for ($jobA, $jobB, $jobC, $jobD); - -# check all children were cloned and has $jobA as parent -for ($jobB, $jobC, $jobD) { - ok($_->clone, 'job cloned'); - my $h = job_get_deps($_->clone->id); - is_deeply($h->{parents}{Chained}, [$jobA2->id], 'job has jobA2 as parent') or explain($h->{parents}{Chained}); -} +my $duplicate_test = sub { + $jobA = _job_create(\%settingsA); + $jobB = _job_create(\%settingsB, undef, [$jobA->id]); + $jobC = _job_create(\%settingsC, [$jobB->id], [$jobA->id]); + $jobD = _job_create(\%settingsD, [$jobB->id], [$jobA->id]); -for ($jobC, $jobD) { - my $h = job_get_deps($_->clone->id); - is_deeply($h->{parents}{Parallel}, [$jobB->clone->id], 'job has jobB2 as parallel parent'); -} + # hack jobs to appear done to scheduler + _jobs_update_state([$jobA], OpenQA::Schema::Result::Jobs::DONE, OpenQA::Schema::Result::Jobs::PASSED); + _jobs_update_state([$jobB, $jobC, $jobD], OpenQA::Schema::Result::Jobs::DONE, OpenQA::Schema::Result::Jobs::FAILED); + + $jobA2 = $jobA->auto_duplicate; + $_->discard_changes for ($jobA, $jobB, $jobC, $jobD); + + # check all children were cloned and has $jobA as parent + for ($jobB, $jobC, $jobD) { + ok($_->clone, 'job cloned'); + my $h = job_get_deps($_->clone->id); + is_deeply($h->{parents}{Chained}, [$jobA2->id], 'job has jobA2 as parent') or explain($h->{parents}{Chained}); + } + + for ($jobC, $jobD) { + my $h = job_get_deps($_->clone->id); + is_deeply($h->{parents}{Parallel}, [$jobB->clone->id], 'job has jobB2 as parallel parent'); + } +}; sub _job_create_set_done { my ($settings, $state) = @_; @@ -827,7 +829,7 @@ ok($res, "cloneA is $rel parent of cloneB") or explain(@{$cloneA_hash->{children}{$rel}}); } -subtest 'slepos test workers' => sub { +my $slepos_test_workers = sub { my %settingsSUS = %settings; $settingsSUS{TEST} = 'SupportServer'; my %settingsAS = %settings; @@ -872,4 +874,19 @@ ok(_job_cloned_and_related($jobBS, $jobT), "jobBS and jobT"); }; +# This enforces order in the processing of the nodes, to test PR#1623 +my $unordered_sort = \&OpenQA::Schema::Result::Jobs::search_for; +my $ordered_sort = sub { + return $unordered_sort->(@_)->search(undef, {order_by => {-desc => 'id'}}); +}; + +my %tests = ('duplicate' => $duplicate_test, 'slepos test workers' => $slepos_test_workers); +while (my ($k, $v) = each %tests) { + no warnings 'redefine'; + *OpenQA::Schema::Result::Jobs::search_for = $unordered_sort; + subtest "$k unordered" => $v; + *OpenQA::Schema::Result::Jobs::search_for = $ordered_sort; + subtest "$k ordered" => $v; +} + done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/10-jobs.t new/openQA-4.5.1525548058.3f6bb61a/t/10-jobs.t --- old/openQA-4.5.1524586233.92db89bc/t/10-jobs.t 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/t/10-jobs.t 2018-05-05 21:20:58.000000000 +0200 @@ -581,6 +581,21 @@ _check_timers(0); }; +subtest 'Old logs are deleted when nocleanup is set' => sub { + use OpenQA::Worker::Pool 'clean_pool'; + use OpenQA::Worker::Common qw($nocleanup $pooldir); + $nocleanup = 1; + $pooldir = Mojo::File->tempdir('pool'); + + $pooldir->child('autoinst-log.txt')->spurt('Hello Mojo!'); + $OpenQA::Worker::Jobs::job = {id => 1, settings => {NAME => 'test_job'}}; + OpenQA::Worker::Jobs::start_job('example.host'); + ok(!-e $pooldir->child('autoinst-log.txt'), 'autoinst-log.txt file has been deleted'); + ok(-e $pooldir->child('worker-log.txt'), 'Worker log is there'); + $nocleanup = 0; + $pooldir = undef; +}; + $t->get_ok('/t99946')->status_is(302)->header_like(Location => qr{tests/99946}); subtest 'delete job assigned as last use for asset' => sub { @@ -630,7 +645,6 @@ ok(!$exception, 'dead qemu bogus exec'); }; - subtest 'check dead children stop job' => sub { sub OpenQA::Worker::Jobs::api_call { 1; } use OpenQA::Utils; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/14-grutasks.t new/openQA-4.5.1525548058.3f6bb61a/t/14-grutasks.t --- old/openQA-4.5.1524586233.92db89bc/t/14-grutasks.t 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/t/14-grutasks.t 2018-05-05 21:20:58.000000000 +0200 @@ -397,6 +397,52 @@ ok(!-e $filename, 'file got cleaned'); }; +subtest 'Gru tasks limit' => sub { + my $id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 1}); + my $res = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 1}); + ok defined $id, 'First task is scheduled'; + is $res, undef, 'No new job scheduled'; + $id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 2}); + ok defined $id, 'Second task is scheduled'; + $res = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 2}); + is $res, undef, 'Second task is not scheduled anymore'; + + is $t->app->minion->backend->list_jobs(0, undef, {tasks => ['limit_assets'], states => ['inactive']})->{total}, 2; + + $c->run('run', '-o'); + $id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 2}); + ok defined $id, 'task is scheduled'; + $id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 2}); + ok defined $id, 'task is scheduled'; + $res = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, limit => 2}); + is $res, undef, 'Other tasks is not scheduled anymore'; + $c->run('run', '-o'); +}; + +subtest 'Gru tasks TTL' => sub { + my $job_id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, ttl => -5}); + $c->run('run', '-o'); + my $result = $t->app->minion->job($job_id)->info->{result}; + is $result->{error}, 'TTL Expired', 'TTL Expired - job discarded' or diag explain $result; + + $job_id = $t->app->gru->enqueue(limit_assets => [] => {priority => 10, ttl => 20}); + $c->run('run', '-o'); + $result = $t->app->minion->job($job_id)->info->{result}; + + # Depending on logging options, gru task output can differ + like $result, qr/will delete in 14|Job successfully executed/i, 'TTL not Expired - Job executed' + or diag explain $result; + + my @ids; + for (1 .. 100) { + push @ids, $t->app->gru->enqueue(limit_assets => [] => {priority => 10, ttl => -5}); + } + $c->run('run', '-o'); + + is $t->app->minion->job($_)->info->{result}->{error}, 'TTL Expired', 'TTL Expired - job discarded' for @ids; + +}; + SKIP: { skip 'no network available', 1 if $ENV{OBS_RUN}; subtest 'download assets with correct permissions' => sub { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/30-test_parser.t new/openQA-4.5.1525548058.3f6bb61a/t/30-test_parser.t --- old/openQA-4.5.1524586233.92db89bc/t/30-test_parser.t 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/t/30-test_parser.t 2018-05-05 21:20:58.000000000 +0200 @@ -25,6 +25,7 @@ use OpenQA::Parser::Format::JUnit; use OpenQA::Parser::Format::LTP; use OpenQA::Parser::Format::XUnit; +use OpenQA::Parser::Format::TAP; use Mojo::File qw(path tempdir); use Data::Dumper; use Mojo::JSON qw(decode_json encode_json); @@ -547,7 +548,34 @@ }; +sub test_tap_file { + my $p = shift; + is $p->results->size, 1, 'Expected 1 results'; + $p->results->each( + sub { + is $_->details->[0]->{result}, 'ok', "Test has passed" or diag explain $_; + }); +} + +subtest tap_parse => sub { + my $parser = OpenQA::Parser::Format::TAP->new; + + my $tap_test_file = path($FindBin::Bin, "data")->child("tap_format_example.tap"); + $parser = OpenQA::Parser::Format::TAP->new; + $parser->load($tap_test_file); + + is $parser->results->size, 1, "File has 6 test cases"; + + is $parser->results->first->result, 'passed', 'First test passes'; + is scalar @{$parser->results->first->details}, 6, '1 test cases details'; + + is $parser->results->last->result, 'passed', 'Last test passes'; + is scalar @{$parser->results->last->details}, 6, '1 test cases details'; + + is $_->{result}, 'ok', 'All testcases are passing' for @{$parser->results->first->details}; + +}; sub test_ltp_file { my $p = shift; @@ -678,8 +706,10 @@ diag("JSON serialization"); $parser = $parser_name->new(); $parser->load($test_result_file); - $obj_content = $parser->to_json(); + $obj_content = $parser->to_json(); + diag explain $obj_content; $deserialized = $parser_name->new()->from_json($obj_content); + diag explain $deserialized; ok "$deserialized" ne "$parser", "Different objects"; $test_function->($parser); $test_function->($deserialized); @@ -717,6 +747,7 @@ serialize_test("OpenQA::Parser::Format::LTP", "new_ltp_result_array.json", "test_ltp_file_v2"); serialize_test("OpenQA::Parser::Format::JUnit", "slenkins_control-junit-results.xml", "test_junit_file"); serialize_test("OpenQA::Parser::Format::XUnit", "xunit_format_example.xml", "test_xunit_file"); + serialize_test("OpenQA::Parser::Format::TAP", "tap_format_example.tap", "test_tap_file"); }; subtest 'Unstructured data' => sub { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/data/tap_format_example.tap new/openQA-4.5.1525548058.3f6bb61a/t/data/tap_format_example.tap --- old/openQA-4.5.1524586233.92db89bc/t/data/tap_format_example.tap 1970-01-01 01:00:00.000000000 +0100 +++ new/openQA-4.5.1525548058.3f6bb61a/t/data/tap_format_example.tap 2018-05-05 21:20:58.000000000 +0200 @@ -0,0 +1,12 @@ +t/tap_format_example.tap .. +1..6 +# +# Create a new Board and Tile, then place +# the Tile onto the board. +# +ok 1 - The object isa Board +ok 2 - Board size is zero +ok 3 - The object isa Tile +ok 4 - Get possible places to put the Tile +ok 5 - Placing the tile produces no error +ok 6 - Board size is 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/t/ui/18-tests-details.t new/openQA-4.5.1525548058.3f6bb61a/t/ui/18-tests-details.t --- old/openQA-4.5.1524586233.92db89bc/t/ui/18-tests-details.t 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/t/ui/18-tests-details.t 2018-05-05 21:20:58.000000000 +0200 @@ -31,6 +31,7 @@ use OpenQA::Test::Case; use OpenQA::Client; use Mojo::IOLoop; +use Module::Load::Conditional qw(can_load); my $test_case = OpenQA::Test::Case->new; $test_case->init_data; @@ -239,7 +240,7 @@ "on src page from details route" ); -# create 2 needle files, so they are there. The fixtures are deleted in other tests +# create 2 additional needle files for this particular test; fixtures are deleted in other tests my $ntext = <<EOM; { "area": [ @@ -257,13 +258,13 @@ ] } EOM - -ok(open(my $fh, '>', 't/data/openqa/share/tests/opensuse/needles/sudo-passwordprompt-lxde.json')); -print $fh $ntext; -close($fh); -ok(open($fh, '>', 't/data/openqa/share/tests/opensuse/needles/sudo-passwordprompt.json')); -print $fh $ntext; -close($fh); +my $needle_dir = 't/data/openqa/share/tests/opensuse/needles'; +ok(-d $needle_dir || mkdir($needle_dir), 'create needle directory'); +for my $needle_name (qw(sudo-passwordprompt-lxde sudo-passwordprompt)) { + ok(open(my $fh, '>', "$needle_dir/$needle_name.json")); + print $fh $ntext; + close($fh); +} sub test_with_error { my ($needle_to_modify, $error, $tags, $expect, $test_name) = @_; @@ -327,6 +328,63 @@ \%expected_candidates, 'needles appear twice, each time under different tag'); }; +subtest 'filtering' => sub { + $driver->get('/tests/99937'); + + # load Selenium::Remote::WDKeys module or skip this test if not available + unless (can_load(modules => {'Selenium::Remote::WDKeys' => undef,})) { + plan skip_all => 'Install Selenium::Remote::WDKeys to run this test'; + return; + } + + # define test helper + my $count_steps = sub { + my ($result) = @_; + return $driver->execute_script("return \$('#results .result${result}:visible').length;"); + }; + my $count_headings = sub { + return $driver->execute_script("return \$('#results td[colspan=\"3\"]:visible').length;"); + }; + + # check initial state (no filters enabled) + ok(!$driver->find_element('#details-name-filter')->is_displayed(), 'name filter initially not displayed'); + ok(!$driver->find_element('#details-only-failed-filter')->is_displayed(), 'failed filter initially not displayed'); + is($count_steps->('ok'), 47, 'number of passed steps without filter'); + is($count_steps->('failed'), 3, 'number of failed steps without filter'); + is($count_headings->(), 3, 'number of module headings without filter'); + + # show filter form + $driver->find_element('.details-filter-toggle a')->click(); + + # enable name filter + $driver->find_element('#details-name-filter')->send_keys('at'); + is($count_steps->('ok'), 3, 'number of passed steps only with name filter'); + is($count_steps->('failed'), 1, 'number of failed steps only with name filter'); + is($count_headings->(), 0, 'no module headings shown when filter active'); + + # enable failed filter + $driver->find_element('#details-only-failed-filter')->click(); + is($count_steps->('ok'), 0, 'number of passed steps with both filters'); + is($count_steps->('failed'), 1, 'number of failed steps with both filters'); + is($count_headings->(), 0, 'no module headings shown when filter active'); + + # disable name filter + $driver->find_element('#details-name-filter')->send_keys( + Selenium::Remote::WDKeys->KEYS->{end}, + Selenium::Remote::WDKeys->KEYS->{backspace}, + Selenium::Remote::WDKeys->KEYS->{backspace}, + ); + is($count_steps->('ok'), 0, 'number of passed steps only with failed filter'); + is($count_steps->('failed'), 3, 'number of failed steps only with failed filter'); + is($count_headings->(), 0, 'no module headings shown when filter active'); + + # disable failed filter + $driver->find_element('#details-only-failed-filter')->click(); + is($count_steps->('ok'), 47, 'same number of passed steps as initial'); + is($count_steps->('failed'), 3, 'same number of failed steps as initial'); + is($count_headings->(), 3, 'module headings shown again'); +}; + # set job 99963 to done via API to tests whether worker is still displayed then my $t_api = Test::Mojo->new('OpenQA::WebAPI'); my $app = $t_api->app; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/templates/layouts/dependencies.html.ep new/openQA-4.5.1525548058.3f6bb61a/templates/layouts/dependencies.html.ep --- old/openQA-4.5.1524586233.92db89bc/templates/layouts/dependencies.html.ep 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/templates/layouts/dependencies.html.ep 2018-05-05 21:20:58.000000000 +0200 @@ -1,7 +1,9 @@ % if ($job->parents->first()) { -<div class="box box-shadow" id="parents_info_box"> - <div class="box-header aligncenter">Parents</div> - <table class="infotbl"> +<table class="infotbl table table-striped" id="parents_info_box"> + <thead> + <tr><th colspan="2">Parents</th></tr> + </thead> + <tbody> <% for my $dep ($job->parents->all()) { %> <tr> <td style="width: 40%;"> @@ -9,22 +11,22 @@ </td> <td> %if ($dep->parent->state eq 'cancelled' || $dep->parent->state eq 'done') { - <span style="padding: 0 10%; display: inline-block; - text-align: center;" - class="<%= css_for({'result' => $dep->parent->result}) %>"><%= $dep->parent->result %></span> + <span class="dependency_result <%= css_for({'result' => $dep->parent->result}) %>"><%= $dep->parent->result %></span> % } else { %= $dep->parent->state % } </td> </tr> <% } %> - </table> -</div> + </tbody> +</table> % } % if ($job->children->first()) { -<div class="box box-shadow" id="parents_info_box"> - <div class="box-header aligncenter">Children</div> - <table class="infotbl"> +<table class="infotbl table table-striped" id="childs_info_box"> + <thead> + <tr><th colspan="2">Children</th></tr> + </thead> + <tbody> <% for my $dep ($job->children->all()) { %> <tr> <td style="width: 40%;"> @@ -32,15 +34,13 @@ </td> <td> %if ($dep->child->state eq 'cancelled' || $dep->child->state eq 'done') { - <span style="padding: 0 10%; display: inline-block; - text-align: center;" - class="<%= css_for({'result' => $dep->child->result}) %>"><%= $dep->child->result %></span> + <span class="dependency_result <%= css_for({'result' => $dep->child->result}) %>"><%= $dep->child->result %></span> % } else { %= $dep->child->state % } </td> </tr> <% } %> - </table> -</div> + </tbody> +</table> % } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/templates/main/group_builds.html.ep new/openQA-4.5.1525548058.3f6bb61a/templates/main/group_builds.html.ep --- old/openQA-4.5.1524586233.92db89bc/templates/main/group_builds.html.ep 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/templates/main/group_builds.html.ep 2018-05-05 21:20:58.000000000 +0200 @@ -11,9 +11,9 @@ %= link_to "Build$build" => url_for('tests_overview')->query(distri => [sort keys %{$build_res->{distris}}], version => $build_res->{version}, build => $build, groupid => $group->{id} ) % } - (<abbr class="timeago" title="<%= $build_res->{oldest}->datetime() %>Z"> + <span class="smaller-font">(<abbr class="timeago" title="<%= $build_res->{oldest}->datetime() %>Z"> %= $build_res->{oldest} - </abbr>) + </abbr>)</span> % my $group_build_id = $group->{id} . '-' . $build_res->{escaped_id}; %= include 'main/review_badge', group_build_id => $group_build_id, build_res => $build_res, id_prefix => '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openQA-4.5.1524586233.92db89bc/templates/test/details.html.ep new/openQA-4.5.1525548058.3f6bb61a/templates/test/details.html.ep --- old/openQA-4.5.1524586233.92db89bc/templates/test/details.html.ep 2018-04-24 18:10:33.000000000 +0200 +++ new/openQA-4.5.1525548058.3f6bb61a/templates/test/details.html.ep 2018-05-05 21:20:58.000000000 +0200 @@ -1,4 +1,19 @@ % if (@$modlist) { + <div class="details-filter-toggle"> + <a href="#" aria-controls="previous" class="nav-link" title="Filter"> + <i class="fas fa-filter"></i> + </a> + </div> + <form class="row details-filter hidden"> + <div class="col-sm-12 col-md-6"> + Name: + <input type="search" class="form-control form-control-sm" placeholder="Filter by name" aria-controls="results" id="details-name-filter"> + </div> + <div class="col-sm-12 col-md-6 result-filter-container"> + <input id="details-only-failed-filter" name="relevant" type="checkbox" value="1"> + <label for="details-only-failed-filter">Show only failures</label> + </div> + </form> <table id="results" class="table table-striped"> <thead> <tr>
