diff options
-rw-r--r-- | non-puppet/qtmetrics2/index.php | 57 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/Database.php | 74 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/Factory.php | 36 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/TestfunctionRun.php | 200 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/test/DatabaseTest.php | 45 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/test/FactoryTest.php | 37 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/about.html | 4 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/testset_testfunctions.html | 288 |
8 files changed, 726 insertions, 15 deletions
diff --git a/non-puppet/qtmetrics2/index.php b/non-puppet/qtmetrics2/index.php index a7d0290..10a4856 100644 --- a/non-puppet/qtmetrics2/index.php +++ b/non-puppet/qtmetrics2/index.php @@ -34,7 +34,7 @@ /** * Qt Metrics API - * @since 10-08-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -469,6 +469,61 @@ $app->get('/testset/:testset/:project', function($testset, $project) use($app) })->name('testset'); /** + * UI route: /testset/:testset/:project/:conf (GET) + */ + +$app->get('/testset/:testset/:project/:conf', function($testset, $project, $conf) use($app) +{ + $testset = strip_tags($testset); + $project = strip_tags($project); + $conf = strip_tags($conf); + if (Factory::checkTestset($testset)) { + $testsetRoute = str_replace('/:testset/:project', '', Slim\Slim::getInstance()->urlFor('testset')); + $testsetProjectRoute = str_replace('/:project', '', Slim\Slim::getInstance()->urlFor('testsetproject')); + $confProjectRoute = str_replace('/:conf/:testsetproject', '', Slim\Slim::getInstance()->urlFor('conf_testsetproject')); + $ini = Factory::conf(); + $breadcrumb = array( + array('name' => 'home', 'link' => Slim\Slim::getInstance()->urlFor('root')), + array('name' => 'overview', 'link' => Slim\Slim::getInstance()->urlFor('overview')), + array('name' => $project, 'link' => $testsetProjectRoute . '/' . $project), + array('name' => $conf, 'link' => $confProjectRoute . '/' . urlencode($conf) . '/' . $project), + array('name' => $testset, 'link' => $testsetRoute . '/' . $testset. '/' . $project) + ); + $confProjectRoute = str_replace('/:conf/:testsetproject', '', Slim\Slim::getInstance()->urlFor('conf_testsetproject')); + $testfunctionRoute = 'testfunction'; // TODO: Replace later with $testfunctionRoute = str_replace('/:testfunction', '', Slim\Slim::getInstance()->urlFor('testfunction')); + $app->render('testset_testfunctions.html', array( + 'root' => Slim\Slim::getInstance()->urlFor('root'), + 'breadcrumb' => $breadcrumb, + 'testfunctionRoute' => $testfunctionRoute, + 'refreshed' => Factory::db()->getDbRefreshed() . ' (GMT)', + 'masterProject' => $ini['master_build_project'], + 'masterState' => $ini['master_build_state'], + 'conf' => $conf, + 'projectRuns' => Factory::createProjectRuns( + $ini['master_build_project'], + $ini['master_build_state']), // managed as objects + 'testset' => Factory::createTestset( + $testset, + $project, + $ini['master_build_project'], + $ini['master_build_state']), // managed as object + 'testfunctionRuns' => Factory::createTestfunctionRunsInConf( + $testset, + $project, + $conf, + $ini['master_build_project'], + $ini['master_build_state']) // managed as objects + )); + } else { + $app->render('empty.html', array( + 'root' => Slim\Slim::getInstance()->urlFor('root'), + 'message' => '404 Not Found' + )); + $app->response()->status(404); + } +})->name('testset_testfunctions'); + +/** * UI route: /sitemap (GET) */ diff --git a/non-puppet/qtmetrics2/src/Database.php b/non-puppet/qtmetrics2/src/Database.php index ce5f5ab..3700b78 100644 --- a/non-puppet/qtmetrics2/src/Database.php +++ b/non-puppet/qtmetrics2/src/Database.php @@ -34,8 +34,7 @@ /** * Database class - * @version 0.9 - * @since 21-07-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -924,7 +923,7 @@ class Database { /** * Get run results for a testset in specified builds by branch and configuration * @param string $testset - * @param $testsetProject + * @param string $testsetProject * @param string $runProject * @param string $runState * @return array (string branch, string conf, string build_key, string result, string timestamp, string duration, int run) @@ -977,7 +976,7 @@ class Database { /** * Get result counts for a testset project in specified builds by branch and configuration - * @param $testsetProject + * @param string $testsetProject * @param string $runProject * @param string $runState * @return array (string branch, string conf, string build_key, int passed, int ipassed, int failed, int ifailed) @@ -1030,7 +1029,7 @@ class Database { /** * Get results for failed testsets in specified configuration builds by branch * Only the failures are listed - * @param $conf + * @param string $conf * @param string $runProject * @param string $runState * @return array (string branch, string build_key, string testset, string project, string result, string timestamp, string duration, int run) @@ -1085,8 +1084,8 @@ class Database { /** * Get results for failed testsets in specified configuration builds and project by branch * Only the failures are listed - * @param $conf - * @param $testsetProject + * @param string $conf + * @param string $testsetProject * @param string $runProject * @param string $runState * @return array (string branch, string build_key, string testset, string project, string result, string timestamp, string duration, int run) @@ -1117,7 +1116,7 @@ class Database { conf.name = ? AND project_run.project_id = (SELECT id FROM project WHERE name = ?) AND project_run.state_id = (SELECT id FROM state WHERE name = ?) - ORDER BY branch.name, project.name, testset.name, project_run.build_key DESC; + ORDER BY branch.name, testset.name, project_run.build_key DESC; "); $query->execute(array( $testsetProject, @@ -1141,6 +1140,65 @@ class Database { } /** + * Get results for failed and skipped testfunctions in specified configuration builds and project by branch + * Only the fail/skip and xpass/xfail results are listed + * @param string $testset + * @param string $testsetProject + * @param string $conf + * @param string $runProject + * @param string $runState + * @return array (string branch, string build_key, string testfunction, string result, string timestamp, string duration) + */ + public function getTestfunctionConfResultsByBranch($testset, $testsetProject, $conf, $runProject, $runState) + { + $result = array(); + $query = $this->db->prepare(" + SELECT + branch.name AS branch, + project_run.build_key, + testfunction.name AS testfunction, + testfunction_run.result, + project_run.timestamp, + testfunction_run.duration + FROM testfunction_run + INNER JOIN testfunction ON testfunction_run.testfunction_id = testfunction.id + INNER JOIN testset_run ON testfunction_run.testset_run_id = testset_run.id + INNER JOIN testset ON testset_run.testset_id = testset.id + INNER JOIN project ON testset.project_id = project.id + INNER JOIN conf_run ON testset_run.conf_run_id = conf_run.id + INNER JOIN conf ON conf_run.conf_id = conf.id + INNER JOIN project_run ON conf_run.project_run_id = project_run.id + INNER JOIN branch ON project_run.branch_id = branch.id + WHERE + (testfunction_run.result LIKE '%fail' OR testfunction_run.result LIKE '%skip' OR testfunction_run.result LIKE '%x%') AND + testset.name = ? AND + project.name = ? AND + conf.name = ? AND + project_run.project_id = (SELECT id FROM project WHERE name = ?) AND + project_run.state_id = (SELECT id FROM state WHERE name = ?) + ORDER BY branch.name, testfunction.name, project_run.build_key DESC; + "); + $query->execute(array( + $testset, + $testsetProject, + $conf, + $runProject, + $runState + )); + while($row = $query->fetch(PDO::FETCH_ASSOC)) { + $result[] = array( + 'branch' => $row['branch'], + 'buildKey' => $row['build_key'], + 'testfunction' => $row['testfunction'], + 'result' => $row['result'], + 'timestamp' => $row['timestamp'], + 'duration' => $row['duration'] + ); + } + return $result; + } + + /** * Get the timestamp when database last refreshed * @return string (timestamp) */ diff --git a/non-puppet/qtmetrics2/src/Factory.php b/non-puppet/qtmetrics2/src/Factory.php index 8429852..fe35142 100644 --- a/non-puppet/qtmetrics2/src/Factory.php +++ b/non-puppet/qtmetrics2/src/Factory.php @@ -34,7 +34,7 @@ /** * Factory class - * @since 17-08-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -46,6 +46,7 @@ require_once 'Conf.php'; require_once 'ConfRun.php'; require_once 'Testset.php'; require_once 'TestsetRun.php'; +require_once 'TestfunctionRun.php'; class Factory { @@ -404,6 +405,39 @@ class Factory { } /** + * Create TestfunctionRun objects in a configuration for those in database + * @param string $testset + * @param string $testsetProject + * @param string $conf + * @param string $runProject + * @param string $runState + * @return array TestfunctionRun objects + */ + public static function createTestfunctionRunsInConf($testset, $testsetProject, $conf, $runProject, $runState) + { + $objects = array(); + $dbEntries = self::db()->getTestfunctionConfResultsByBranch($testset, $testsetProject, $conf, $runProject, $runState); + foreach($dbEntries as $entry) { + $obj = new TestfunctionRun( + $entry['testfunction'], + $testset, + $testsetProject, + $runProject, + $entry['branch'], + $runState, + $entry['buildKey'], + $conf, + TestfunctionRun::stripResult($entry['result']), + TestfunctionRun::isBlacklisted($entry['result']), + $entry['timestamp'], + $entry['duration'] + ); + $objects[] = $obj; + } + return $objects; + } + + /** * Get the date that was n days before the last database refresh date. * @param int $days * @return string (date in unix date format) diff --git a/non-puppet/qtmetrics2/src/TestfunctionRun.php b/non-puppet/qtmetrics2/src/TestfunctionRun.php new file mode 100644 index 0000000..56f95aa --- /dev/null +++ b/non-puppet/qtmetrics2/src/TestfunctionRun.php @@ -0,0 +1,200 @@ +<?php +############################################################################# +## +## Copyright (C) 2015 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Quality Assurance module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL21$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see http://www.qt.io/terms-conditions. For further +## information use the contact form at http://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 or version 3 as published by the Free +## Software Foundation and appearing in the file LICENSE.LGPLv21 and +## LICENSE.LGPLv3 included in the packaging of this file. Please review the +## following information to ensure the GNU Lesser General Public License +## requirements will be met: https://www.gnu.org/licenses/lgpl.html and +## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## As a special exception, The Qt Company gives you certain additional +## rights. These rights are described in The Qt Company LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## $QT_END_LICENSE$ +## +############################################################################# + +/** + * TestfunctionRun class + * @since 08-09-2015 + * @author Juha Sippola + */ + +class TestfunctionRun extends ProjectRun { + + /** + * Testfunction results (these must follow the enumeration in the database; excluding the blacklisted flag) + */ + const RESULT_NOT_SET = NULL; + const RESULT_EMPTY = ""; + const RESULT_NA = "na"; + const RESULT_SUCCESS = "pass"; + const RESULT_SUCCESS_UNEXPECTED = "xpass"; + const RESULT_FAILURE = "fail"; + const RESULT_FAILURE_EXPECTED = "xfail"; + const RESULT_SKIP = "skip"; + + /** + * If the testfunction name long, a shorter version of the name can be requested + */ + const SHORT_NAME_LENGTH = 50; + + /** + * Testfunction name. + * @var string + */ + private $name; + + /** + * Testset name. + * @var string + */ + private $testsetName; + + /** + * Testset project name. + * @var string + */ + private $testsetProjectName; + + /** + * Configuration name. + * @var string + */ + private $confName; + + /** + * Blacklisted flag (true = blacklisted). + * @var bool + */ + private $blacklisted; + + /** + * TestfunctionRun constructor. + * @param string $name + * @param string $testsetName + * @param string $testsetProjectName + * @param string $projectName + * @param string $branchName + * @param string $stateName + * @param int $buildKey + * @param string $confName + * @param string $result (plain result without any possible flags) + * @param bool $blacklisted (true = blacklisted) + * @param string $timestamp + * @param int $duration (in deciseconds) + */ + public function __construct($name, $testsetName, $testsetProjectName, $projectName, $branchName, $stateName, $buildKey, $confName, $result, $blacklisted, $timestamp, $duration) { + parent::__construct($projectName, $branchName, $stateName, $buildKey, $result, $timestamp, $duration); + $this->name = $name; + $this->testsetName = $testsetName; + $this->testsetProjectName = $testsetProjectName; + $this->confName = $confName; + $this->blacklisted = $blacklisted; + } + + /** + * Get name of the testfunction. + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get short name of the testfunction. + * @return string + */ + public function getShortName() + { + if (strlen($this->name) > self::SHORT_NAME_LENGTH) + return substr($this->name, 0, self::SHORT_NAME_LENGTH - 10) . '...' . substr($this->name, -7); + else + return $this->name; + } + + /** + * Get name of the testset project. + * @return string + */ + public function getTestsetProjectName() + { + return $this->testsetProjectName; + } + + /** + * Get name of the testset. + * @return string + */ + public function getTestsetName() + { + return $this->testsetName; + } + + /** + * Get configuration name. + * @return string + */ + public function getConfName() + { + return $this->confName; + } + + /** + * Get blacklisted flag. + * @return bool (true = blacklisted) + */ + public function getBlacklisted() + { + return $this->blacklisted; + } + + /** + * Strip the result from the combined blacklisted-result string + * @param string $resultString + * @return string + */ + public static function stripResult($resultString) + { + $resultString = str_replace('bpass', 'pass', $resultString); // remove the possible blacklisted flag + $resultString = str_replace('bfail', 'fail', $resultString); // remove the possible blacklisted flag + $resultString = str_replace('bx', 'x', $resultString); // remove the possible blacklisted flag + $resultString = str_replace('bskip', 'skip', $resultString); // remove the possible blacklisted flag + return $resultString; + } + + /** + * Check the blacklisted flag from the combined blacklisted-result string + * @param string $resultString + * @return bool (true = blacklisted) + */ + public static function isBlacklisted($resultString) + { + $flag = false; + if (strpos($resultString, 'b') === 0) // begins with 'b' + $flag = true; + return $flag; + } + +} + +?> diff --git a/non-puppet/qtmetrics2/src/test/DatabaseTest.php b/non-puppet/qtmetrics2/src/test/DatabaseTest.php index 8fc798c..7ce99df 100644 --- a/non-puppet/qtmetrics2/src/test/DatabaseTest.php +++ b/non-puppet/qtmetrics2/src/test/DatabaseTest.php @@ -38,8 +38,7 @@ require_once(__DIR__.'/../Factory.php'); * Database unit test class * Some of the tests require the test data as inserted into database with qtmetrics_insert.sql * @example To run (in qtmetrics root directory): php <path-to-phpunit>/phpunit.phar ./src/test - * @version 0.9 - * @since 21-07-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -944,6 +943,48 @@ class DatabaseTest extends PHPUnit_Framework_TestCase } /** + * Test getTestfunctionConfResultsByBranch + * @dataProvider testGetTestfunctionConfResultsByBranchData + */ + public function testGetTestfunctionConfResultsByBranch($testset, $testsetProject, $conf, $runProject, $runState, $exp_branch, $exp_testfunction, $exp_key, $has_data) + { + $branches = array(); + $keys = array(); + $testfunctions = array(); + $db = Factory::db(); + $result = $db->getTestfunctionConfResultsByBranch($testset, $testsetProject, $conf, $runProject, $runState); + foreach($result as $row) { + $this->assertArrayHasKey('branch', $row); + $this->assertArrayHasKey('buildKey', $row); + $this->assertArrayHasKey('testfunction', $row); + $this->assertArrayHasKey('result', $row); + $this->assertArrayHasKey('timestamp', $row); + $this->assertArrayHasKey('duration', $row); + $branches[] = $row['branch']; + $keys[] = $row['buildKey']; + $testfunctions[] = $row['testfunction']; + } + if ($has_data) { + $this->assertNotEmpty($result); + $this->assertContains($exp_branch, $branches); + $this->assertContains($exp_key, $keys); + $this->assertContains($exp_testfunction, $testfunctions); + } else { + $this->assertEmpty($result); + } + } + public function testGetTestfunctionConfResultsByBranchData() + { + return array( + array('tst_qfont', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', 'exactMatch', '1348', 1), // fail + array('tst_qfont', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', 'lastResortFont', '1348', 1), // skip + array('tst_networkselftest', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', 'smbServer', '1348', 1), // skip + array('tst_qftp', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', '', '', '', 0), // no fail or skip + array('tst_qfont', 'qtbase', 'invalid', 'Qt5', 'state', '', '', '', 0) + ); + } + + /** * Test getDbRefreshed */ public function testGetDbRefreshed() diff --git a/non-puppet/qtmetrics2/src/test/FactoryTest.php b/non-puppet/qtmetrics2/src/test/FactoryTest.php index 8fbb17e..5e24833 100644 --- a/non-puppet/qtmetrics2/src/test/FactoryTest.php +++ b/non-puppet/qtmetrics2/src/test/FactoryTest.php @@ -37,7 +37,7 @@ require_once(__DIR__.'/../Factory.php'); /** * Factory unit test class * @example To run (in qtmetrics root directory): php <path-to-phpunit>/phpunit.phar ./src/test - * @since 17-08-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -424,6 +424,41 @@ class FactoryTest extends PHPUnit_Framework_TestCase } /** + * Test createTestfunctionRunsInConf + * @dataProvider testCreateTestfunctionRunsInConfData + */ + public function testCreateTestfunctionRunsInConf($testset, $testsetProject, $conf, $runProject, $runState, $exp_branch, $exp_buildKey, $exp_testfunction, $has_data) + { + $branches = array(); + $buildKeys = array(); + $testfunctions = array(); + $runs = Factory::createTestfunctionRunsInConf($testset, $testsetProject, $conf, $runProject, $runState); + foreach($runs as $run) { + $this->assertTrue($run instanceof TestfunctionRun); + $branches[] = $run->getBranchName(); + $buildKeys[] = $run->getBuildKey(); + $testfunctions[] = $run->getName(); + } + if ($has_data) { + $this->assertContains($exp_branch, $branches); + $this->assertContains($exp_buildKey, $buildKeys); + $this->assertContains($exp_testfunction, $testfunctions); + } else { + $this->assertEmpty($runs); + } + } + public function testCreateTestfunctionRunsInConfData() + { + return array( + array('tst_qfont', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', '1348', 'exactMatch', 1), // fail + array('tst_qfont', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', '1348', 'lastResortFont', 1), // skip + array('tst_networkselftest', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', 'stable', '1348', 'smbServer', 1), // skip + array('tst_qftp', 'qtbase', 'macx-clang_developer-build_OSX_10.8', 'Qt5', 'state', '', '', '', 0), // no fail or skip + array('tst_qfont', 'qtbase', 'invalid', 'Qt5', 'state', '', '', '', 0) + ); + } + + /** * Test getSinceDate * @dataProvider testGetSinceDateData */ diff --git a/non-puppet/qtmetrics2/templates/about.html b/non-puppet/qtmetrics2/templates/about.html index e8b7dd2..9eb5d0e 100644 --- a/non-puppet/qtmetrics2/templates/about.html +++ b/non-puppet/qtmetrics2/templates/about.html @@ -34,7 +34,7 @@ /** * About window content - * @since 19-08-2015 + * @since 08-09-2015 * @author Juha Sippola */ @@ -43,4 +43,4 @@ <p>This is Qt Metrics revision 2 with redesigned UI and database.</p> <p>These pages are still <strong>under construction</strong> and therefore the views and functionality is limited.</p> <p>See the <a href="https://wiki.qt.io/Qt_Metrics_2_Backlog" target="_blank">backlog</a> for development items currently identified or in progress.</p> -<p><small>Version 0.20 (19-Aug-2015)</small></p> +<p><small>Version 0.21 (8-Sep-2015)</small></p> diff --git a/non-puppet/qtmetrics2/templates/testset_testfunctions.html b/non-puppet/qtmetrics2/templates/testset_testfunctions.html new file mode 100644 index 0000000..6f6317c --- /dev/null +++ b/non-puppet/qtmetrics2/templates/testset_testfunctions.html @@ -0,0 +1,288 @@ +{# +############################################################################# +## +## Copyright (C) 2015 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Quality Assurance module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL21$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see http://www.qt.io/terms-conditions. For further +## information use the contact form at http://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 or version 3 as published by the Free +## Software Foundation and appearing in the file LICENSE.LGPLv21 and +## LICENSE.LGPLv3 included in the packaging of this file. Please review the +## following information to ensure the GNU Lesser General Public License +## requirements will be met: https://www.gnu.org/licenses/lgpl.html and +## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## As a special exception, The Qt Company gives you certain additional +## rights. These rights are described in The Qt Company LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## $QT_END_LICENSE$ +## +############################################################################# + +/** + * Testfunctions page + * @since 08-09-2015 + * @author Juha Sippola + */ + +#} + +{% include "header.html" %} + +{# testset as Testset object +/** + * @var Testset[] testset + */ +#} + +{# projectRuns as ProjectRun objects +/** + * @var ProjectRun[] projectRuns + */ +#} + +{# testfunctionRuns as TestfunctionRun objects +/** + * @var TestfunctionRun[] testfunctionRuns + */ +#} + +<ol class="breadcrumb"> +{% for link in breadcrumb %} +<li><a href="{{ link.link }}">{{ link.name }}</a></li> +{% endfor %} +<li class="active">testfunctions</li> +</ol> + +<div class="container-fluid"> +<div class="row"> + +<div class="col-sm-12 col-md-12 main"> + +{# Check if any runs available #} +{% set runsAvailable = 0 %} +{% for run in testfunctionRuns %} +{% set runsAvailable = 1 %} +{% endfor %} + +{##### Title #####} + +<h1 class="page-header"> +{{ testset.getName }} +<button type="button" class="btn btn-xs btn-info" data-toggle="collapse" data-target="#info" aria-expanded="false" aria-controls="info"> +<span class="glyphicon glyphicon-info-sign"></span> +</button> +<small>{{ refreshed }}</small> +</h1> + +{##### Info well #####} + +<div class="collapse" id="info"> +<div class="well infoWell"> +<span class="glyphicon glyphicon-info-sign"></span> <strong>Testset</strong><br> +<ul> +<li><strong>Testfunction Results in Branches</strong> shows the {{ testset.getName }} <strong>failed and skipped</strong> results in configuration +{{ conf }} by branch on <strong>{{ masterProject }} {{ masterState }}</strong> builds +<ul> +<li>flags: <span class="label label-default">b</span> = blacklisted flag set for the testfunction on the latest build shown</li> +<li>results: <span class="glyphicon glyphicon-remove red"></span> = {{ constant('TestfunctionRun::RESULT_FAILURE') }}, +<span class="glyphicon glyphicon-ok-sign red"></span> = {{ constant('TestfunctionRun::RESULT_SUCCESS_UNEXPECTED') }}, +<span class="glyphicon glyphicon-remove-sign green"></span> = {{ constant('TestfunctionRun::RESULT_FAILURE_EXPECTED') }}, +<span class="glyphicon glyphicon-ban-circle gray"></span> = {{ constant('TestfunctionRun::RESULT_SKIP') }}</li> +</ul> +</li> +<li>Details on the runs are available as tooltip on result icon</li> +</ul> +</div> +</div> + +{% if runsAvailable %} + +{##### Results in Branches #####} + +<div class="panel panel-primary"> +<div class="panel-heading"> +<h4 class="panel-title bold">Testfunction Results in Branches <small>(failures and skipped only)</small></h4> +</div> +</div> + +{# Get branches #} +{% set branches = [] %} +{% for run in projectRuns %} +{% if run.getBranchName not in branches %} +{% set branches = branches|merge([run.getBranchName]) %} +{% endif %} +{% endfor %} + +{# Loop all the branches #} +{% for branch in branches %} + +{# Get all build keys, dates and log links #} +{% set buildKey = '' %} +{% set buildKeys = [] %} +{% set dates = [] %} +{% for run in projectRuns %} +{% if run.getBranchName == branch %} +{% if buildKey != run.getBuildKey %} +{% set buildKey = run.getBuildKey %} +{% set buildKeys = buildKeys|merge([run.getBuildKey]) %} +{% set dates = dates|merge([run.getTimestamp]) %} +{% endif %} +{% endif %} +{% endfor %} + +{# Check if testfunction run for this branch #} +{% set testfunctionBranch = 0 %} +{% for run in testfunctionRuns if run.getBranchName == branch %} +{% set testfunctionBranch = 1 %} +{% endfor %} + +{# Show branch if testfunction run for it #} +{% if testfunctionBranch %} +<div class="panel panel-info"> +<div class="panel-heading"> +<h4 class="panel-title bold">{{ branch }}</h4> +</div> +<div class="panel-body"> +<div class="table-responsive"> +<table class="table table-striped"> +<thead> +<tr> +<th class="bold">{{ testset.getName }}</th> +<th class="bold rightBorder">flags</th> +{% for key, buildKey in buildKeys %} +<th class="center"> +{% if buildKey|length > 6 %} +<span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ buildKey }}">{{ buildKey|slice(0, 4) }}...</span><br> +{% else %} +{{ buildKey }}<br> +{% endif %} +<span class="gray"><small>{{ dates[key]|date("m-d") }}</small></span> +</th> +{% endfor %} +</tr> +</thead> +<tbody> +{% set testfunctionPrev = '' %} +{% set buildKeyIndexPrinted = -1 %} +{% set buildKeyFound = 0 %} +{% for run in testfunctionRuns if run.getBranchName == branch %} + +{# New row for each testfunction #} +{% if testfunctionPrev != run.getName %} +{# Close previous row #} +{% if testfunctionPrev != '' %} +{# Fill empty cells at the end of the row #} +{% for key, buildKey in buildKeys %} +{% if key > buildKeyIndexPrinted %} +<td></td> +{% endif %} +{% endfor %} +</tr> +{% endif %} +<tr> +{% set link = testfunctionRoute ~ '/' ~ run.getName|url_encode ~ '/' ~ testset.getName|url_encode ~ '/' ~ testset.getProjectName|url_encode ~ '/' ~ run.getConfName|url_encode %} +<td><a href="{{ link }}"><small> +{% if run.getName|length > constant('TestfunctionRun::SHORT_NAME_LENGTH') %} +<span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ run.getName }}">{{ run.getShortName }}</span> +{% else %} +{{ run.getName }} +{% endif %} +</small></a></td> + +{# Flags for the latest build #} +<td class="center rightBorder"> +{% if run.getBlacklisted %} +<span class="label label-default">b</span> +{% endif %} +</td> +{% set buildKeyIndexPrinted = -1 %} +{% endif %} + +{# Result per build key #} +{% set buildKeyFound = 0 %} +{% for key, buildKey in buildKeys %} +{# Print each column only once (checked based on column index key and buildKeyFound flag) #} +{% if key > buildKeyIndexPrinted and not buildKeyFound %} +{% if buildKey == run.getBuildKey %} +{# Print result #} +{% if run.getResult == constant('TestfunctionRun::RESULT_FAILURE') %} +{% set resultIcon = 'glyphicon glyphicon-remove red' %} +{% elseif run.getResult == constant('TestfunctionRun::RESULT_FAILURE_EXPECTED') %} +{% set resultIcon = 'glyphicon glyphicon-remove-sign green' %} +{% elseif run.getResult == constant('TestfunctionRun::RESULT_SUCCESS_UNEXPECTED') %} +{% set resultIcon = 'glyphicon glyphicon-ok-sign red' %} +{% elseif run.getResult == constant('TestfunctionRun::RESULT_SKIP') %} +{% set resultIcon = 'glyphicon glyphicon-ban-circle gray' %} +{% else %} +{% set resultIcon = '' %} +{% endif %} +{% if (run.getDuration / 10) > 60 %} +{% set durationFormatted = ' (00:' ~ ((run.getDuration/10)|round)|date("i:s") ~ ')' %} +{% else %} +{% set durationFormatted = '' %} +{% endif %} +<td class="center"> +<span class="spaceHorizontal {{ resultIcon }} clickOnTouch" data-toggle="tooltip" data-placement="top" data-html="true" +title="<table> +<tr><th>Build key: </th><td>{{ buildKey }}</td></tr> +<tr><th>Configuration: </th><td>{{ run.getConfName }}</td></tr> +<tr><th>Timestamp: </th><td>{{ run.getTimestamp }}</td></tr> +<tr><th>Result: </th><td>{{ run.getResult }}</td></tr> +<tr><th>Duration: </th><td>{{ run.getDuration / 10 }} s {{ durationFormatted }}</td></tr> +<tr><th>Blacklisted: </th><td>{% if run.getBlacklisted %}yes{% else %}no{% endif %}</td></tr></table>"> +</span></td> +{% set buildKeyFound = 1 %} +{% else %} +{# Print empty cell #} +<td></td> +{% endif %} +{% set buildKeyIndexPrinted = key %} +{% endif %}{# key #} +{% endfor %}{# key #} +{% set testfunctionPrev = run.getName %} +{% endfor %}{# run #} + +{# Close last row (also fill empty cells at the end of the row) #} +{% for key, buildKey in buildKeys %} +{% if key > buildKeyIndexPrinted %} +<td></td> +{% endif %} +{% endfor %}{# key #} +</tr> +</tbody> +</table> +</div> {# .table-responsive #} +</div> {# .panel-body #} +</div> {# .panel... #} +{% endif %}{# testfunctionBranch #} +{% endfor %}{# branch #} + +{% else %}{# runsAvailable #} +<div class="alert alert-success" role="alert"> +No failed or skipped testfunctions in testset {{ testset.getName }} in project {{ testset.getProjectName }} and configuration {{ conf }}! +</div> +{% endif %}{# runsAvailable #} +</div> {# .col... #} +</div> {# .row #} +</div> {# /container-fluid #} + +{% include "footer.html" %} + +{# Local scripts for this page #} +<script src="scripts/tooltip.js"></script> + +{% include "close.html" %} |