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>


Reply via email to