diff options
author | Juha Sippola <juhasippola@outlook.com> | 2015-07-01 15:54:56 +0300 |
---|---|---|
committer | Tony Sarajärvi <tony.sarajarvi@theqtcompany.com> | 2015-09-16 07:32:01 +0000 |
commit | 17114a51b5015b5af18818c30344bbe5365d7a6c (patch) | |
tree | 529f1fbdfea6c4279510bebf5f350e3033f0f673 | |
parent | 5a2c85839bfb064c7d8faa79ee2d00bb51458e87 (diff) |
Qt Metrics 2 (v0.6): Testset page
Implemented the Results in Branches section into
testset page.
Changed testset URL to include its project to
identify testsets with same name clearly.
Change-Id: I4ffd7ec6bbbc473af0d742e808568ff7d3b273da
Reviewed-by: Tony Sarajärvi <tony.sarajarvi@theqtcompany.com>
-rw-r--r-- | non-puppet/qtmetrics2/index.php | 29 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/scripts/tooltip.js | 63 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/Database.php | 105 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/Factory.php | 84 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/TestsetRun.php | 38 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/test/DatabaseTest.php | 98 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/src/test/FactoryTest.php | 41 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/styles/qtmetrics.css | 26 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/about.html | 6 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/testset.html | 288 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/testsets_flaky.html | 112 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/templates/testsets_top.html | 146 | ||||
-rw-r--r-- | non-puppet/qtmetrics2/testset_search.php | 10 |
13 files changed, 811 insertions, 235 deletions
diff --git a/non-puppet/qtmetrics2/index.php b/non-puppet/qtmetrics2/index.php index c17924b..746ffbe 100644 --- a/non-puppet/qtmetrics2/index.php +++ b/non-puppet/qtmetrics2/index.php @@ -34,8 +34,8 @@ /** * Qt Metrics API - * @version 0.4 - * @since 18-06-2015 + * @version 0.5 + * @since 25-06-2015 * @author Juha Sippola */ @@ -133,12 +133,13 @@ $app->get('/test/flaky', function() use($app) }); /** - * UI route: /testset/:testset (GET) + * UI route: /testset/:testset/:project (GET) */ -$app->get('/testset/:testset', function($testset) use($app) +$app->get('/testset/:testset/:project', function($testset, $project) use($app) { $testset = strip_tags($testset); + $project = strip_tags($project); $ini = Factory::conf(); $breadcrumb = array( array('name' => 'home', 'link' => Slim\Slim::getInstance()->urlFor('root')) @@ -150,10 +151,21 @@ $app->get('/testset/:testset', function($testset) use($app) 'refreshed' => Factory::db()->getDbRefreshed() . ' (GMT)', 'lastDaysFailures' => $ini['top_failures_last_days'], 'lastDaysFlaky' => $ini['flaky_testsets_last_days'], + 'sinceDateFailures' => Factory::getSinceDate(intval($ini['top_failures_last_days']) - 1), + 'sinceDateFlaky' => Factory::getSinceDate(intval($ini['flaky_testsets_last_days']) - 1), 'masterProject' => $ini['master_build_project'], 'masterState' => $ini['master_build_state'], - 'testsets' => Factory::createTestset( + 'projectBuilds' => Factory::db()->getProjectBuildsByBranch( + $ini['master_build_project'], + $ini['master_build_state']), + 'testset' => Factory::createTestset( + $testset, + $project, + $ini['master_build_project'], + $ini['master_build_state']), // managed as object + 'testsetRuns' => Factory::createTestsetRuns( $testset, + $project, $ini['master_build_project'], $ini['master_build_state']) // managed as objects )); @@ -164,7 +176,7 @@ $app->get('/testset/:testset', function($testset) use($app) )); $app->response()->status(404); } -}); +})->name('testsetProject'); $app->run(); @@ -180,7 +192,10 @@ if (isset($_POST["testsetInputSubmit"])) { exit(); } if (isset($_POST["testsetInputValue"])) { - header('Location: ' . Slim\Slim::getInstance()->urlFor('root') . 'testset/' . htmlspecialchars($_POST['testsetInputValue'])); + $string = explode(' (in ', htmlspecialchars($_POST['testsetInputValue'])); // the separator must match with that used in testset_search.php + $testset = $string[0]; + $project = str_replace(')', '', $string[1]); + header('Location: ' . Slim\Slim::getInstance()->urlFor('root') . 'testset/' . $testset . '/' . $project); exit(); } } diff --git a/non-puppet/qtmetrics2/scripts/tooltip.js b/non-puppet/qtmetrics2/scripts/tooltip.js new file mode 100644 index 0000000..78dcfb9 --- /dev/null +++ b/non-puppet/qtmetrics2/scripts/tooltip.js @@ -0,0 +1,63 @@ +/* +############################################################################# +## +## 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$ +## +############################################################################# + +/** + * Initialize Bootstrap tooltips + * @version 0.1 + * @since 26-06-2015 + * @author Juha Sippola + */ + +$(function () { + + // Set tooltip activation to click on touch devices (and hover on others) + var is_touch_device = ("ontouchstart" in window) || window.DocumentTouch && document instanceof DocumentTouch; + $(".clickOnTouch").tooltip({ + trigger: is_touch_device ? "click" : "hover" + }); + + // Bootstrap tooltip + $('[data-toggle="tooltip"]').tooltip(); + + // Hide clicked tooltip + $('body').on('click', function (e) { + $('[data-toggle="tooltip"]').each(function () { + //the 'is' for element that triggered the tooltip + if (!$(this).is(e.target) && $(this).has(e.target).length === 0) { + $(this).tooltip('hide'); + } + }); + }); + +}); diff --git a/non-puppet/qtmetrics2/src/Database.php b/non-puppet/qtmetrics2/src/Database.php index 9f9999c..efc87c3 100644 --- a/non-puppet/qtmetrics2/src/Database.php +++ b/non-puppet/qtmetrics2/src/Database.php @@ -34,8 +34,8 @@ /** * Database class - * @version 0.3 - * @since 16-06-2015 + * @version 0.4 + * @since 22-06-2015 * @author Juha Sippola */ @@ -114,16 +114,20 @@ class Database { { $result = array(); $query = $this->db->prepare(" - SELECT DISTINCT name + SELECT testset.name AS testset, project.name AS project FROM testset - WHERE name LIKE ? - ORDER BY name; + INNER JOIN project ON testset.project_id = project.id + WHERE testset.name LIKE ? + ORDER BY testset.name; "); $query->execute(array( '%' . $filter . '%' )); while($row = $query->fetch(PDO::FETCH_ASSOC)) { - $result[] = array('name' => $row['name']); + $result[] = array( + 'name' => $row['testset'], + 'project' => $row['project'] + ); } return $result; } @@ -499,6 +503,95 @@ class Database { } /** + * Get project build keys and timestamps by branch + * @param string $runProject + * @param string $runState + * @return array (string branch, string build_key, string timestamp) + */ + public function getProjectBuildsByBranch($runProject, $runState) + { + $result = array(); + $query = $this->db->prepare(" + SELECT + branch.name AS branch, + project_run.build_key, + project_run.timestamp + FROM project_run + INNER JOIN branch ON project_run.branch_id = branch.id + WHERE + 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_run.timestamp DESC; + "); + $query->execute(array( + $runProject, + $runState + )); + while($row = $query->fetch(PDO::FETCH_ASSOC)) { + $result[] = array( + 'branch' => $row['branch'], + 'buildKey' => $row['build_key'], + 'timestamp' => $row['timestamp'] + ); + } + return $result; + } + + /** + * Get run results for a testset in specified builds by branch and configuration + * @param string $testset + * @param $testsetProject + * @param string $runProject + * @param string $runState + * @return array (string branch, string conf, string build_key, string result) + */ + public function getTestsetResultsByBranchConf($testset, $testsetProject, $runProject, $runState) + { + $result = array(); + $query = $this->db->prepare(" + SELECT + branch.name AS branch, + conf.name AS conf, + project_run.build_key, + testset_run.result, + project_run.timestamp, + testset_run.duration, + testset_run.run + FROM testset_run + 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 + testset.name = ? AND + project.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, conf.name, project_run.timestamp DESC; + "); + $query->execute(array( + $testset, + $testsetProject, + $runProject, + $runState + )); + while($row = $query->fetch(PDO::FETCH_ASSOC)) { + $result[] = array( + 'branch' => $row['branch'], + 'conf' => $row['conf'], + 'buildKey' => $row['build_key'], + 'result' => $row['result'], + 'timestamp' => $row['timestamp'], + 'duration' => $row['duration'], + 'run' => $row['run'] + ); + } + 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 ce1751e..0870f8c 100644 --- a/non-puppet/qtmetrics2/src/Factory.php +++ b/non-puppet/qtmetrics2/src/Factory.php @@ -34,8 +34,8 @@ /** * Factory class - * @version 0.2 - * @since 12-06-2015 + * @version 0.3 + * @since 23-06-2015 * @author Juha Sippola */ @@ -166,7 +166,7 @@ class Factory { $objects = array(); $ini = self::conf(); // Failure result list (from specified builds only) - if ($listType == self::LIST_FAILURES) { + if ($listType === self::LIST_FAILURES) { $days = intval($ini['top_failures_last_days']) - 1; $since = self::getSinceDate($days); $limit = intval($ini['top_failures_n']); @@ -179,7 +179,7 @@ class Factory { } } // Flaky list (all builds) - if ($listType == self::LIST_FLAKY) { + if ($listType === self::LIST_FLAKY) { $days = intval($ini['flaky_testsets_last_days']) - 1; $since = self::getSinceDate($days); $limit = intval($ini['flaky_testsets_n']); @@ -194,39 +194,65 @@ class Factory { } /** - * Create Testset object(s) for those in database - * If several testsets with same name in different projects, all are created + * Create Testset object for that in database * Counts are limited by date (since) and length, failure result counts for specified builds only * @param string $name + * @param string $testsetProject * @param string $runProject * @param string $runState * @return array Testset object(s) */ - public static function createTestset($name, $runProject, $runState) + public static function createTestset($name, $testsetProject, $runProject, $runState) { - $objects = array(); $ini = self::conf(); - // Get testset(s) - $dbTestset = self::db()->getTestsetProject($name); - foreach($dbTestset as $testset) { - $obj = new Testset($testset['name'], $testset['project']); - $obj->setStatus($runProject, $runState); - // Failure result counts (from specified builds only) - $days = intval($ini['top_failures_last_days']) - 1; - $since = self::getSinceDate($days); - $dbTestsetDetails = self::db()->getTestsetResultCounts($name, $runProject, $runState, $since); - foreach($dbTestsetDetails as $detail) { - if ($testset['project'] == $detail['project']) - $obj->setTestsetResultCounts($detail['passed'], $detail['failed']); - } - // Flaky counts (all builds) - $days = intval($ini['flaky_testsets_last_days']) - 1; - $since = self::getSinceDate($days); - $dbTestsetDetails = self::db()->getTestsetFlakyCounts($name, $since); - foreach($dbTestsetDetails as $detail) { - if ($testset['project'] == $detail['project']) - $obj->setTestsetFlakyCounts($detail['flaky'], $detail['total']); - } + $obj = new Testset($name, $testsetProject); + $obj->setStatus($runProject, $runState); + // Failure result counts (from specified builds only) + $days = intval($ini['top_failures_last_days']) - 1; + $since = self::getSinceDate($days); + $dbTestsetDetails = self::db()->getTestsetResultCounts($name, $runProject, $runState, $since); + foreach($dbTestsetDetails as $detail) { + if ($detail['project'] === $testsetProject) + $obj->setTestsetResultCounts($detail['passed'], $detail['failed']); + } + // Flaky counts (all builds) + $days = intval($ini['flaky_testsets_last_days']) - 1; + $since = self::getSinceDate($days); + $dbTestsetDetails = self::db()->getTestsetFlakyCounts($name, $since); + foreach($dbTestsetDetails as $detail) { + if ($detail['project'] === $testsetProject) + $obj->setTestsetFlakyCounts($detail['flaky'], $detail['total']); + } + return $obj; + } + + /** + * Create TestsetRun objects for those in database + * @param string $testset + * @param string $testsetProject + * @param string $runProject + * @param string $runState + * @return array TestsetRun objects + */ + public static function createTestsetRuns($testset, $testsetProject, $runProject, $runState) + { + $objects = array(); + $dbEntries = self::db()->getTestsetResultsByBranchConf($testset, $testsetProject, $runProject, $runState); + foreach($dbEntries as $entry) { + $obj = new TestsetRun( + $testset, + $testsetProject, + $runProject, + $entry['branch'], + $runState, + $entry['buildKey'], + $entry['conf'], + $entry['run'], + TestsetRun::stripResult($entry['result']), + TestsetRun::isInsignificant($entry['result']), + $entry['timestamp'], + $entry['duration'] + ); $objects[] = $obj; } return $objects; diff --git a/non-puppet/qtmetrics2/src/TestsetRun.php b/non-puppet/qtmetrics2/src/TestsetRun.php index 9f5f198..f733712 100644 --- a/non-puppet/qtmetrics2/src/TestsetRun.php +++ b/non-puppet/qtmetrics2/src/TestsetRun.php @@ -34,8 +34,8 @@ /** * TestsetRun class - * @version 0.2 - * @since 12-06-2015 + * @version 0.3 + * @since 23-06-2015 * @author Juha Sippola */ @@ -56,13 +56,19 @@ class TestsetRun extends ProjectRun { private $name; /** + * Testset project name. + * @var string + */ + private $testsetProjectName; + + /** * Configuration name. * @var string */ private $confName; /** - * Run number (a failed test is repeated once). + * Run number (a failed test is repeated). * @var int */ private $run; @@ -77,6 +83,7 @@ class TestsetRun extends ProjectRun { * TestsetRun constructor. * TestsetRun include the result in the project configuration build * @param string $testsetName + * @param string $testsetProjectName * @param string $projectName * @param string $branchName * @param string $stateName @@ -86,11 +93,12 @@ class TestsetRun extends ProjectRun { * @param string $result (plain result without any possible flags) * @param bool $insignificant (true = insignificant) * @param int $timestamp - * @param int $duration + * @param int $duration (in deciseconds) */ - public function __construct($name, $projectName, $branchName, $stateName, $buildKey, $confName, $run, $result, $insignificant, $timestamp, $duration) { + public function __construct($name, $testsetProjectName, $projectName, $branchName, $stateName, $buildKey, $confName, $run, $result, $insignificant, $timestamp, $duration) { parent::__construct($projectName, $branchName, $stateName, $buildKey, $result, $timestamp, $duration); $this->name = $name; + $this->$testsetProjectName = $testsetProjectName; $this->confName = $confName; $this->run = $run; $this->insignificant = $insignificant; @@ -106,6 +114,24 @@ class TestsetRun extends ProjectRun { } /** + * Get configuration name. + * @return string + */ + public function getConfName() + { + return $this->confName; + } + + /** + * Get run number. + * @return int + */ + public function getRun() + { + return $this->run; + } + + /** * Get insignificance flag. * @return bool (true = insignificant) */ @@ -134,7 +160,7 @@ class TestsetRun extends ProjectRun { public static function isInsignificant($resultString) { $flag = false; - if (strpos($resultString, 'i') == 0) // begins with 'i' + if (strpos($resultString, 'i') === 0) // begins with 'i' $flag = true; return $flag; } diff --git a/non-puppet/qtmetrics2/src/test/DatabaseTest.php b/non-puppet/qtmetrics2/src/test/DatabaseTest.php index 98b854c..afb6671 100644 --- a/non-puppet/qtmetrics2/src/test/DatabaseTest.php +++ b/non-puppet/qtmetrics2/src/test/DatabaseTest.php @@ -38,8 +38,8 @@ 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.3 - * @since 15-06-2015 + * @version 0.4 + * @since 23-06-2015 * @author Juha Sippola */ @@ -125,6 +125,10 @@ class DatabaseTest extends PHPUnit_Framework_TestCase $db = Factory::db(); $result = $db->getTestsetsFiltered($filter); $this->assertGreaterThanOrEqual($exp_match_count_min, count($result)); + foreach($result as $row) { + $this->assertArrayHasKey('name', $row); + $this->assertArrayHasKey('project', $row); + } } public function testGetTestsetsFilteredData() { @@ -180,9 +184,9 @@ class DatabaseTest extends PHPUnit_Framework_TestCase foreach($result as $row) { $this->assertArrayHasKey('os', $row); $this->assertArrayHasKey('os_version', $row); - if ($row['os'] == $exp_os) + if ($row['os'] === $exp_os) $osCount++; - if ($row['os_version'] == $exp_os_version) + if ($row['os_version'] === $exp_os_version) $versionCount++; } $this->assertGreaterThanOrEqual($exp_count_min, $osCount); @@ -208,7 +212,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase $result = $db->getLatestProjectBranchBuildKeys($project, $state); $this->assertNotEmpty($result); foreach($result as $row) { - if ($row['name'] == $exp_branch) { + if ($row['name'] === $exp_branch) { $this->assertArrayHasKey('name', $row); $this->assertArrayHasKey('key', $row); $this->assertEquals($exp_build_key, $row['key']); @@ -456,6 +460,90 @@ class DatabaseTest extends PHPUnit_Framework_TestCase } /** + * Test getProjectBuildsByBranch + * @dataProvider testGetProjectBuildsByBranchData + */ + public function testGetProjectBuildsByBranch($runProject, $runState, $exp_branch, $exp_key, $has_data) + { + $branches = array(); + $keys = array(); + $db = Factory::db(); + $result = $db->getProjectBuildsByBranch($runProject, $runState); + foreach($result as $row) { + $this->assertArrayHasKey('branch', $row); + $this->assertArrayHasKey('buildKey', $row); + $this->assertArrayHasKey('timestamp', $row); + $branches[] = $row['branch']; + $keys[] = $row['buildKey']; + } + if ($has_data) { + $this->assertNotEmpty($result); + $this->assertContains($exp_branch, $branches); + $this->assertContains($exp_key, $keys); + } else { + $this->assertEmpty($result); + } + } + public function testGetProjectBuildsByBranchData() + { + return array( + array('Qt5', 'state', 'dev', '1023', 1), + array('Qt5', 'state', 'stable', '1348', 1), + array('Qt5', 'state', 'stable', '1348', 1), + array('Qt5', 'state', 'stable', '1348', 1), + array('Qt5', 'state', 'dev', 'BuildKeyInStringFormat12345', 1), + array('Qt5', 'invalid', '', '', 0) + ); + } + + /** + * Test getTestsetResultsByBranchConf + * @dataProvider testGetTestsetResultsByBranchConfData + */ + public function testGetTestsetResultsByBranchConf($testset, $testsetProject, $runProject, $runState, $exp_branch, $exp_conf, $exp_key, $exp_result, $has_data) + { + $branches = array(); + $confs = array(); + $keys = array(); + $results = array(); + $db = Factory::db(); + $result = $db->getTestsetResultsByBranchConf($testset, $testsetProject, $runProject, $runState); + foreach($result as $row) { + $this->assertArrayHasKey('branch', $row); + $this->assertArrayHasKey('conf', $row); + $this->assertArrayHasKey('buildKey', $row); + $this->assertArrayHasKey('result', $row); + $this->assertArrayHasKey('timestamp', $row); + $this->assertArrayHasKey('duration', $row); + $this->assertArrayHasKey('run', $row); + $branches[] = $row['branch']; + $confs[] = $row['conf']; + $keys[] = $row['buildKey']; + $results[] = $row['result']; + } + if ($has_data) { + $this->assertNotEmpty($result); + $this->assertContains($exp_branch, $branches); + $this->assertContains($exp_conf, $confs); + $this->assertContains($exp_key, $keys); + $this->assertContains($exp_result, $results); + } else { + $this->assertEmpty($result); + } + } + public function testGetTestsetResultsByBranchConfData() + { + return array( + array('tst_qftp', 'Qt5', 'Qt5', 'state', '', '', '', '', 0), + array('tst_qftp', 'QtBase', 'Qt5', 'state', 'dev', 'linux-g++_developer-build_qtnamespace_qtlibinfix_Ubuntu_11.10_x64', '1023', 'ifailed', 1), + array('tst_qftp', 'QtBase', 'Qt5', 'state', 'stable', 'win32-msvc2010_developer-build_angle_Windows_7', '1348', 'ipassed', 1), + array('tst_qfont', 'QtBase', 'Qt5', 'state', 'stable', 'macx-clang_developer-build_OSX_10.8', '1348', 'failed', 1), + array('tst_qfont', 'QtBase', 'Qt5', 'state', 'stable', 'win32-msvc2010_developer-build_angle_Windows_7', '1348', 'passed', 1), + array('tst_qfont', 'QtBase', 'Qt5', 'state', 'dev', 'linux-g++-32_developer-build_Ubuntu_10.04_x86', 'BuildKeyInStringFormat12345', 'failed', 1) + ); + } + + /** * Test getDbRefreshed */ public function testGetDbRefreshed() diff --git a/non-puppet/qtmetrics2/src/test/FactoryTest.php b/non-puppet/qtmetrics2/src/test/FactoryTest.php index 7bde27d..5f1028a 100644 --- a/non-puppet/qtmetrics2/src/test/FactoryTest.php +++ b/non-puppet/qtmetrics2/src/test/FactoryTest.php @@ -37,8 +37,8 @@ require_once(__DIR__.'/../Factory.php'); /** * Factory unit test class * @example To run (in qtmetrics root directory): php <path-to-phpunit>/phpunit.phar ./src/test - * @version 0.2 - * @since 12-06-2015 + * @version 0.3 + * @since 23-06-2015 * @author Juha Sippola */ @@ -111,11 +111,11 @@ class FactoryTest extends PHPUnit_Framework_TestCase public function testGetTestsetsFilteredData() { return array( - array('', 3), // test data includes three testsets - array('f', 3), // all - array('ft', 2), // tst_qftp and tst_networkselftest - array('ftp', 1), // tst_qftp - array('tst_qftp', 1), + array('', 4), // test data includes four testsets + array('f', 4), // all + array('ft', 3), // tst_qftp (twice) and tst_networkselftest + array('ftp', 2), // tst_qftp (twice) + array('tst_qftp', 2), array('tst_qfont', 1), array('tst_qfon', 1), array('tst_qfontt', 0), @@ -133,7 +133,7 @@ class FactoryTest extends PHPUnit_Framework_TestCase $projects = Factory::createProjects($runProject, $runState); foreach($projects as $project) { $this->assertTrue($project instanceof Project); - if ($project->getName() == $runProject) { // check only the projects with project_run data + if ($project->getName() === $runProject) { // check only the projects with project_run data $this->assertNotEmpty($project->getStatus()); } } @@ -192,12 +192,12 @@ class FactoryTest extends PHPUnit_Framework_TestCase * Test createTestset * @dataProvider testCreateTestsetData */ - public function testCreateTestset($testset, $project, $runProject, $runState) + public function testCreateTestset($name, $project, $runProject, $runState) { - $testsets = Factory::createTestset($testset, $runProject, $runState); + $testsets = Factory::createTestset($name, $project, $runProject, $runState); foreach($testsets as $testset) { $this->assertTrue($testset instanceof Testset); - if ($testset->getProjectName() == $project) { + if ($testset->getProjectName() === $project) { $status = $testset->getStatus(); $this->assertNotEmpty($status); $result = $testset->getTestsetResultCounts(); @@ -220,6 +220,25 @@ class FactoryTest extends PHPUnit_Framework_TestCase } /** + * Test createTestsetRuns + * @dataProvider testCreateTestsetRunsData + */ + public function testCreateTestsetRuns($name, $projectName, $projectName, $branchName, $stateName, $buildKey, $confName, $run, $result, $insignificant, $timestamp, $duration) + { + $runs = Factory::createTestsetRuns($name, $projectName, $projectName, $branchName, $stateName, $buildKey, $confName, $run, $result, $insignificant, $timestamp, $duration); + foreach($runs as $run) { + $this->assertTrue($run instanceof TestsetRun); + } + } + public function testCreateTestsetRunsData() + { + return array( + array('tst_qftp', 'qtbase', 'Qt5', 'stable', 'state', '1348', 'win64-msvc2012_developer-build_qtnamespace_Windows_8', 5, 'failed', true, '28.5.2013 0:54', 8130), + array('tst_qfont', 'qtbase', 'Qt5', 'dev', 'state', 'BuildKeyInStringFormat12345', 'linux-g++-32_developer-build_Ubuntu_10.04_x86', 1, 'failed', false, '28.5.2013 0:54', 8130) + ); + } + + /** * Test getSinceDate * @dataProvider testGetSinceDateData */ diff --git a/non-puppet/qtmetrics2/styles/qtmetrics.css b/non-puppet/qtmetrics2/styles/qtmetrics.css index 8c01db0..0d47cc8 100644 --- a/non-puppet/qtmetrics2/styles/qtmetrics.css +++ b/non-puppet/qtmetrics2/styles/qtmetrics.css @@ -35,8 +35,8 @@ /** * Qt Metrics style sheet - * @version 0.1 - * @since 04-06-2015 + * @version 0.2 + * @since 22-06-2015 * @author Juha Sippola */ @@ -53,7 +53,7 @@ * Load home page image (from www.qt.io) with text color adjustments in tablets and bigger devices only (typically using faster connection) */ -@media screen and (min-width: 720px) { +@media screen and (min-width: 768px) { .jumbotron { background-image: url("https://d3hp9ud7yvwzy0.cloudfront.net/wp-content/uploads/2014/06/Qt-in-nutshell-hero2.jpg"); background-size: cover; @@ -77,7 +77,7 @@ * Include UI elements and behavior in tablets and bigger devices only (typically using faster connection) */ -@media screen and (max-width: 720px) { +@media screen and (max-width: 768px) { .showInLargeDisplay { display: none; } @@ -92,6 +92,16 @@ } /* + * Make the tooltip align left, respect new lines and prevent text from wrapping + */ +.tooltip-inner { + text-align: left; + white-space: pre; + max-width: none; + background-color: #12293E; +} + +/* * Make space horizontally outside an element */ @@ -131,6 +141,10 @@ border-left: 2px solid lightgrey; } +.rightBorder { + border-right: 2px solid lightgrey; +} + .center { text-align: center } @@ -170,3 +184,7 @@ .textSmall { font-size: small; } + +.bold { + font-weight: bold; +} diff --git a/non-puppet/qtmetrics2/templates/about.html b/non-puppet/qtmetrics2/templates/about.html index c893598..1ba66fc 100644 --- a/non-puppet/qtmetrics2/templates/about.html +++ b/non-puppet/qtmetrics2/templates/about.html @@ -34,8 +34,8 @@ /** * About window content - * @version 0.5 - * @since 18-06-2015 + * @version 0.6 + * @since 26-06-2015 * @author Juha Sippola */ @@ -44,4 +44,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.5 (18-Jun-2015)</small></p> +<p><small>Version 0.6 (26-Jun-2015)</small></p> diff --git a/non-puppet/qtmetrics2/templates/testset.html b/non-puppet/qtmetrics2/templates/testset.html index c69e859..59f98e4 100644 --- a/non-puppet/qtmetrics2/templates/testset.html +++ b/non-puppet/qtmetrics2/templates/testset.html @@ -34,8 +34,8 @@ /** * Testset page - * @version 0.3 - * @since 18-06-2015 + * @version 0.4 + * @since 26-06-2015 * @author Juha Sippola */ @@ -43,23 +43,26 @@ {% include "header.html" %} -{# testsets as Testset objects +{# Failed/passed bar area size in px #} +{% set BAR_AREA = 120 %} + +{# testset as Testset object /** * @var Testset[] testsets */ #} -{# Get the testset name #} -{% set testsetName = '' %} -{% for testset in testsets %} - {% set testsetName = testset.getName %} -{% endfor %} +{# testsetRuns as TestsetRun objects +/** + * @var TestsetRun[] testsetRuns + */ +#} <ol class="breadcrumb"> {% for link in breadcrumb %} <li><a href="{{ link.link }}">{{ link.name }}</a></li> {% endfor %} - <li class="active">{{ testsetName }}</li> + <li class="active">{{ testset.getName }}</li> </ol> <div class="container-fluid"> @@ -67,14 +70,18 @@ <div class="col-sm-12 col-md-12 main"> + {##### Title #####} + <h1 class="page-header"> - {{ testsetName }} + {{ 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> @@ -83,35 +90,54 @@ <strong>{{ masterProject }} {{ masterState }}</strong> builds across all branches (shows failed if failed in one or in several).</li> <li><strong>failed</strong> count shows the number of <strong>{{ masterProject }} {{ masterState }}</strong> - builds where {{ testsetName }} failed during the last {{ lastDaysFailures }} days.</li> + builds where {{ testset.getName }} failed during the last {{ lastDaysFailures }} days + (since {{ sinceDateFailures }}).</li> <li><strong>flaky</strong> count shows the number of <strong>all</strong> builds where - {{ testsetName }} failed on the first run but, when rerun, it passed - (during the last {{ lastDaysFlaky }} days).</li> + {{ testset.getName }} failed on the first run but, when rerun, it passed + (during the last {{ lastDaysFlaky }} days, since {{ sinceDateFlaky }}).</li> + <li><strong>Results in Branches</strong> shows the {{ testset.getName }} run results by branch + and their configuration on <strong>{{ masterProject }} {{ masterState }}</strong> builds + (<span class="glyphicon glyphicon-ok green"></span> = passed, + <span class="glyphicon glyphicon-ok-sign green"></span> = passed as flaky, + <span class="glyphicon glyphicon-remove red"></span> = failed); details on the runs are + available as tooltip on result icon.</li> </ul> </div> </div> - <div class="panel-body"> - <div class="table-responsive"> - <table class="table table-striped"> - <thead> - <tr> - <th>testset</th> - <th class="showInLargeDisplay">project</th> - <th>latest result</th> - <th class="leftBorder center">failed <span class ="gray">(total)</span></th> - <th class="leftBorder center">flaky <span class ="gray">(total)</span></th> - </tr> - </thead> - <tbody> - {# Print testset(s) #} - {% for testset in testsets %} + {##### Summary #####} + + <div class="panel panel-primary"> + <div class="panel-heading"> + <h4 class="panel-title bold">Summary</h4> + </div> + <div class="panel-body"> + <div class="table-responsive"> + <table class="table table-striped"> + <thead> <tr> - {# Testset name #} - <td>{{ testset.getName }}</td> + <th>project</th> + <th>latest result</th> + <th class="leftBorder center"><span class="spaceHorizontal glyphicon glyphicon-remove red"></span>failed <span class ="gray">(total)</span></th> + <th class="showInLargeDisplay"></th> + <th class="leftBorder center"><span class="spaceHorizontal glyphicon glyphicon-ok-sign green"></span>flaky <span class ="gray">(total)</span></th> + <th class="showInLargeDisplay"></th> + </tr> + </thead> + <tbody> + {# Calculate max result count for the bar #} + {% set maxCount = 1 %} + {% if (testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed) > maxCount %} + {% set maxCount = testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed %} + {% endif %} + {% if testset.getTestsetFlakyCounts.flaky > maxCount %} + {% set maxCount = testset.getTestsetFlakyCounts.flaky %} + {% endif %} + {# Print summary #} + <tr> {# Project name #} - <td class="showInLargeDisplay">{{ testset.getProjectName }}</td> + <td>{{ testset.getProjectName }}</td> {# Testset status according to the latest build results #} {% if testset.getStatus == constant('testsetRun::RESULT_SUCCESS') %} @@ -128,30 +154,208 @@ {% set passed = testset.getTestsetResultCounts.passed %} {% set total = passed + failed %} <td class="leftBorder center">{{ failed }}<span class ="gray"> ({{ total }})</span></td> + {# Show results as bars (scaled to BAR_AREA px) #} + {% set passedBar = ((BAR_AREA/maxCount) * passed)|round(0, 'floor') %} + {% if (passed > 0) and (passedBar == 0) %} + {% set passedBar = 1 %} + {% endif %} + {% set failedBar = ((BAR_AREA/maxCount)*failed)|round(0, 'floor') %} + {% if (failed > 0) and (failedBar == 0) %} + {% set failedBar = 1 %} + {% endif %} + <td class="center showInLargeDisplay"> + <div> + <div class="floatLeft redBackground" style="width: {{ failedBar }}px">{{ failed }}</div> + <div class="floatLeft greenBackground" style="width: {{ passedBar }}px">{{ passed }}</div> + </div> + </td> {# Show flaky #} {% set flaky = testset.getTestsetFlakyCounts.flaky %} <td class="leftBorder center">{{ flaky }}<span class ="gray"> ({{ total }})</span></td> + {# Show results as bars (scaled to BAR_AREA px) #} + {% set flakyBar = ((BAR_AREA/maxCount)*flaky)|round(0, 'floor') %} + {% if (flaky > 0) and (flakyBar == 0) %} + {% set flakyBar = 1 %} + {% endif %} + <td class="center showInLargeDisplay"> + {% if flaky > 0 %} + <div> + <div class="floatLeft redBackground" style="width: {{ flakyBar }}px">{{ flaky }}</div> + </div> + {% endif %} + </td> </tr> - {% endfor %} - </tbody> - </table> - </div> {# /table-responsive #} - </div> {# /panel-body #} + </tbody> + </table> + </div> {# /table-responsive #} + </div> {# /panel-body #} + </div> {# /panel... #} + + {##### Results in Branches #####} + + <div class="panel panel-primary"> + <div class="panel-heading"> + <h4 class="panel-title bold">Results in Branches</h4> + </div> + </div> + + {# Get branches #} + {% set branches = [] %} + {% for run in projectBuilds %} + {% if run.branch not in branches %} + {% set branches = branches|merge([run.branch]) %} + {% endif %} + {% endfor %} + + {# Loop all the branches #} + {% for branch in branches %} + + {# Get all build keys #} + {% set buildKey = '' %} + {% set buildKeys = [] %} + {% set dates = [] %} + {% for run in projectBuilds %} + {% if run.branch == branch %} + {% if buildKey != run.buildKey %} + {% set buildKey = run.buildKey %} + {% set buildKeys = buildKeys|merge([run.buildKey]) %} + {% set dates = dates|merge([run.timestamp]) %} + {% endif %} + {% endif %} + {% endfor %} + + {# Check if testset run for this branch #} + {% set testsetBranch = 0 %} + {% for run in testsetRuns if run.getBranchName == branch %} + {% set testsetBranch = 1 %} + {% endfor %} + + {# Show branch if testset run for it #} + {% if testsetBranch %} + <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 rightBorder">{{ testset.getName }}</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> + {% else %} + {{ buildKey }} + {% endif %} + <br> + <span class="gray"><small>{{ dates[key]|date("m-d") }}</small></span> + </th> + {% endfor %} + </tr> + </thead> + <tbody> + {% set confPrev = '' %} + {% set buildKeyIndexPrinted = -1 %} + {% set buildKeyFound = 0 %} + {% for run in testsetRuns if run.getBranchName == branch %} + + {# New row for each conf #} + {% if confPrev != run.getConfName %} + {# Close previous row #} + {% if confPrev != '' %} + {# Fill empty cells at the end of the row #} + {% for key, buildKey in buildKeys %} + {% if key > buildKeyIndexPrinted %} + <td></td> + {% endif %} + {% endfor %} + </tr> + {% endif %} + <tr> + <td class="rightBorder"><small>{{ run.getConfName }}</small></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 #} + {% set flaky = '' %} + {% if run.getResult == constant('testsetRun::RESULT_SUCCESS') %} + {% if run.getRun == 1 %} + {% set resultIcon = 'glyphicon glyphicon-ok green' %} + {% else %} + {# Flaky #} + {% set resultIcon = 'glyphicon glyphicon-ok-sign green' %} + {% set flaky = ' (on run ' ~ run.getRun ~ ' as flaky)' %} + {% endif %} + {% elseif run.getResult == constant('testsetRun::RESULT_FAILURE') %} + {% set resultIcon = 'glyphicon glyphicon-remove red' %} + {% else %} + {% set resultIcon = '' %} + {% endif %} + {% if (run.getDuration / 10) > 60 %} + {% set durationFormatted = ' (00:' ~ (run.getDuration/10)|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 }} {{ flaky }}</td></tr> + <tr><th>Duration: </th><td>{{ run.getDuration / 10 }} s {{ durationFormatted }}</td></tr> + <tr><th>Run #: </th><td>{{ run.getRun }}</td></tr> + <tr><th>Insignificant: </th><td>{% if run.getInsignificant %}yes{% else %}no{% endif %}</td></tr> + </table>"> + </span> + </td> + {% set buildKeyFound = 1 %} + {% else %} + {# Print empty cell #} + <td></td> + {% endif %} + {% set buildKeyIndexPrinted = key %} + {% endif %} + {% endfor %} + {% set confPrev = run.getConfName %} + {% endfor %} + + {# 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 %} + </tr> + </tbody> + </table> + </div> {# /table-responsive #} + </div> {# /panel-body #} + </div> {# /panel... #} + {% endif %} {# testsetBranch #} + {% endfor %} </div> {# /col... #} </div> {# /row #} -</div> {# /container-fluid #} -<br> -<div class="alert alert-danger" role="alert"> - <strong>Under construction!</strong> -</div> +</div> {# /container-fluid #} {% include "footer.html" %} {# Local scripts for this page #} -{# (none) #} +<script src="scripts/tooltip.js"></script> {% include "close.html" %} diff --git a/non-puppet/qtmetrics2/templates/testsets_flaky.html b/non-puppet/qtmetrics2/templates/testsets_flaky.html index 9baa9f2..018881f 100644 --- a/non-puppet/qtmetrics2/templates/testsets_flaky.html +++ b/non-puppet/qtmetrics2/templates/testsets_flaky.html @@ -34,8 +34,8 @@ /** * Flaky testsets page - * @version 0.2 - * @since 18-06-2015 + * @version 0.3 + * @since 24-06-2015 * @author Juha Sippola */ @@ -64,6 +64,8 @@ <div class="col-sm-12 col-md-12 main"> + {##### Title #####} + <h1 class="page-header"> Top {{ topN }} Flaky Testsets <button type="button" class="btn btn-xs btn-info" data-toggle="collapse" data-target="#info" aria-expanded="false" aria-controls="info"> @@ -71,7 +73,8 @@ </button> <small>{{ refreshed }}</small> </h1> - <h3 class="sub-header">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h3> + + {##### Info well #####} <div class="collapse" id="info"> <div class="well infoWell"> @@ -84,56 +87,63 @@ </div> </div> - <div class="panel-body"> - <div class="table-responsive"> - <table class="table table-striped"> - <thead> - <tr> - <th>testset</th> - <th>project</th> - <th class="leftBorder center">flaky <span class ="gray">(total)</span></th> - <th class="showInLargeDisplay">flaky</th> - </tr> - </thead> - <tbody> - {# Calculate max result count for the bar #} - {% set maxCount = 1 %} - {% for testset in testsets %} - {% if testset.getTestsetFlakyCounts.flaky > maxCount %} - {% set maxCount = testset.getTestsetFlakyCounts.flaky %} - {% endif %} - {% endfor %} - - {# Print testsets #} - {% for testset in testsets %} - <tr> - {# Testset name #} - <td><a href="{{ testsetRoute }}/{{ testset.getName }}">{{ testset.getName }}</a></td> - - {# Project name #} - <td>{{ testset.getProjectName }}</td> - - {# Show results as numbers #} - {% set flaky = testset.getTestsetFlakyCounts.flaky %} - {% set total = testset.getTestsetFlakyCounts.total %} - <td class="leftBorder center">{{ flaky }}<span class ="gray"> ({{ total }})</span></td> + {##### Flaky list #####} - {# Show results as bars (scaled to BAR_AREA px) #} - {% set flakyBar = ((BAR_AREA/maxCount)*flaky)|round(0, 'floor') %} - {% if (flaky > 0) and (flakyBar == 0) %} - {% set flakyBar = 1 %} - {% endif %} - <td class="center showInLargeDisplay"> - <div> - <div class="floatLeft redBackground" style="width: {{ flakyBar }}px"> </div> - </div> - </td> + <div class="panel panel-primary"> + <div class="panel-heading"> + <h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4> + </div> + <div class="panel-body"> + <div class="table-responsive"> + <table class="table table-striped"> + <thead> + <tr> + <th>testset</th> + <th>project</th> + <th class="leftBorder center">flaky <span class ="gray">(total)</span></th> + <th class="showInLargeDisplay">flaky</th> </tr> - {% endfor %} - </tbody> - </table> - </div> {# /table-responsive #} - </div> {# /panel-body #} + </thead> + <tbody> + {# Calculate max result count for the bar #} + {% set maxCount = 1 %} + {% for testset in testsets %} + {% if testset.getTestsetFlakyCounts.flaky > maxCount %} + {% set maxCount = testset.getTestsetFlakyCounts.flaky %} + {% endif %} + {% endfor %} + + {# Print testsets #} + {% for testset in testsets %} + <tr> + {# Testset name #} + <td><a href="{{ testsetRoute }}/{{ testset.getName }}/{{ testset.getProjectName }}">{{ testset.getName }}</a></td> + + {# Project name #} + <td>{{ testset.getProjectName }}</td> + + {# Show results as numbers #} + {% set flaky = testset.getTestsetFlakyCounts.flaky %} + {% set total = testset.getTestsetFlakyCounts.total %} + <td class="leftBorder center">{{ flaky }}<span class ="gray"> ({{ total }})</span></td> + + {# Show results as bars (scaled to BAR_AREA px) #} + {% set flakyBar = ((BAR_AREA/maxCount)*flaky)|round(0, 'floor') %} + {% if (flaky > 0) and (flakyBar == 0) %} + {% set flakyBar = 1 %} + {% endif %} + <td class="center showInLargeDisplay"> + <div> + <div class="floatLeft redBackground" style="width: {{ flakyBar }}px"> </div> + </div> + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> {# /table-responsive #} + </div> {# /panel-body #} + </div> {# /panel... #} </div> {# /col... #} </div> {# /row #} diff --git a/non-puppet/qtmetrics2/templates/testsets_top.html b/non-puppet/qtmetrics2/templates/testsets_top.html index aa2d864..a9abec5 100644 --- a/non-puppet/qtmetrics2/templates/testsets_top.html +++ b/non-puppet/qtmetrics2/templates/testsets_top.html @@ -34,8 +34,8 @@ /** * Top failures (testsets) page - * @version 0.3 - * @since 18-06-2015 + * @version 0.4 + * @since 24-06-2015 * @author Juha Sippola */ @@ -64,6 +64,8 @@ <div class="col-sm-12 col-md-12 main"> + {##### Title #####} + <h1 class="page-header"> Top {{ topN }} Failures <button type="button" class="btn btn-xs btn-info" data-toggle="collapse" data-target="#info" aria-expanded="false" aria-controls="info"> @@ -71,7 +73,8 @@ </button> <small>{{ refreshed }}</small> </h1> - <h3 class="sub-header">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h3> + + {##### Info well #####} <div class="collapse" id="info"> <div class="well infoWell"> @@ -86,73 +89,80 @@ </div> </div> - <div class="panel-body"> - <div class="table-responsive"> - <table class="table table-striped"> - <thead> - <tr> - <th>testset</th> - <th class="showInLargeDisplay">project</th> - <th>latest result</th> - <th class="leftBorder center">failed <span class ="gray">(total)</span></th> - <th class="showInLargeDisplay">failed + passed</th> - </tr> - </thead> - <tbody> - {# Calculate max result count for the bar #} - {% set maxCount = 1 %} - {% for testset in testsets %} - {% if (testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed) > maxCount %} - {% set maxCount = testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed %} - {% endif %} - {% endfor %} - - {# Print testsets #} - {% for testset in testsets %} + {##### Top list #####} + + <div class="panel panel-primary"> + <div class="panel-heading"> + <h4 class="panel-title bold">Last {{ lastDays }} days <small>(since {{ sinceDate }})</small></h4> + </div> + <div class="panel-body"> + <div class="table-responsive"> + <table class="table table-striped"> + <thead> <tr> - {# Testset name #} - <td><a href="{{ testsetRoute }}/{{ testset.getName }}">{{ testset.getName }}</a></td> - - {# Project name #} - <td class="showInLargeDisplay">{{ testset.getProjectName }}</td> - - {# Testset status according to the latest build results #} - {% if testset.getStatus == constant('testsetRun::RESULT_SUCCESS') %} - {% set resultIcon = 'glyphicon glyphicon-ok green' %} - {% elseif testset.getStatus == constant('testsetRun::RESULT_FAILURE') %} - {% set resultIcon = 'glyphicon glyphicon-remove red' %} - {% else %} - {% set resultIcon = '' %} - {% endif %} - <td><span class="spaceHorizontal {{ resultIcon }}"></span>{{ testset.getStatus }}</td> - - {# Show results as numbers #} - {% set failed = testset.getTestsetResultCounts.failed %} - {% set passed = testset.getTestsetResultCounts.passed %} - {% set total = passed + failed %} - <td class="leftBorder center">{{ failed }}<span class ="gray"> ({{ total }})</span></td> - - {# Show results as bars (scaled to BAR_AREA px) #} - {% set passedBar = ((BAR_AREA/maxCount) * passed)|round(0, 'floor') %} - {% if (passed > 0) and (passedBar == 0) %} - {% set passedBar = 1 %} - {% endif %} - {% set failedBar = ((BAR_AREA/maxCount)*failed)|round(0, 'floor') %} - {% if (failed > 0) and (failedBar == 0) %} - {% set failedBar = 1 %} - {% endif %} - <td class="center showInLargeDisplay"> - <div> - <div class="floatLeft redBackground" style="width: {{ failedBar }}px"> </div> - <div class="floatLeft greenBackground" style="width: {{ passedBar }}px"> </div> - </div> - </td> + <th>testset</th> + <th class="showInLargeDisplay">project</th> + <th>latest result</th> + <th class="leftBorder center">failed <span class ="gray">(total)</span></th> + <th class="showInLargeDisplay">failed + passed</th> </tr> - {% endfor %} - </tbody> - </table> - </div> {# /table-responsive #} - </div> {# /panel-body #} + </thead> + <tbody> + {# Calculate max result count for the bar #} + {% set maxCount = 1 %} + {% for testset in testsets %} + {% if (testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed) > maxCount %} + {% set maxCount = testset.getTestsetResultCounts.passed + testset.getTestsetResultCounts.failed %} + {% endif %} + {% endfor %} + + {# Print testsets #} + {% for testset in testsets %} + <tr> + {# Testset name #} + <td><a href="{{ testsetRoute }}/{{ testset.getName }}/{{ testset.getProjectName }}">{{ testset.getName }}</a></td> + + {# Project name #} + <td class="showInLargeDisplay">{{ testset.getProjectName }}</td> + + {# Testset status according to the latest build results #} + {% if testset.getStatus == constant('testsetRun::RESULT_SUCCESS') %} + {% set resultIcon = 'glyphicon glyphicon-ok green' %} + {% elseif testset.getStatus == constant('testsetRun::RESULT_FAILURE') %} + {% set resultIcon = 'glyphicon glyphicon-remove red' %} + {% else %} + {% set resultIcon = '' %} + {% endif %} + <td><span class="spaceHorizontal {{ resultIcon }}"></span>{{ testset.getStatus }}</td> + + {# Show results as numbers #} + {% set failed = testset.getTestsetResultCounts.failed %} + {% set passed = testset.getTestsetResultCounts.passed %} + {% set total = passed + failed %} + <td class="leftBorder center">{{ failed }}<span class ="gray"> ({{ total }})</span></td> + + {# Show results as bars (scaled to BAR_AREA px) #} + {% set passedBar = ((BAR_AREA/maxCount) * passed)|round(0, 'floor') %} + {% if (passed > 0) and (passedBar == 0) %} + {% set passedBar = 1 %} + {% endif %} + {% set failedBar = ((BAR_AREA/maxCount)*failed)|round(0, 'floor') %} + {% if (failed > 0) and (failedBar == 0) %} + {% set failedBar = 1 %} + {% endif %} + <td class="center showInLargeDisplay"> + <div> + <div class="floatLeft redBackground" style="width: {{ failedBar }}px"> </div> + <div class="floatLeft greenBackground" style="width: {{ passedBar }}px"> </div> + </div> + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> {# /table-responsive #} + </div> {# /panel-body #} + </div> {# /panel... #} </div> {# /col... #} </div> {# /row #} diff --git a/non-puppet/qtmetrics2/testset_search.php b/non-puppet/qtmetrics2/testset_search.php index d280564..0758ad1 100644 --- a/non-puppet/qtmetrics2/testset_search.php +++ b/non-puppet/qtmetrics2/testset_search.php @@ -34,8 +34,8 @@ /** * Testset autocomplete search - * @version 0.1 - * @since 04-06-2015 + * @version 0.2 + * @since 25-06-2015 * @author Juha Sippola */ @@ -48,8 +48,12 @@ if (isset($_GET['term'])) { $rows = Factory::getTestsetsFiltered($_GET['term']); foreach ($rows as $row) { foreach ($row as $key => $value) { - $list[] = $value; + if ($key === 'name') + $name = $value; + else + $project = $value; } + $list[] = $name . ' (in ' . $project . ')'; // the separator must match with that used in index.php } // Return list as json string echo json_encode($list); |