logo       

[MediaWiki-CVS] SVN: [54066] trunk/extensions/CodeReview: msg#01444

mediawiki-cvs

Subject: [MediaWiki-CVS] SVN: [54066] trunk/extensions/CodeReview

http://www.mediawiki.org/wiki/Special:Code/MediaWiki/54066

Revision: 54066
Author: brion
Date: 2009-07-31 01:37:18 +0000 (Fri, 31 Jul 2009)

Log Message:
-----------
Server side for test run data integration into code review.

Parser tests on trunk can now upload test results to a wiki running CodeReview.
While the tests are running, the run data is marked as in progress and will
display a spinner in the test column on the revision view. After completion,
the result set is uploaded, and success/total counts are displayed, with nice
red digits if there's failures.

Failed tests are listed by name on the revision detail page. Currently details
such as the output diff are not included, but there's a blob field ready to
accept such.

The status and result updates are sent to the API, action=codetestupdate. Rather
than forcing the client side to figure out how to log in with an account, I'm
just protecting it with an HMAC which validates that the request is legit; a
shared secret should be configured on the client and server ends.

Probably not too efficient in the list view as it'll pull a query per rev to get
the counts... There's a summary of counts in code_test_run however there may be
multiple rows as this is extended past ParserTests to encompass other test
suites
yet to be developed.

Currently no UI for the test suite control data either; and we really need to
clean up how the UI handles branching; we should make interesting
branches/directories
easily selectable in the UI so we can follow just trunk, or just some branch, or
whatever.

Note that, for instance, it only really makes sense to run the parser tests on
trunk phase3,
not on unrelated stuff in other branches; it'll let you send data for other
versions, it
just will be confusing. ;)

Modified Paths:
--------------
trunk/extensions/CodeReview/CodeRepository.php
trunk/extensions/CodeReview/CodeReview.i18n.php
trunk/extensions/CodeReview/CodeReview.php
trunk/extensions/CodeReview/CodeRevision.php
trunk/extensions/CodeReview/CodeRevisionListView.php
trunk/extensions/CodeReview/CodeRevisionView.php
trunk/extensions/CodeReview/codereview.css
trunk/extensions/CodeReview/codereview.sql

Added Paths:
-----------
trunk/extensions/CodeReview/CodeTestResult.php
trunk/extensions/CodeReview/CodeTestRun.php
trunk/extensions/CodeReview/CodeTestSuite.php
trunk/extensions/CodeReview/api/ApiCodeTestUpload.php
trunk/extensions/CodeReview/archives/codereview-code_tests.sql

Modified: trunk/extensions/CodeReview/CodeRepository.php
===================================================================
--- trunk/extensions/CodeReview/CodeRepository.php 2009-07-31 01:19:00 UTC
(rev 54065)
+++ trunk/extensions/CodeReview/CodeRepository.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -170,6 +170,26 @@
throw new MWException( 'Failed to load expected
revision data' );
return CodeRevision::newFromRow( $this, $row );
}
+
+ /**
+ * Load test suite information
+ */
+ public function getTestSuite( $name ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $row = $dbr->selectRow( 'code_test_suite',
+ '*',
+ array(
+ 'ctsuite_repo_id' => $this->getId(),
+ 'ctsuite_name' => $name,
+ ),
+ __METHOD__
+ );
+ if( $row ) {
+ return CodeTestSuite::newFromRow( $this, $row );
+ } else {
+ return null;
+ }
+ }

/**
* @param int $rev Revision ID

Modified: trunk/extensions/CodeReview/CodeReview.i18n.php
===================================================================
--- trunk/extensions/CodeReview/CodeReview.i18n.php 2009-07-31 01:19:00 UTC
(rev 54065)
+++ trunk/extensions/CodeReview/CodeReview.i18n.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -28,6 +28,7 @@
'code-authors' => 'authors',
'code-status' => 'states',
'code-tags' => 'tags',
+ 'code-tests' => 'Test cases',
'code-authors-text' => 'Below is a list of repo authors in order of
recent commits.',
'code-author-haslink' => 'This author is linked to the wiki user $1',
'code-author-orphan' => 'This author has no link with a wiki account',
@@ -46,6 +47,7 @@
'code-field-status' => 'Status',
'code-field-timestamp' => 'Date',
'code-field-comments' => 'Notes',
+ 'code-field-tests' => 'Tests',
'code-field-path' => 'Path',
'code-field-text' => 'Note',
'code-field-select' => 'Select',

Modified: trunk/extensions/CodeReview/CodeReview.php
===================================================================
--- trunk/extensions/CodeReview/CodeReview.php 2009-07-31 01:19:00 UTC (rev
54065)
+++ trunk/extensions/CodeReview/CodeReview.php 2009-07-31 01:37:18 UTC (rev
54066)
@@ -40,6 +40,7 @@
$wgAutoloadClasses['ApiCodeUpdate'] = $dir . 'api/ApiCodeUpdate.php';
$wgAutoloadClasses['ApiCodeDiff'] = $dir . 'api/ApiCodeDiff.php';
$wgAutoloadClasses['ApiCodeComments'] = $dir . 'api/ApiCodeComments.php';
+$wgAutoloadClasses['ApiCodeTestUpload'] = $dir . 'api/ApiCodeTestUpload.php';

$wgAutoloadClasses['CodeDiffHighlighter'] = $dir . 'DiffHighlighter.php';
$wgAutoloadClasses['CodeRepository'] = $dir . 'CodeRepository.php';
@@ -66,6 +67,10 @@
$wgAutoloadClasses['CodeView'] = $dir . 'SpecialCode.php';
$wgAutoloadClasses['SpecialRepoAdmin'] = $dir . 'SpecialRepoAdmin.php';

+$wgAutoloadClasses['CodeTestSuite'] = $dir . 'CodeTestSuite.php';
+$wgAutoloadClasses['CodeTestRun'] = $dir . 'CodeTestRun.php';
+$wgAutoloadClasses['CodeTestResult'] = $dir . 'CodeTestResult.php';
+
$wgSpecialPages['Code'] = 'SpecialCode';
$wgSpecialPageGroups['Code'] = 'developer';
$wgSpecialPages['RepoAdmin'] = 'SpecialRepoAdmin';
@@ -73,6 +78,7 @@

$wgAPIModules['codeupdate'] = 'ApiCodeUpdate';
$wgAPIModules['codediff'] = 'ApiCodeDiff';
+$wgAPIModules['codetestupload'] = 'ApiCodeTestUpload';
$wgAPIListModules['codecomments'] = 'ApiCodeComments';

$wgExtensionMessagesFiles['CodeReview'] = $dir . 'CodeReview.i18n.php';
@@ -129,6 +135,10 @@
// What images can be used for client-side side-by-side comparisons?
$wgCodeReviewImgRegex = '/\.(png|jpg|jpeg|gif)$/i';

+// Set to a secret string for HMAC validation of test run data uploads.
+// Should match test runner's $wgParserTestRemote['secret'].
+$wgCodeReviewSharedSecret = false;
+
# Schema changes
$wgHooks['LoadExtensionSchemaUpdates'][] = 'efCodeReviewSchemaUpdates';

@@ -141,6 +151,7 @@
$wgExtNewIndexes[] = array( 'code_relations', 'repo_to_from',
"$base/archives/code_relations_index.sql" );
//$wgExtNewFields[] = array( 'code_rev',
"$base/archives/codereview-cr_status.sql" ); // FIXME FIXME this is a change to
options... don't know how
$wgExtNewTables[] = array( 'code_bugs',
"$base/archives/code_bugs.sql" );
+ $wgExtNewTables[] = array( 'code_test_suite',
"$base/archives/codereview-code_tests.sql" );
} elseif( $wgDBtype == 'postgres' ) {
// TODO
}

Modified: trunk/extensions/CodeReview/CodeRevision.php
===================================================================
--- trunk/extensions/CodeReview/CodeRevision.php 2009-07-31 01:19:00 UTC
(rev 54065)
+++ trunk/extensions/CodeReview/CodeRevision.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -578,6 +578,56 @@
public function isValidTag( $tag ) {
return ( $this->normalizeTag( $tag ) !== false );
}
+
+ public function getTestRuns() {
+ $dbr = wfGetDB( DB_SLAVE );
+ $result = $dbr->select(
+ array(
+ 'code_test_suite',
+ 'code_test_run',
+ ),
+ '*',
+ array(
+ 'ctsuite_repo_id' => $this->mRepoId,
+ 'ctsuite_id=ctrun_suite_id',
+ 'ctrun_rev_id' => $this->mId,
+ ),
+ __METHOD__ );
+ $runs = array();
+ foreach( $result as $row ) {
+ $suite = CodeTestSuite::newFromRow( $this->mRepo, $row
);
+ $runs[] = new CodeTestRun( $suite, $row );
+ }
+ return $runs;
+ }
+
+ public function getTestResults( $success = null ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $conds = array(
+ 'ctr_repo_id' => $this->mRepoId,
+ 'ctr_rev_id' => $this->mId,
+ 'ctr_case_id=ctc_id',
+ 'ctc_suite_id=cts_id' );
+ if( $success === true ) {
+ $conds['ctr_result'] = 1;
+ } elseif( $success === false ) {
+ $conds['ctr_result'] = 0;
+ }
+ $results = $dbr->select(
+ array(
+ 'code_test_result',
+ 'code_test_case',
+ 'code_test_suite',
+ ),
+ '*',
+ $conds,
+ __METHOD__ );
+ $out = array();
+ foreach( $results as $row ) {
+ $out[] = new CodeTestResult( $row );
+ }
+ return $out;
+ }

public function getPrevious() {
// hack!

Modified: trunk/extensions/CodeReview/CodeRevisionListView.php
===================================================================
--- trunk/extensions/CodeReview/CodeRevisionListView.php 2009-07-31
01:19:00 UTC (rev 54065)
+++ trunk/extensions/CodeReview/CodeRevisionListView.php 2009-07-31
01:37:18 UTC (rev 54066)
@@ -187,7 +187,7 @@
'options' => array( 'GROUP BY' => 'cp_rev_id',
'USE INDEX' => array( 'code_path' => 'cp_repo_id' ) ),
'join_conds' => array(
'code_rev' => array( 'INNER JOIN',
'cr_repo_id = cp_repo_id AND cr_id = cp_rev_id' ),
- 'code_comment' => array( 'LEFT JOIN',
'cc_repo_id = cp_repo_id AND cc_rev_id = cp_rev_id' )
+ 'code_comment' => array( 'LEFT JOIN',
'cc_repo_id = cp_repo_id AND cc_rev_id = cp_rev_id' ),
)
);
// No path; entire repo...
@@ -198,7 +198,7 @@
'conds' => array( 'cr_repo_id' =>
$this->mRepo->getId() ),
'options' => array( 'GROUP BY' => 'cr_id' ),
'join_conds' => array(
- 'code_comment' => array( 'LEFT JOIN',
'cc_repo_id = cr_repo_id AND cc_rev_id = cr_id' )
+ 'code_comment' => array( 'LEFT JOIN',
'cc_repo_id = cr_repo_id AND cc_rev_id = cr_id' ),
)
);
}
@@ -206,8 +206,15 @@
}

function getSelectFields() {
- return array( $this->getDefaultSort(), 'cr_status', 'COUNT(
DISTINCT cc_id ) AS comments',
- 'cr_path', 'cr_message', 'cr_author', 'cr_timestamp' );
+ return array( $this->getDefaultSort(),
+ 'cr_id',
+ 'cr_repo_id',
+ 'cr_status',
+ 'COUNT(DISTINCT cc_id) AS comments',
+ 'cr_path',
+ 'cr_message',
+ 'cr_author',
+ 'cr_timestamp' );
}

function getFieldNames() {
@@ -215,6 +222,7 @@
$this->getDefaultSort() => wfMsg( 'code-field-id' ),
'cr_status' => wfMsg( 'code-field-status' ),
'comments' => wfMsg( 'code-field-comments' ),
+ 'tests' => wfMsg( 'code-field-tests' ),
'cr_path' => wfMsg( 'code-field-path' ),
'cr_message' => wfMsg( 'code-field-message' ),
'cr_author' => wfMsg( 'code-field-author' ),
@@ -260,6 +268,40 @@
} else {
return intval( $value );
}
+ case 'tests':
+ // fixme -- this still isn't too efficient...
+ $rev = CodeRevision::newFromRow( $this->mRepo, $row );
+ $runs = $rev->getTestRuns();
+ if( empty( $runs ) ) {
+ return ' ';
+ } else {
+ $total = 0;
+ $success = 0;
+ $progress = false;
+ foreach( $runs as $run ) {
+ $total += $run->countTotal;
+ $success += $run->countSuccess;
+ if( $run->status == 'running' ) {
+ $progress = true;
+ }
+ }
+ if( $progress ) {
+ global $wgStylePath;
+ return Xml::element( 'img', array(
+ 'src' =>
"$wgStylePath/common/images/spinner.gif",
+ 'width' => 20,
+ 'height' => 20,
+ 'alt' => "...",
+ 'title' => "Tests in
progress...",
+ ));
+ }
+ if( $success == $total ) {
+ $class = 'mw-codereview-success';
+ } else {
+ $class = 'mw-codereview-fail';
+ }
+ return "<span
class='$class'><strong>$success</strong>/$total</span>";
+ }
case 'cr_path':
return Xml::openElement( 'div', array( 'title' =>
(string)$value ) ) .
$this->mView->mSkin->link(

Modified: trunk/extensions/CodeReview/CodeRevisionView.php
===================================================================
--- trunk/extensions/CodeReview/CodeRevisionView.php 2009-07-31 01:19:00 UTC
(rev 54065)
+++ trunk/extensions/CodeReview/CodeRevisionView.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -81,6 +81,12 @@
}

$html .= $this->formatMetaData( $fields );
+ # Show test case info
+ $tests = $this->formatTests();
+ if( $tests ) {
+ $html .= "<h2 id='code-tests'>" . wfMsgHtml(
'code-tests' ) .
+ "</h2>\n" . $tests;
+ }
# Output diff
if ( $this->mRev->isDiffable() ) {
$diffHtml = $this->formatDiff();
@@ -282,6 +288,42 @@
return $this->mSkin->link( $special, htmlspecialchars( $tag ) );
}

+ protected function formatTests() {
+ $runs = $this->mRev->getTestRuns();
+ $html = '';
+ if( count( $runs ) ) {
+ foreach( $runs as $run ) {
+ $html .= "<h3>" . htmlspecialchars(
$run->suite->name ) . "</h3>\n";
+ if( $run->status == 'complete' ) {
+ $total = $run->countTotal;
+ $success = $run->countSuccess;
+ $failed = $total - $success;
+ if( $failed ) {
+ $html .= "<p><span
class='mw-codereview-success'>$success</span> succeeded tests, " .
+ "<span
class='mw-codereview-fail'>$failed</span> failed tests:</p>";
+
+ $tests = $run->getResults(
false );
+ $html .= "<ul>\n";
+ foreach( $tests as $test ) {
+ $html .= "<li>" .
htmlspecialchars( $test->caseName ) . "</li>\n";
+ }
+ $html .= "</ul>\n";
+ } else {
+ $html .= "<p><span
class='mw-codereview-success'>$success</span> succeeded tests.</p>";
+
+ }
+ } elseif( $run->status == "running" ) {
+ $html .= "<p>Test cases are
running...</p>";
+ } elseif( $run->status == "abort" ) {
+ $html .= "<p>Test run aborted.</p>";
+ } else {
+ // Err, this shouldn't happen?
+ }
+ }
+ }
+ return $html;
+ }
+
protected function formatDiff() {
global $wgEnableAPI;


Added: trunk/extensions/CodeReview/CodeTestResult.php
===================================================================
--- trunk/extensions/CodeReview/CodeTestResult.php
(rev 0)
+++ trunk/extensions/CodeReview/CodeTestResult.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -0,0 +1,11 @@
+<?php
+
+class CodeTestResult {
+ function __construct( CodeTestRun $run, $row ) {
+ $this->run = $run;
+ $this->id = $row->ctresult_id;
+ $this->caseId = $row->ctresult_case_id;
+ $this->caseName = $row->ctcase_name;
+ $this->success = (bool)$row->ctresult_success;
+ }
+}


Property changes on: trunk/extensions/CodeReview/CodeTestResult.php
___________________________________________________________________
Added: svn:eol-style
+ native

Added: trunk/extensions/CodeReview/CodeTestRun.php
===================================================================
--- trunk/extensions/CodeReview/CodeTestRun.php (rev 0)
+++ trunk/extensions/CodeReview/CodeTestRun.php 2009-07-31 01:37:18 UTC (rev
54066)
@@ -0,0 +1,170 @@
+<?php
+
+class CodeTestRun {
+ public function __construct( CodeTestSuite $suite, $row ) {
+ if( is_object( $row ) ) {
+ $row = wfObjectToArray( $row );
+ }
+ $this->suite = $suite;
+ $this->id = intval( $row['ctrun_id'] );
+ $this->revId = intval( $row['ctrun_rev_id'] );
+ $this->status = $row['ctrun_status'];
+ $this->countTotal = $row['ctrun_count_total'];
+ $this->countSuccess = $row['ctrun_count_success'];
+
+ $this->mCaseMap = null; // Lazy-initialize...
+ }
+
+ public function getResults( $success=null ) {
+ $dbr = wfGetDB( DB_MASTER );
+ $conds = array(
+ 'ctresult_run_id' => $this->id,
+ 'ctresult_case_id=ctcase_id',
+ );
+ if( $success !== null ) {
+ $conds['ctresult_success'] = $success ? 1 : 0;
+ }
+
+ $result = $dbr->select(
+ array(
+ 'code_test_result',
+ 'code_test_case',
+ ),
+ '*',
+ $conds,
+ __METHOD__ );
+
+ $out = array();
+ foreach( $result as $row ) {
+ $out[] = new CodeTestResult( $this, $row );
+ }
+ return $out;
+ }
+
+ public static function newFromRevId( CodeTestSuite $suite, $revId ) {
+ $dbr = wfGetDB( DB_MASTER );
+ $row = $dbr->selectRow( 'code_test_run',
+ '*',
+ array(
+ 'ctrun_suite_id' => $suite->id,
+ 'ctrun_rev_id' => $revId,
+ ),
+ __METHOD__ );
+ if( $row ) {
+ return new CodeTestRun( $suite, $row );
+ } else {
+ return null;
+ }
+ }
+
+ public function setStatus( $status ) {
+ $this->status = $status;
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'code_test_run',
+ array(
+ 'ctrun_status' => $status,
+ ),
+ array(
+ 'ctrun_id' => $this->id,
+ ),
+ __METHOD__ );
+ }
+
+ public static function insertRun( CodeTestSuite $suite, $revId,
$status, $results=array() ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $countTotal = count( $results );
+ $countSucceeded = count( array_filter( $results ) );
+
+ $insertData = array(
+ 'ctrun_suite_id' => $suite->id,
+ 'ctrun_rev_id' => $revId,
+ 'ctrun_status' => $status,
+ 'ctrun_count_total' => $countTotal,
+ 'ctrun_count_success' => $countSucceeded,
+ );
+ $dbw->insert( 'code_test_run',
+ $insertData,
+ __METHOD__ );
+
+ $insertData['ctrun_id'] = $dbw->insertId();
+ $run = new CodeTestRun( $suite, $insertData );
+ if( $status == 'complete' && $results ) {
+ $run->insertData( $results );
+ }
+ return $run;
+ }
+
+ public function getCaseId( $caseName ) {
+ $this->loadCaseMap();
+ if( isset( $this->mCaseMap[$caseName] ) ) {
+ return $this->mCaseMap[$caseName];
+ } else {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->insert( 'code_test_case',
+ array(
+ 'ctcase_suite_id' => $this->id,
+ 'ctcase_name' => $caseName,
+ ),
+ __METHOD__ );
+ $id = intval( $dbw->insertId() );
+ $this->mCaseMap[$caseName] = $id;
+ return $id;
+ }
+ }
+
+ protected function loadCaseMap() {
+ if( is_null( $this->mCaseMap ) ) {
+ $this->mCaseMap = array();
+ $dbw = wfGetDB( DB_MASTER );
+ $result = $dbw->select( 'code_test_case',
+ array(
+ 'ctcase_id',
+ 'ctcase_name',
+ ),
+ array(
+ 'ctcase_suite_id' => $this->id,
+ ),
+ __METHOD__
+ );
+ foreach( $result as $row ) {
+ $this->mCaseMap[$row->ctcase_name] = intval(
$row->ctcase_id );
+ }
+ }
+ }
+
+ public function saveResults( $results ) {
+ $this->insertResults( $results );
+ $this->status = "complete";
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'code_test_run',
+ array(
+ 'ctrun_status' => $this->status,
+ 'ctrun_count_total' => $this->countTotal,
+ 'ctrun_count_success' => $this->countSuccess,
+ ),
+ array(
+ 'ctrun_id' => $this->id,
+ ),
+ __METHOD__ );
+ }
+
+ public function insertResults( $results ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $this->countTotal = 0;
+ $this->countSuccess = 0;
+ foreach( $results as $caseName => $result ) {
+ $this->countTotal++;
+ if( $result ) {
+ $this->countSuccess++;
+ }
+ $insertData[] = array(
+ 'ctresult_run_id' => $this->id,
+ 'ctresult_case_id' => $this->getCaseId(
$caseName ),
+ 'ctresult_success' => $result ? 1 : 0,
+ );
+ }
+ $dbw->insert( 'code_test_result', $insertData, __METHOD__ );
+ }
+}


Property changes on: trunk/extensions/CodeReview/CodeTestRun.php
___________________________________________________________________
Added: svn:eol-style
+ native

Added: trunk/extensions/CodeReview/CodeTestSuite.php
===================================================================
--- trunk/extensions/CodeReview/CodeTestSuite.php
(rev 0)
+++ trunk/extensions/CodeReview/CodeTestSuite.php 2009-07-31 01:37:18 UTC
(rev 54066)
@@ -0,0 +1,38 @@
+<?php
+
+class CodeTestSuite {
+ public static function newFromRow( CodeRepository $repo, $row ) {
+ $suite = new CodeTestSuite();
+ $suite->id = intval( $row->ctsuite_id );
+ $suite->repo = $repo;
+ $suite->repoId = $repo->getId();
+ $suite->branchPath = $row->ctsuite_branch_path;
+ $suite->name = $row->ctsuite_name;
+ $suite->desc = $row->ctsuite_desc;
+ return $suite;
+ }
+
+ function getRun( $revId ) {
+ return CodeTestRun::newFromRevId( $this, $revId );
+ }
+
+ function setStatus( $revId, $status ) {
+ $run = $this->getRun( $revId );
+ if( $run ) {
+ $run->setStatus( $status );
+ } else {
+ $run = CodeTestRun::insertRun( $this, $revId, $status );
+ }
+ return $run;
+ }
+
+ function saveResults( $revId, $results ) {
+ $run = $this->getRun( $revId );
+ if( $run ) {
+ $run->saveResults( $results );
+ } else {
+ $run = CodeTestRun::insertRun( $this, $revId,
"complete", $results );
+ }
+ return $run;
+ }
+}


Property changes on: trunk/extensions/CodeReview/CodeTestSuite.php
___________________________________________________________________
Added: svn:eol-style
+ native

Added: trunk/extensions/CodeReview/api/ApiCodeTestUpload.php
===================================================================
--- trunk/extensions/CodeReview/api/ApiCodeTestUpload.php
(rev 0)
+++ trunk/extensions/CodeReview/api/ApiCodeTestUpload.php 2009-07-31
01:37:18 UTC (rev 54066)
@@ -0,0 +1,119 @@
+<?php
+
+class ApiCodeTestUpload extends ApiBase {
+
+ public function execute() {
+ global $wgUser;
+ // Before doing anything at all, let's check permissions
+ if( !$wgUser->isAllowed('codereview-use') ) {
+ $this->dieUsage('You don\'t have permission to upload
test results', 'permissiondenied');
+ }
+ $params = $this->extractRequestParams();
+
+ $this->validateParams( $params );
+ $this->validateHmac( $params );
+
+ $repo = CodeRepository::newFromName( $params['repo'] );
+ if( !$repo ) {
+ $this->dieUsage( "Invalid repo ``{$params['repo']}''",
'invalidrepo' );
+ }
+
+ $suite = $repo->getTestSuite( $params['suite'] );
+ if( !$suite ) {
+ $this->dieUsage( "Invalid test suite
``{$params['suite']}''", 'invalidsuite' );
+ }
+
+ // Note that we might be testing a revision that hasn't gotten
slurped in yet,
+ // so we won't reject data for revisions we don't know about
yet.
+ $revId = intval( $params['rev'] );
+
+ $status = $params['status'];
+ if( $status == 'running' || $status == 'aborted' ) {
+ // Set the 'tests running' flag so we can mark it...
+ $suite->setStatus( $revId, $status );
+ } elseif( $status == 'complete' ) {
+ // Save data and mark running test as completed.
+ $results = json_decode( $params['results'], true );
+ if( !is_array( $results ) ) {
+ $this->dieUsage( "Invalid test result data",
'invalidresults' );
+ }
+ $suite->saveResults( $revId, $results );
+ }
+ }
+
+ protected function validateParams( $params ) {
+ $required = array( 'repo', 'suite', 'rev', 'status', 'hmac' );
+ if( isset( $params['status'] ) && $params['status'] ==
'complete' ) {
+ $required[] = 'results';
+ }
+ foreach( $required as $arg ) {
+ if ( !isset( $params[$arg] ) ) {
+ $this->dieUsageMsg( array( 'missingparam', $arg
) );
+ }
+ }
+ }
+
+ protected function validateHmac( $params ) {
+ global $wgCodeReviewSharedSecret;
+
+ // Generate a hash MAC to validate our credentials
+ $message = array(
+ $params['repo'],
+ $params['suite'],
+ $params['rev'],
+ $params['status'],
+ );
+ if( $params['status'] == "complete" ) {
+ $message[] = $params['results'];
+ }
+ $hmac = hash_hmac( "sha1", implode( "|", $message ),
$wgCodeReviewSharedSecret );
+ if( $hmac != $params['hmac'] ) {
+ $this->dieUsageMsg( array( 'invalidhmac',
$params['hmac'] ) );
+ }
+ }
+
+ public function mustBePosted() {
+ // Discourage casual browsing :)
+ return true;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'repo' => null,
+ 'suite' => null,
+ 'rev' => array(
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => 1
+ ),
+ 'status' => array(
+ ApiBase::PARAM_TYPE => array( 'running',
'complete', 'abort' ),
+ ),
+ 'hmac' => null,
+ 'results' => null,
+ );
+ }
+
+ public function getParamDescription() {
+ return array(
+ 'repo' => 'Name of repository to update',
+ 'suite' => 'Name of test suite to record run results
for',
+ 'rev' => 'Revision ID tests were run against',
+ 'status' => 'Status of test run',
+ 'hmac' => 'HMAC validation',
+ 'results' => 'JSON-encoded map of test names to success
results, for status "complete"',
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Upload CodeReview test run results from a test
runner.' );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiCodeUpdate.php 48928 2009-03-27
18:41:20Z catrope $';
+ }
+}


Property changes on: trunk/extensions/CodeReview/api/ApiCodeTestUpload.php
___________________________________________________________________
Added: svn:eol-style
+ native

Added: trunk/extensions/CodeReview/archives/codereview-code_tests.sql
===================================================================
--- trunk/extensions/CodeReview/archives/codereview-code_tests.sql
(rev 0)
+++ trunk/extensions/CodeReview/archives/codereview-code_tests.sql
2009-07-31 01:37:18 UTC (rev 54066)
@@ -0,0 +1,66 @@
+--
+-- Information on available test suites
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_suite;
+CREATE TABLE /*$wgDBprefix*/code_test_suite (
+ -- Unique ID per test suite
+ ctsuite_id int auto_increment not null,
+
+ -- Repository ID of the code base this applies to
+ ctsuite_repo_id int not null,
+
+ -- Which branch path this applies to, eg '/trunk/phase3'
+ ctsuite_branch_path varchar(255) not null,
+
+ -- Pleasantly user-readable name, eg "ParserTests"
+ ctsuite_name varchar(255) not null,
+
+ -- Description...
+ ctsuite_desc varchar(255) not null,
+
+ primary key ctsuite_id (ctsuite_id)
+) /*$wgDBtableOptions*/;
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_case;
+CREATE TABLE /*$wgDBprefix*/code_test_case (
+ ctcase_id int auto_increment not null,
+ ctcase_suite_id int not null,
+ ctcase_name varchar(255) not null,
+
+ primary key ctc_id (ctcase_id),
+ key (ctcase_suite_id, ctcase_id)
+) /*$wgDBtableOptions*/;
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_run;
+CREATE TABLE /*$wgDBprefix*/code_test_run (
+ ctrun_id int auto_increment not null,
+
+ ctrun_suite_id int not null,
+ ctrun_rev_id int not null,
+
+ ctrun_status enum ('running', 'complete', 'abort'),
+
+ ctrun_count_total int,
+ ctrun_count_success int,
+
+ primary key ctrun_id (ctrun_id),
+ key suite_rev (ctrun_suite_id, ctrun_rev_id)
+) /*$wgDBtableOptions*/;
+
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_result;
+CREATE TABLE /*$wgDBprefix*/code_test_result (
+ ctresult_id int auto_increment not null,
+
+ -- Which test run and case are we on?
+ ctresult_run_id int not null,
+ ctresult_case_id int not null,
+
+ -- Did we succeed or fail?
+ ctresult_success bool not null,
+
+ -- Optional HTML chunk data
+ ctresult_details blob,
+
+ primary key ctr_id (ctresult_id),
+ key run_id (ctresult_run_id, ctresult_id)
+) /*$wgDBtableOptions*/;


Property changes on:
trunk/extensions/CodeReview/archives/codereview-code_tests.sql
___________________________________________________________________
Added: svn:eol-style
+ native

Modified: trunk/extensions/CodeReview/codereview.css
===================================================================
--- trunk/extensions/CodeReview/codereview.css 2009-07-31 01:19:00 UTC (rev
54065)
+++ trunk/extensions/CodeReview/codereview.css 2009-07-31 01:37:18 UTC (rev
54066)
@@ -78,6 +78,13 @@
color: #666;
}

+.mw-codereview-success {
+ color: #1a2;
+}
+.mw-codereview-fail {
+ color: #d21;
+}
+
/* Diffs */
.mw-codereview-diff ins {
text-decoration: none;

Modified: trunk/extensions/CodeReview/codereview.sql
===================================================================
--- trunk/extensions/CodeReview/codereview.sql 2009-07-31 01:19:00 UTC (rev
54065)
+++ trunk/extensions/CodeReview/codereview.sql 2009-07-31 01:37:18 UTC (rev
54066)
@@ -65,7 +65,7 @@
cr_diff mediumblob NULL,
-- Text flags: gzip,utf-8,external
cr_flags tinyblob NOT NULL,
-
+
primary key (cr_repo_id, cr_id),
key (cr_repo_id, cr_timestamp),
key cr_repo_author (cr_repo_id, cr_author, cr_timestamp)
@@ -217,3 +217,70 @@
key cpc_repo_rev_time (cpc_repo_id, cpc_rev_id, cpc_timestamp),
key cpc_repo_time (cpc_repo_id, cpc_timestamp)
) /*$wgDBTableOptions*/;
+
+--
+-- Information on available test suites
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_suite;
+CREATE TABLE /*$wgDBprefix*/code_test_suite (
+ -- Unique ID per test suite
+ ctsuite_id int auto_increment not null,
+
+ -- Repository ID of the code base this applies to
+ ctsuite_repo_id int not null,
+
+ -- Which branch path this applies to, eg '/trunk/phase3'
+ ctsuite_branch_path varchar(255) not null,
+
+ -- Pleasantly user-readable name, eg "ParserTests"
+ ctsuite_name varchar(255) not null,
+
+ -- Description...
+ ctsuite_desc varchar(255) not null,
+
+ primary key ctsuite_id (ctsuite_id)
+) /*$wgDBtableOptions*/;
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_case;
+CREATE TABLE /*$wgDBprefix*/code_test_case (
+ ctcase_id int auto_increment not null,
+ ctcase_suite_id int not null,
+ ctcase_name varchar(255) not null,
+
+ primary key ctc_id (ctcase_id),
+ key (ctcase_suite_id, ctcase_id)
+) /*$wgDBtableOptions*/;
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_run;
+CREATE TABLE /*$wgDBprefix*/code_test_run (
+ ctrun_id int auto_increment not null,
+
+ ctrun_suite_id int not null,
+ ctrun_rev_id int not null,
+
+ ctrun_status enum ('running', 'complete', 'abort'),
+
+ ctrun_count_total int,
+ ctrun_count_success int,
+
+ primary key ctrun_id (ctrun_id),
+ key suite_rev (ctrun_suite_id, ctrun_rev_id)
+) /*$wgDBtableOptions*/;
+
+
+DROP TABLE IF EXISTS /*$wgDBprefix*/code_test_result;
+CREATE TABLE /*$wgDBprefix*/code_test_result (
+ ctresult_id int auto_increment not null,
+
+ -- Which test run and case are we on?
+ ctresult_run_id int not null,
+ ctresult_case_id int not null,
+
+ -- Did we succeed or fail?
+ ctresult_success bool not null,
+
+ -- Optional HTML chunk data
+ ctresult_details blob,
+
+ primary key ctr_id (ctresult_id),
+ key run_id (ctresult_run_id, ctresult_id)
+) /*$wgDBtableOptions*/;



_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@xxxxxxxxxxxxxxxxxxx
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | Mail Home | sitemap | FAQ | advertise