summaryrefslogtreecommitdiffstats
path: root/non-puppet/qtmetrics2
diff options
context:
space:
mode:
authorJuha Sippola <juhasippola@outlook.com>2015-09-23 12:23:59 +0300
committerTony Sarajärvi <tony.sarajarvi@theqtcompany.com>2015-09-23 09:40:41 +0000
commit7054f29267bb4f3dec16b60217bbf28d61435aaa (patch)
treea8649b2e7a7933a9891ec1abacd67923b495b5c7 /non-puppet/qtmetrics2
parent1f60410f51f86287ebe9c8694d92df139e830b6f (diff)
Qt Metrics 2 (v0.34): Bpassed test rows for testset
New page to list blacklisted passed test rows since a specific date for one testset. This can be opened from the testset page via a button. Change-Id: I82acf6d03ad860f61360f8ede18787cfd9eb44aa Reviewed-by: Tony Sarajärvi <tony.sarajarvi@theqtcompany.com>
Diffstat (limited to 'non-puppet/qtmetrics2')
-rw-r--r--non-puppet/qtmetrics2/index.php74
-rw-r--r--non-puppet/qtmetrics2/scripts/ajax.js27
-rw-r--r--non-puppet/qtmetrics2/src/Database.php70
-rw-r--r--non-puppet/qtmetrics2/src/Factory.php30
-rw-r--r--non-puppet/qtmetrics2/src/Testrow.php107
-rw-r--r--non-puppet/qtmetrics2/src/test/DatabaseTest.php42
-rw-r--r--non-puppet/qtmetrics2/src/test/FactoryTest.php25
-rw-r--r--non-puppet/qtmetrics2/src/test/TestrowTest.php156
-rw-r--r--non-puppet/qtmetrics2/templates/about.html4
-rw-r--r--non-puppet/qtmetrics2/templates/testfunction.html11
-rw-r--r--non-puppet/qtmetrics2/templates/testfunctions_bpass.html7
-rw-r--r--non-puppet/qtmetrics2/templates/testfunctions_bpass_data.html138
-rw-r--r--non-puppet/qtmetrics2/templates/testrows_bpass.html111
-rw-r--r--non-puppet/qtmetrics2/templates/testset.html8
14 files changed, 728 insertions, 82 deletions
diff --git a/non-puppet/qtmetrics2/index.php b/non-puppet/qtmetrics2/index.php
index 98bb7a3..4156976 100644
--- a/non-puppet/qtmetrics2/index.php
+++ b/non-puppet/qtmetrics2/index.php
@@ -34,7 +34,7 @@
/**
* Qt Metrics API
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -518,7 +518,10 @@ $app->get('/data/test/bpassed', function() use($app)
'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
'lastDays' => $ini['blacklisted_pass_last_days'],
'sinceDate' => $since,
- 'testfunctions' => Factory::createTestfunctions(
+ 'list' => 'functions',
+ 'testset' => '',
+ 'project' => '',
+ 'tests' => Factory::createTestfunctions(
Factory::LIST_BPASSES,
'',
'',
@@ -570,13 +573,15 @@ $app->get('/data/test/bpassed/:testset/:project', function($testset, $project) u
$ini = Factory::conf();
$days = intval($ini['blacklisted_pass_last_days']) - 1;
$since = Factory::getSinceDate($days);
+ $testsetRoute = str_replace('/:testset/:project', '', Slim\Slim::getInstance()->urlFor('testset'));
$app->render('testfunctions_bpass_data.html', array(
- 'testsetRoute' => Slim\Slim::getInstance()->urlFor('root') . 'testset',
+ 'testsetRoute' => $testsetRoute,
'lastDays' => $ini['blacklisted_pass_last_days'],
'sinceDate' => $since,
+ 'list' => 'functions',
'testset' => $testset,
'project' => $project,
- 'testfunctions' => Factory::createTestfunctions(
+ 'tests' => Factory::createTestfunctions(
Factory::LIST_BPASSES,
$testset,
$project,
@@ -586,6 +591,65 @@ $app->get('/data/test/bpassed/:testset/:project', function($testset, $project) u
});
/**
+ * UI route: /test/bpassed/testrows/:testset/:project (GET)
+ */
+
+$app->get('/test/bpassed/testrows/:testset/:project', function($testset, $project) use($app)
+{
+ $ini = Factory::conf();
+ $dbStatus = Factory::db()->getDbRefreshStatus();
+ if (Factory::checkTestset($testset)) {
+ $days = intval($ini['blacklisted_pass_last_days']) - 1;
+ $since = Factory::getSinceDate($days);
+ $testsetRoute = str_replace('/:testset/:project', '', Slim\Slim::getInstance()->urlFor('testset'));
+ $breadcrumb = array(
+ array('name' => 'home', 'link' => Slim\Slim::getInstance()->urlFor('root')),
+ array('name' => $testset, 'link' => $testsetRoute . '/' . $testset . '/' . $project)
+ );
+ $app->render('testrows_bpass.html', array(
+ 'root' => Slim\Slim::getInstance()->urlFor('root'),
+ 'dbStatus' => $dbStatus,
+ 'refreshed' => $dbStatus['refreshed'] . ' (GMT)',
+ 'breadcrumb' => $breadcrumb,
+ 'lastDays' => $ini['blacklisted_pass_last_days'],
+ 'sinceDate' => $since,
+ 'testset' => $testset,
+ 'project' => $project,
+ 'masterProject' => $ini['master_build_project'],
+ 'masterState' => $ini['master_build_state']
+ ));
+ } else {
+ $app->render('empty.html', array(
+ 'root' => Slim\Slim::getInstance()->urlFor('root'),
+ 'dbStatus' => $dbStatus,
+ 'message' => '404 Not Found'
+ ));
+ $app->response()->status(404);
+ }
+})->name('bpassedtestsetTestrows');
+
+$app->get('/data/test/bpassed/testrows/:testset/:project', function($testset, $project) use($app)
+{
+ $ini = Factory::conf();
+ $days = intval($ini['blacklisted_pass_last_days']) - 1;
+ $since = Factory::getSinceDate($days);
+ $testfunctionRoute = str_replace('/:testfunction/:testset/:project/:conf', '', Slim\Slim::getInstance()->urlFor('testfunction'));
+ $app->render('testfunctions_bpass_data.html', array(
+ 'testfunctionRoute' => $testfunctionRoute,
+ 'lastDays' => $ini['blacklisted_pass_last_days'],
+ 'sinceDate' => $since,
+ 'list' => 'rows',
+ 'testset' => $testset,
+ 'project' => $project,
+ 'tests' => Factory::createTestrows(
+ $testset,
+ $project,
+ $ini['master_build_project'],
+ $ini['master_build_state']) // managed as objects
+ ));
+});
+
+/**
* UI route: /testset/:testset/:project (GET)
*/
@@ -602,6 +666,7 @@ $app->get('/testset/:testset/:project', function($testset, $project) use($app)
$testsetTestfunctionsRoute = str_replace('/:testset/:project/:conf', '', Slim\Slim::getInstance()->urlFor('testset_testfunctions'));
$testsetProjectRoute = str_replace('/:project', '', Slim\Slim::getInstance()->urlFor('testsetproject'));
$bpassedTestsetRoute = str_replace('/:testset/:project', '', Slim\Slim::getInstance()->urlFor('bpassedtestset'));
+ $bpassedtestsetTestrowsRoute = str_replace('/:testset/:project', '', Slim\Slim::getInstance()->urlFor('bpassedtestsetTestrows'));
$app->render('testset.html', array(
'root' => Slim\Slim::getInstance()->urlFor('root'),
'dbStatus' => $dbStatus,
@@ -610,6 +675,7 @@ $app->get('/testset/:testset/:project', function($testset, $project) use($app)
'testsetTestfunctionsRoute' => $testsetTestfunctionsRoute,
'testsetProjectRoute' => $testsetProjectRoute,
'bpassedTestsetRoute' => $bpassedTestsetRoute,
+ 'bpassedtestsetTestrowsRoute' => $bpassedtestsetTestrowsRoute,
'lastDaysFailures' => $ini['top_failures_last_days'],
'lastDaysFlaky' => $ini['flaky_testsets_last_days'],
'sinceDateFailures' => Factory::getSinceDate(intval($ini['top_failures_last_days']) - 1),
diff --git a/non-puppet/qtmetrics2/scripts/ajax.js b/non-puppet/qtmetrics2/scripts/ajax.js
index 7851819..294194b 100644
--- a/non-puppet/qtmetrics2/scripts/ajax.js
+++ b/non-puppet/qtmetrics2/scripts/ajax.js
@@ -34,20 +34,22 @@
/**
* Ajax route calls
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
$(function () {
- // Get all div ids on a page to call correct routes
var div;
var divs = [];
+ var project;
+ var testset;
+ var url;
+
+ // Get all div ids on a page to call correct routes
$(".container-fluid").find("div").each(function(){ divs.push(this.id); });
// Testset project / latest status
- var project;
- var testset;
if ($.inArray('testset_project_data_latest', divs) > -1) {
project = $('#project').html();
$.ajax({
@@ -118,7 +120,6 @@ $(function () {
if ($.inArray('testfunctions_blacklisted_passed_data', divs) > -1) {
testset = $('#testset').html();
project = $('#project').html();
- var url;
if (testset === '') {
url = "data/test/bpassed";
} else {
@@ -135,4 +136,20 @@ $(function () {
});
}
+ // Blacklisted passed testrows
+ if ($.inArray('testrows_blacklisted_passed_data', divs) > -1) {
+ testset = $('#testset').html();
+ project = $('#project').html();
+ url = "data/test/bpassed/testrows/" + testset + "/" + project;
+ $.ajax({
+ url: url,
+ dataType: "html",
+ cache: true
+ })
+ .done(function( html ) {
+ console.log(this.url + " done");
+ $('#testrows_blacklisted_passed_data').html(html);
+ });
+ }
+
});
diff --git a/non-puppet/qtmetrics2/src/Database.php b/non-puppet/qtmetrics2/src/Database.php
index 33b77b8..a3b7f1b 100644
--- a/non-puppet/qtmetrics2/src/Database.php
+++ b/non-puppet/qtmetrics2/src/Database.php
@@ -34,7 +34,7 @@
/**
* Database class
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -933,6 +933,72 @@ class Database {
}
/**
+ * Get counts of blacklisted passed testrows for a testset in specified builds since specified date
+ * Only the testfunctions that are blacklisted, are only passed and have been run since the specified date are listed
+ * @param string $testset
+ * @param string $project
+ * @param string $runProject
+ * @param string $runState
+ * @param string $date
+ * @return array (string name, string testfunction, string testset, string project, string conf, int bpassed, int btotal)
+ */
+ public function getTestrowsBlacklistedPassedCountsTestset($testset, $project, $runProject, $runState, $date)
+ {
+ $result = array();
+ $query = $this->db->prepare("
+ SELECT
+ testrow.name AS testrow,
+ testfunction.name AS testfunction,
+ testset.name AS testset,
+ project.name AS project,
+ conf.name AS conf,
+ COUNT(CASE WHEN testrow_run.result IN ('bpass', 'bxfail') THEN testrow_run.result END) AS bpassed,
+ COUNT(CASE WHEN testrow_run.result LIKE '%' THEN testrow_run.result END) AS btotal
+ FROM testrow_run
+ INNER JOIN testrow ON testrow_run.testrow_id = testrow.id
+ INNER JOIN testfunction_run ON testrow_run.testfunction_run_id = testfunction_run.id
+ 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
+ INNER JOIN state ON project_run.state_id = state.id
+ WHERE
+ project_run.project_id = (SELECT id FROM project WHERE name = ?) AND
+ project_run.state_id = (SELECT id FROM state WHERE name = ?) AND
+ testset.name = ? AND
+ project.name = ? AND
+ project_run.timestamp >= ? AND
+ branch.archived = 0
+ GROUP BY testrow.name, testfunction.name, testset.name, project.name, conf.name
+ ORDER BY project.name, testset.name, testfunction.name, testrow.name, conf.name;
+ ");
+ $query->bindParam(1, $runProject);
+ $query->bindParam(2, $runState);
+ $query->bindParam(3, $testset);
+ $query->bindParam(4, $project);
+ $query->bindParam(5, $date);
+ $query->execute();
+ while($row = $query->fetch(PDO::FETCH_ASSOC)) {
+ if ($row['bpassed'] === $row['btotal']) { // return only those where only bpasses
+ $result[] = array(
+ 'name' => $row['testrow'],
+ 'testfunction' => $row['testfunction'],
+ 'testset' => $row['testset'],
+ 'project' => $row['project'],
+ 'conf' => $row['conf'],
+ 'bpassed' => $row['bpassed'],
+ 'btotal' => $row['btotal']
+ );
+ }
+ }
+ return $result;
+ }
+
+ /**
* Get project run data by branch
* @param string $runProject
* @param string $runState
@@ -1434,7 +1500,7 @@ class Database {
INNER JOIN project_run ON conf_run.project_run_id = project_run.id
INNER JOIN branch ON project_run.branch_id = branch.id
WHERE
- (testrow_run.result LIKE '%fail' OR testrow_run.result LIKE '%skip' OR testrow_run.result LIKE '%x%') AND
+ (testrow_run.result LIKE '%fail' OR testrow_run.result LIKE '%skip' OR testrow_run.result LIKE '%x%' OR testrow_run.result LIKE 'b%') AND
testfunction.name = ? AND
testset.name = ? AND
project.name = ? AND
diff --git a/non-puppet/qtmetrics2/src/Factory.php b/non-puppet/qtmetrics2/src/Factory.php
index 7867154..7bce306 100644
--- a/non-puppet/qtmetrics2/src/Factory.php
+++ b/non-puppet/qtmetrics2/src/Factory.php
@@ -34,7 +34,7 @@
/**
* Factory class
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -48,6 +48,7 @@ require_once 'Testset.php';
require_once 'TestsetRun.php';
require_once 'Testfunction.php';
require_once 'TestfunctionRun.php';
+require_once 'Testrow.php';
require_once 'TestrowRun.php';
class Factory {
@@ -310,7 +311,7 @@ class Factory {
if ($listType === self::LIST_BPASSES) {
$days = intval($ini['blacklisted_pass_last_days']) - 1;
$since = self::getSinceDate($days);
- if ($testset === '')
+ if (empty($testset))
$dbEntries = self::db()->getTestfunctionsBlacklistedPassedCounts($runProject, $runState, $since);
else
$dbEntries = self::db()->getTestfunctionsBlacklistedPassedCountsTestset($testset, $project, $runProject, $runState, $since);
@@ -324,6 +325,31 @@ class Factory {
}
/**
+ * Create Testrow objects for those in database (with bpassed counts)
+ * List is limited by date (since) and length, and for specified builds only
+ * @param string $testset
+ * @param string $project
+ * @param string $runProject
+ * @param string $runState
+ * @return array Testfunction objects
+ */
+ public static function createTestrows($testset, $project, $runProject, $runState)
+ {
+ $objects = array();
+ $ini = self::conf();
+ // Blacklisted passed list (from specified builds only)
+ $days = intval($ini['blacklisted_pass_last_days']) - 1;
+ $since = self::getSinceDate($days);
+ $dbEntries = self::db()->getTestrowsBlacklistedPassedCountsTestset($testset, $project, $runProject, $runState, $since);
+ foreach($dbEntries as $entry) {
+ $obj = new Testrow($entry['name'], $entry['testfunction'], $entry['testset'], $entry['project'], $entry['conf']);
+ $obj->setBlacklistedCounts($entry['bpassed'], $entry['btotal']);
+ $objects[] = $obj;
+ }
+ return $objects;
+ }
+
+ /**
* Create ProjectRun objects for those in database
* @param string $runProject
* @param string $runState
diff --git a/non-puppet/qtmetrics2/src/Testrow.php b/non-puppet/qtmetrics2/src/Testrow.php
new file mode 100644
index 0000000..39f69c3
--- /dev/null
+++ b/non-puppet/qtmetrics2/src/Testrow.php
@@ -0,0 +1,107 @@
+<?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$
+##
+#############################################################################
+
+/**
+ * Testrow class
+ * @since 23-09-2015
+ * @author Juha Sippola
+ */
+
+class Testrow extends Testfunction {
+
+ /**
+ * Testfunction name.
+ * @var string
+ */
+ private $testfunctionName;
+
+ /**
+ * Testrow constructor.
+ * @param string $name
+ * @param string $testfunctionName
+ * @param string $testsetName
+ * @param string $testsetProjectName
+ * @param string $confName
+ */
+ public function __construct($name, $testfunctionName, $testsetName, $testsetProjectName, $confName) {
+ parent::__construct($testfunctionName, $testsetName, $testsetProjectName, $confName);
+ $this->name = $name;
+ $this->testfunctionName = $testfunctionName;
+ }
+
+ /**
+ * Get name of the testrow.
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get short name of the testrow.
+ * @return string
+ */
+ public function getShortName()
+ {
+ if (strlen($this->name) > parent::SHORT_NAME_LENGTH)
+ return substr($this->name, 0, parent::SHORT_NAME_LENGTH - 10) . '...' . substr($this->name, -7);
+ else
+ return $this->name;
+ }
+
+ /**
+ * Get name of the testfunction.
+ * @return string
+ */
+ public function getTestfunctionName()
+ {
+ return $this->testfunctionName;
+ }
+
+ /**
+ * Get short name of the testfunction.
+ * @return string
+ */
+ public function getTestfunctionShortName()
+ {
+ if (strlen($this->testfunctionName) > parent::SHORT_NAME_LENGTH)
+ return substr($this->testfunctionName, 0, parent::SHORT_NAME_LENGTH - 10) . '...' . substr($this->testfunctionName, -7);
+ else
+ return $this->testfunctionName;
+ }
+
+}
+
+?>
diff --git a/non-puppet/qtmetrics2/src/test/DatabaseTest.php b/non-puppet/qtmetrics2/src/test/DatabaseTest.php
index d5e4ad5..942cf38 100644
--- a/non-puppet/qtmetrics2/src/test/DatabaseTest.php
+++ b/non-puppet/qtmetrics2/src/test/DatabaseTest.php
@@ -38,7 +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
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -718,6 +718,46 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
}
/**
+ * Test getTestrowsBlacklistedPassedCountsTestset
+ * @dataProvider testGetTestrowsBlacklistedPassedCountsTestsetData
+ */
+ public function testGetTestrowsBlacklistedPassedCountsTestset($testset, $project, $runProject, $runState, $date, $exp_testrow, $exp_excluded_testrow, $exp_testrow_count_min, $exp_bpassed_min)
+ {
+ $testrows = array();
+ $bpassed = 0;
+ $db = Factory::db();
+ $result = $db->getTestrowsBlacklistedPassedCountsTestset($testset, $project, $runProject, $runState, $date);
+ foreach($result as $row) {
+ $this->assertArrayHasKey('name', $row);
+ $this->assertArrayHasKey('testset', $row);
+ $this->assertArrayHasKey('testfunction', $row);
+ $this->assertArrayHasKey('project', $row);
+ $this->assertArrayHasKey('conf', $row);
+ $this->assertArrayHasKey('bpassed', $row);
+ $this->assertArrayHasKey('btotal', $row);
+ $this->assertEquals($row['btotal'], $row['bpassed']);
+ $testrows[] = $row['name'];
+ $bpassed += $row['bpassed'];
+ }
+ $this->assertGreaterThanOrEqual($exp_testrow_count_min, count($testrows));
+ if ($exp_testrow_count_min > 0) {
+ $this->assertNotEmpty($result);
+ $this->assertContains($exp_testrow, $testrows);
+ $this->assertNotContains($exp_excluded_testrow, $testrows);
+ $this->assertGreaterThanOrEqual($exp_bpassed_min, $bpassed);
+ }
+ }
+ public function testGetTestrowsBlacklistedPassedCountsTestsetData()
+ {
+ return array(
+ array('tst_qfont', 'qtbase', 'Qt5', 'state', '2013-05-01', 'cursive', 'serif', 1, 1), // in test data cursive has bpassed and serif doesn't
+ array('tst_qftp', 'qtbase', 'Qt5', 'state', '2013-05-01', '', '', 0, 0),
+ array('tst_qfont', 'qtbase', 'Qt5', 'state', '2013-05-29', '', '', 0, 0),
+ array('tst_qfont', 'qtbase', 'Qt5', 'state', '2999-05-29', '', '', 0, 0)
+ );
+ }
+
+ /**
* Test getProjectBuildsByBranch
* @dataProvider testGetProjectBuildsByBranchData
*/
diff --git a/non-puppet/qtmetrics2/src/test/FactoryTest.php b/non-puppet/qtmetrics2/src/test/FactoryTest.php
index 96530f7..72271b2 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 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -314,6 +314,29 @@ class FactoryTest extends PHPUnit_Framework_TestCase
}
/**
+ * Test createTestrows
+ * @dataProvider testCreateTestrowsData
+ */
+ public function testCreateTestrows($testset, $project, $runProject, $runState)
+ {
+ $testrows = Factory::createTestrows($testset, $project, $runProject, $runState);
+ foreach($testrows as $testrow) {
+ $this->assertTrue($testrow instanceof Testrow);
+ $blacklisted = $testrow->getBlacklistedCounts();
+ $this->assertNotNull($blacklisted);
+ $this->assertArrayHasKey('bpassed', $blacklisted);
+ $this->assertArrayHasKey('btotal', $blacklisted);
+ }
+ }
+ public function testCreateTestrowsData()
+ {
+ return array(
+ array('tst_qfont', 'qtbase', 'Qt5', 'state'),
+ array('tst_qftp', 'qtbase', 'Qt5', 'state')
+ );
+ }
+
+ /**
* Test createProjectRuns
* @dataProvider testCreateProjectRunsData
*/
diff --git a/non-puppet/qtmetrics2/src/test/TestrowTest.php b/non-puppet/qtmetrics2/src/test/TestrowTest.php
new file mode 100644
index 0000000..f52c404
--- /dev/null
+++ b/non-puppet/qtmetrics2/src/test/TestrowTest.php
@@ -0,0 +1,156 @@
+<?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$
+##
+#############################################################################
+
+require_once(__DIR__.'/../Factory.php');
+
+/**
+ * Testrow unit test class
+ * @example To run (in qtmetrics root directory): php <path-to-phpunit>/phpunit.phar ./src/test
+ * @since 23-09-2015
+ * @author Juha Sippola
+ */
+
+class TestrowTest extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * Test getName, getShortName, getTestsetName, getTestsetProjectName, getConfName
+ * @dataProvider testGetNameData
+ */
+ public function testGetName($name, $shortName, $testfunction, $testset, $project, $conf)
+ {
+ $testrow = new Testrow($name, $testfunction, $testset, $project, $conf);
+ $this->assertEquals($name, $testrow->getName());
+ $this->assertEquals($shortName, $testrow->getShortName());
+ $this->assertEquals($testfunction, $testrow->getTestfunctionName());
+ $this->assertEquals($testset, $testrow->getTestsetName());
+ $this->assertEquals($project, $testrow->getTestsetProjectName());
+ $this->assertEquals($conf, $testrow->getConfName());
+ }
+ public function testGetNameData()
+ {
+ return array(
+ array(
+ 'cursive',
+ 'cursive',
+ 'defaultFamily',
+ 'tst_qfont',
+ 'QtBase',
+ 'macx-clang_developer-build_OSX_10.8'),
+ array(
+ 'my_testrow',
+ 'my_testrow',
+ 'my_testfunction',
+ 'my_testset',
+ 'my_project',
+ 'my_conf'),
+ array(
+ 'my_long_testrow_name_that_has_over_50_letters_in_it',
+ 'my_long_testrow_name_that_has_over_50_le...s_in_it',
+ 'my_testfunction',
+ 'my_testset',
+ 'my_project',
+ 'my_conf')
+ );
+ }
+
+ /**
+ * Test setResultCounts and getResultCounts
+ * @dataProvider testGetResultCountsData
+ */
+ public function testGetTestsetResultCounts($name, $testset, $project, $conf, $passed, $failed, $skipped)
+ {
+ $testfunction = new Testfunction($name, $testset, $project, $conf);
+ $this->assertTrue($testfunction instanceof Testfunction);
+ // Counts not set
+ $result = $testfunction->getResultCounts();
+ $this->assertArrayHasKey('passed', $result);
+ $this->assertArrayHasKey('failed', $result);
+ $this->assertArrayHasKey('skipped', $result);
+ $this->assertNull($result['passed']);
+ $this->assertNull($result['failed']);
+ $this->assertNull($result['skipped']);
+ // Counts set
+ $testfunction->setResultCounts($passed, $failed, $skipped);
+ $result = $testfunction->getResultCounts();
+ $this->assertArrayHasKey('passed', $result);
+ $this->assertArrayHasKey('failed', $result);
+ $this->assertArrayHasKey('skipped', $result);
+ $this->assertEquals($passed, $result['passed']);
+ $this->assertEquals($failed, $result['failed']);
+ $this->assertEquals($skipped, $result['skipped']);
+ }
+ public function testGetResultCountsData()
+ {
+ return array(
+ array('cleanupTestCase', 'tst_qftp', 'QtBase', 'macx-clang_developer-build_OSX_10.8', 1, 2, 3),
+ array('cleanupTestCase', 'tst_qftp', 'Qt5', 'macx-clang_developer-build_OSX_10.8', 123456, 654321, 111222),
+ array('my_testfunction', 'my_testfunction', 'my_project', 'my_conf', 7, 14, 7)
+ );
+ }
+
+ /**
+ * Test setBlacklistedCounts and getBlacklistedCounts
+ * @dataProvider testGetBlacklistedCountsData
+ */
+ public function testGetBlacklistedCounts($name, $testset, $project, $conf, $bpassed, $btotal)
+ {
+ $testfunction = new Testfunction($name, $testset, $project, $conf);
+ $this->assertTrue($testfunction instanceof Testfunction);
+ // Counts not set
+ $result = $testfunction->getBlacklistedCounts();
+ $this->assertArrayHasKey('bpassed', $result);
+ $this->assertArrayHasKey('btotal', $result);
+ $this->assertNull($result['bpassed']);
+ $this->assertNull($result['btotal']);
+ // Counts set
+ $testfunction->setBlacklistedCounts($bpassed, $btotal);
+ $result = $testfunction->getBlacklistedCounts();
+ $this->assertArrayHasKey('bpassed', $result);
+ $this->assertArrayHasKey('btotal', $result);
+ $this->assertEquals($bpassed, $result['bpassed']);
+ $this->assertEquals($btotal, $result['btotal']);
+ }
+ public function testGetBlacklistedCountsData()
+ {
+ return array(
+ array('cleanupTestCase', 'tst_qftp', 'QtBase', 'macx-clang_developer-build_OSX_10.8', 1, 2),
+ array('cleanupTestCase', 'tst_qftp', 'Qt5', 'macx-clang_developer-build_OSX_10.8', 123456, 654321),
+ array('my_testfunction', 'my_testfunction', 'my_project', 'my_conf', 7, 14)
+ );
+ }
+
+}
+
+?>
diff --git a/non-puppet/qtmetrics2/templates/about.html b/non-puppet/qtmetrics2/templates/about.html
index d1d72d5..044d95a 100644
--- a/non-puppet/qtmetrics2/templates/about.html
+++ b/non-puppet/qtmetrics2/templates/about.html
@@ -34,7 +34,7 @@
/**
* About window content
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -52,4 +52,4 @@ and the global Qt developer community are the target audience. For detailed desc
<p>See the <strong><a href="https://wiki.qt.io/Qt_Metrics_2_Backlog" target="_blank">backlog</a></strong>
for development items currently identified or in progress.</p>
-<p><small>Version 0.33 (22-Sep-2015)</small></p>
+<p><small>Version 0.34 (23-Sep-2015)</small></p>
diff --git a/non-puppet/qtmetrics2/templates/testfunction.html b/non-puppet/qtmetrics2/templates/testfunction.html
index 26017db..14d285b 100644
--- a/non-puppet/qtmetrics2/templates/testfunction.html
+++ b/non-puppet/qtmetrics2/templates/testfunction.html
@@ -34,7 +34,7 @@
/**
* Test function page (list of test rows)
- * @since 17-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -95,7 +95,8 @@
<li>results: <span class="glyphicon glyphicon-remove red"></span> = {{ constant('TestrowRun::RESULT_FAILURE') }},
<span class="glyphicon glyphicon-ok-sign red"></span> = {{ constant('TestrowRun::RESULT_SUCCESS_UNEXPECTED') }},
<span class="glyphicon glyphicon-remove-sign green"></span> = {{ constant('TestrowRun::RESULT_FAILURE_EXPECTED') }},
-<span class="glyphicon glyphicon-ban-circle gray"></span> = {{ constant('TestrowRun::RESULT_SKIP') }}</li>
+<span class="glyphicon glyphicon-ban-circle gray"></span> = {{ constant('TestrowRun::RESULT_SKIP') }},
+<span class="glyphicon glyphicon-ok green"></span> = {{ constant('TestrowRun::RESULT_SUCCESS') }} (blacklisted only)</li>
</ul>
</li>
<li>Details on the runs are available as tooltip on result icon</li>
@@ -109,7 +110,7 @@
<div class="panel panel-primary">
<div class="panel-heading">
-<h4 class="panel-title bold">Test Row Results in Branches <small>(failures and skipped only)</small></h4>
+<h4 class="panel-title bold">Test Row Results in Branches <small>(failures, skipped or blacklisted only)</small></h4>
</div>
</div>
@@ -233,7 +234,9 @@
{% if key > buildKeyIndexPrinted and not buildKeyFound %}
{% if buildKey == run.getBuildKey %}
{# Print result #}
-{% if run.getResult == constant('TestfunctionRun::RESULT_FAILURE') %}
+{% if run.getResult == constant('TestfunctionRun::RESULT_SUCCESS') %}
+{% set resultIcon = 'glyphicon glyphicon-ok green' %}
+{% elseif 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' %}
diff --git a/non-puppet/qtmetrics2/templates/testfunctions_bpass.html b/non-puppet/qtmetrics2/templates/testfunctions_bpass.html
index 91ed345..37f665c 100644
--- a/non-puppet/qtmetrics2/templates/testfunctions_bpass.html
+++ b/non-puppet/qtmetrics2/templates/testfunctions_bpass.html
@@ -34,7 +34,7 @@
/**
* Blacklisted passes (testfunctions) page
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -59,7 +59,7 @@
<h1 class="page-header">
<span id="testset">{{ testset }}</span>
<span id="project" class="hidden">{{ project }}</span>
-Test Function Blacklisted Passes
+Blacklisted Test Function Passes
<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>
@@ -100,6 +100,9 @@ and configuration. The testset link opens a page where the test functions are li
<div class="alert alert-warning" role="alert">
<span class="glyphicon glyphicon-time"></span> <strong>Please wait:</strong> Extracting the data will be ready in less than a minute!
</div>
+<div class="alert alert-info" role="alert">
+<span class="glyphicon glyphicon-info-sign"></span> <strong>Tip:</strong> You can quickly check both the blacklisted test function passes and test row passes under each testset.
+</div>
{% endif %}
</div> {# testfunctions_blacklisted_passed_data #}
diff --git a/non-puppet/qtmetrics2/templates/testfunctions_bpass_data.html b/non-puppet/qtmetrics2/templates/testfunctions_bpass_data.html
index 7fd55d7..3fb0123 100644
--- a/non-puppet/qtmetrics2/templates/testfunctions_bpass_data.html
+++ b/non-puppet/qtmetrics2/templates/testfunctions_bpass_data.html
@@ -33,8 +33,8 @@
#############################################################################
/**
- * Blacklisted passes (testfunctions) data
- * @since 22-09-2015
+ * Blacklisted passes (testfunctions or testrows) data
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -43,36 +43,41 @@
{# Failed/passed bar area size in px #}
{% set BAR_AREA = 120 %}
-{# testfunctions as Testfunction objects
+{# tests as Testfunction objects
/**
- * @var Testfunction[] testfunctions
+ * @var Testfunction[] tests
+ */
+#}
+{# tests as Testrow objects
+/**
+ * @var Testrow[] tests
*/
#}
{# Calculate max result count for the bar #}
{% set prevTestsetName = '' %}
{% set prevProjectName = '' %}
-{% set testfunctionCount = 0 %}
+{% set testCount = 0 %}
{% set maxCount = 1 %}
-{% for testfunction in testfunctions %}
-{% if (testfunction.getTestsetName == prevTestsetName) and (testfunction.getTestsetProjectName == prevProjectName) %}
-{% set testfunctionCount = testfunctionCount + 1 %}
+{% for test in tests %}
+{% if (test.getTestsetName == prevTestsetName) and (test.getTestsetProjectName == prevProjectName) %}
+{% set testCount = testCount + 1 %}
{% else %}
-{% if testfunctionCount > maxCount %}
-{% set maxCount = testfunctionCount %}
+{% if testCount > maxCount %}
+{% set maxCount = testCount %}
{% endif %}
-{% set testfunctionCount = 1 %}
+{% set testCount = 1 %}
{% endif %}
-{% set prevTestsetName = testfunction.getTestsetName %}
-{% set prevProjectName = testfunction.getTestsetProjectName %}
+{% set prevTestsetName = test.getTestsetName %}
+{% set prevProjectName = test.getTestsetProjectName %}
{% endfor %}
-{% if testfunctionCount > maxCount %}
-{% set maxCount = testfunctionCount %}
+{% if testCount > maxCount %}
+{% set maxCount = testCount %}
{% endif %}
{##### Summary #####}
-{% if testfunctionCount > 0 %}
+{% if testCount > 0 %}
<div class="panel panel-primary">
<div class="panel-heading">
@@ -94,28 +99,28 @@
{# Print testsets #}
{% set prevTestsetName = '' %}
{% set prevProjectName = '' %}
-{% set testfunctionCount = 0 %}
+{% set testCount = 0 %}
{% set bar = 0 %}
-{% for testfunction in testfunctions %}
+{% for test in tests %}
{# First row #}
{% if prevTestsetName == '' %}
<tr>
-<td>{{ testfunction.getTestsetName }}</td>
-<td>{{ testfunction.getTestsetProjectName }}</td>
-{% set testfunctionCount = 1 %}
+<td>{{ test.getTestsetName }}</td>
+<td>{{ test.getTestsetProjectName }}</td>
+{% set testCount = 1 %}
{# Same testset: Increase the counter #}
-{% elseif (testfunction.getTestsetName == prevTestsetName) and (testfunction.getTestsetProjectName == prevProjectName) %}
-{% set testfunctionCount = testfunctionCount + 1 %}
+{% elseif (test.getTestsetName == prevTestsetName) and (test.getTestsetProjectName == prevProjectName) %}
+{% set testCount = testCount + 1 %}
{# New testset: Print count for previous one and start new row #}
{% else %}
-{% set bar = ((BAR_AREA/maxCount) * testfunctionCount)|round(0, 'floor') %}
-{% if (testfunctionCount > 0) and (bar == 0) %}
+{% set bar = ((BAR_AREA/maxCount) * testCount)|round(0, 'floor') %}
+{% if (testCount > 0) and (bar == 0) %}
{% set bar = 1 %}
{% endif %}
-<td class="leftBorder center">{{ testfunctionCount }}</td>
+<td class="leftBorder center">{{ testCount }}</td>
<td class="center showInLargeDisplay">
<div>
<div class="floatLeft blueBackground" style="width: {{ bar }}px">&nbsp;</div>
@@ -123,21 +128,21 @@
</td>
</tr>
<tr>
-<td>{{ testfunction.getTestsetName }}</td>
-<td>{{ testfunction.getTestsetProjectName }}</td>
-{% set testfunctionCount = 1 %}
+<td>{{ test.getTestsetName }}</td>
+<td>{{ test.getTestsetProjectName }}</td>
+{% set testCount = 1 %}
{% endif %}
-{% set prevTestsetName = testfunction.getTestsetName %}
-{% set prevProjectName = testfunction.getTestsetProjectName %}
-{% endfor %}{# testfunction #}
+{% set prevTestsetName = test.getTestsetName %}
+{% set prevProjectName = test.getTestsetProjectName %}
+{% endfor %}{# test #}
{# Print count for last one #}
-{% if testfunctionCount > 0 %}
-{% set bar = ((BAR_AREA/maxCount) * testfunctionCount)|round(0, 'floor') %}
-{% if (testfunctionCount > 0) and (bar == 0) %}
+{% if testCount > 0 %}
+{% set bar = ((BAR_AREA/maxCount) * testCount)|round(0, 'floor') %}
+{% if (testCount > 0) and (bar == 0) %}
{% set bar = 1 %}
{% endif %}
-<td class="leftBorder center">{{ testfunctionCount }}</td>
+<td class="leftBorder center">{{ testCount }}</td>
<td class="center showInLargeDisplay">
<div>
<div class="floatLeft blueBackground" style="width: {{ bar }}px">&nbsp;</div>
@@ -152,7 +157,7 @@
</div> {# .panel-body #}
</div> {# .panel... #}
-{% endif %}{# testfunctionCount #}
+{% endif %}{# testCount #}
{##### List #####}
@@ -161,13 +166,16 @@
<h4 class="panel-title bold">Blacklisted Passes <small>(last {{ lastDays }} days since {{ sinceDate }})</small></h4>
</div>
-{% if testfunctionCount > 0 %}
+{% if testCount > 0 %}
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
+{% if list == 'rows' %}
+<th>test row</th>
+{% endif %}
<th>test function</th>
<th>testset</th>
<th class="showInLargeDisplay">project</th>
@@ -176,40 +184,56 @@
</thead>
<tbody>
-{# Print testfunctions #}
-{% for testfunction in testfunctions %}
+{# Print tests #}
+{% for test in tests %}
<tr>
-{# Testfunction name #}
-{% if testfunction.getName|length > constant('Testfunction::SHORT_NAME_LENGTH') %}
-<td><span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ testfunction.getName }}">{{ testfunction.getShortName }}</span></td>
-{% else %}
-<td>{{ testfunction.getName }}</td>
-{% endif %}
+{# Name #}
+{% if test.getName|length > constant('Testfunction::SHORT_NAME_LENGTH') %}
+<td><span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ test.getName }}">{{ test.getShortName }}</span></td>
+{% else %}
+<td>{{ test.getName }}</td>
+{% endif %}
+
+{# Testfunction name for a testrow (with a link to testfunction page) #}
+{% if list == 'rows' %}
+{% set link = testfunctionRoute ~ '/' ~ test.getTestfunctionName|url_encode ~ '/' ~ test.getTestsetName|url_encode ~ '/' ~ test.getTestsetProjectName|url_encode ~ '/' ~ test.getConfName|url_encode %}
+<td><a href="{{ link }}">
+{% if test.getTestfunctionName|length > constant('Testfunction::SHORT_NAME_LENGTH') %}
+<span class="clickOnTouch" data-toggle="tooltip" data-placement="top" title="{{ test.getTestfunctionName }}">{{ test.getTestfunctionShortName }}</span>
+{% else %}
+{{ test.getTestfunctionName }}
+{% endif %}
+</a></td>
+{% endif %}
-{# Testset name #}
-{% set link = testsetRoute ~ '/' ~ testfunction.getTestsetName|url_encode ~ '/' ~ testfunction.getTestsetProjectName|url_encode ~ '/' ~ testfunction.getConfName|url_encode %}
-<td><a href="{{ link }}">{{ testfunction.getTestsetName }}</a></td>
+{# Testset name (with a link to testset page for testfunctions list) #}
+{% if list == 'functions' %}
+{% set link = testsetRoute ~ '/' ~ test.getTestsetName|url_encode ~ '/' ~ test.getTestsetProjectName|url_encode ~ '/' ~ test.getConfName|url_encode %}
+<td><a href="{{ link }}">{{ test.getTestsetName }}</a></td>
+{% else %}
+<td>{{ test.getTestsetName }}</td>
+{% endif %}
{# Project name #}
-<td class="showInLargeDisplay">{{ testfunction.getTestsetProjectName }}</td>
+<td class="showInLargeDisplay">{{ test.getTestsetProjectName }}</td>
{# Conf name #}
-<td class="showInLargeDisplay">{{ testfunction.getConfName }}</td>
+<td class="showInLargeDisplay">{{ test.getConfName }}</td>
</tr>
-{% endfor %}{# testfunction #}
+{% endfor %}{# test #}
</tbody>
</table>
</div> {# .table-responsive #}
</div> {# .panel-body #}
-{% endif %}{# testfunctionCount #}
+{% endif %}{# testCount #}
</div> {# .panel... #}
-{% if testfunctionCount == 0 %}
+{% if testCount == 0 %}
<div class="alert alert-info" role="alert">
-The testset {{ testset }} ({{ project }}) either does not have any blacklisted test functions,
-or there are failed or skipped blacklisted test functions since {{ sinceDate }}!
+The testset {{ testset }} ({{ project }}) either does not have any blacklisted test {{ list }},
+or there are failed or skipped blacklisted test {{ list }} since {{ sinceDate }}!
</div>
-{% endif %}{# testfunctionCount #}
+{% endif %}{# testCount #}
diff --git a/non-puppet/qtmetrics2/templates/testrows_bpass.html b/non-puppet/qtmetrics2/templates/testrows_bpass.html
new file mode 100644
index 0000000..7dede8a
--- /dev/null
+++ b/non-puppet/qtmetrics2/templates/testrows_bpass.html
@@ -0,0 +1,111 @@
+{#
+#############################################################################
+##
+## 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$
+##
+#############################################################################
+
+/**
+ * Blacklisted passes (testrows) page
+ * @since 23-09-2015
+ * @author Juha Sippola
+ */
+
+#}
+
+{% include "header.html" %}
+
+<ol class="breadcrumb">
+{% for link in breadcrumb %}
+<li><a href="{{ link.link }}">{{ link.name }}</a></li>
+{% endfor %}
+<li class="active">blacklisted test row passes</li>
+</ol>
+
+<div class="container-fluid">
+<div class="row">
+
+<div class="col-sm-12 col-md-12 main">
+
+{##### Title #####}
+
+<h1 class="page-header">
+<span id="testset">{{ testset }}</span>
+<span id="project" class="hidden">{{ project }}</span>
+Blacklisted Test Row Passes
+<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>Test Row Blacklisted Passes</strong><br>
+<ul>
+<li>Lists the test rows in <strong>{{ masterProject }} {{ masterState }}</strong> builds where tagged
+as blacklisted but have not failed or skipped during the last {{ lastDays }} days.</li>
+<li>In these cases the blacklisted tag could maybe be removed in the CI so that the test row would be
+tested normally in the future builds.</li>
+<li><strong>Summary</strong> shows the count of test rows in each testset (any configuration or branch)
+with blacklisted passes</li>
+<li><strong>Blacklisted Passes</strong> shows the list of test rows with blacklisted passes by testset
+and configuration. The testset link opens a page where the test rows are listed by branch.</li>
+</ul>
+</div>
+</div>
+
+{##### List #####}
+
+<div id="testrows_blacklisted_passed_data">
+<div class="panel panel-primary">
+<div class="panel-heading">
+<h4 class="panel-title bold">Blacklisted Passes <small>(last {{ lastDays }} days since {{ sinceDate }})</small></h4>
+</div>
+</div>
+<div class="progress data_loading">
+<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
+</div>
+</div>
+</div> {# testrows_blacklisted_passed_data #}
+
+</div> {# .col... #}
+</div> {# .row #}
+</div> {# .container-fluid #}
+
+{% include "footer.html" %}
+
+{# Local scripts for this page #}
+<script src="scripts/ajax.js"></script>
+<script src="scripts/tooltip.js"></script>
+
+{% include "close.html" %}
diff --git a/non-puppet/qtmetrics2/templates/testset.html b/non-puppet/qtmetrics2/templates/testset.html
index 817e783..9fd4900 100644
--- a/non-puppet/qtmetrics2/templates/testset.html
+++ b/non-puppet/qtmetrics2/templates/testset.html
@@ -34,7 +34,7 @@
/**
* Testset page (list of configurations)
- * @since 22-09-2015
+ * @since 23-09-2015
* @author Juha Sippola
*/
@@ -124,7 +124,11 @@ and their configuration on <strong>{{ masterProject }} {{ masterState }}</strong
<div>
<div class="btn-group">
{% set link = bpassedTestsetRoute ~ '/' ~ testset.getName|url_encode ~ '/' ~ testset.getProjectName|url_encode %}
-<a class="btn btn-primary btn-xs" href="{{ link }}" role="button">test function blacklisted passes</a>
+<a class="btn btn-primary btn-xs" href="{{ link }}" role="button">blacklisted passes for<br>test functions</a>
+</div>
+<div class="btn-group">
+{% set link = bpassedtestsetTestrowsRoute ~ '/' ~ testset.getName|url_encode ~ '/' ~ testset.getProjectName|url_encode %}
+<a class="btn btn-primary btn-xs" href="{{ link }}" role="button">blacklisted passes for<br>test rows</a>
</div>
</div>
<hr>