1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
<?php
use MediaWiki\Logger\LogCapturingSpi;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\Logger\Spi;
use PHPUnit\Runner\AfterIncompleteTestHook;
use PHPUnit\Runner\AfterRiskyTestHook;
use PHPUnit\Runner\AfterSkippedTestHook;
use PHPUnit\Runner\AfterSuccessfulTestHook;
use PHPUnit\Runner\AfterTestErrorHook;
use PHPUnit\Runner\AfterTestFailureHook;
use PHPUnit\Runner\AfterTestHook;
use PHPUnit\Runner\AfterTestWarningHook;
use PHPUnit\Runner\BeforeTestHook;
/**
* Replaces the logging SPI on each test run. This allows another component
* (the printer) to fetch the logs when reporting why a test failed.
*
* Also logs test start and end messages to the original log.
*/
class MediaWikiLoggerPHPUnitExtension implements
BeforeTestHook,
AfterRiskyTestHook,
AfterIncompleteTestHook,
AfterSkippedTestHook,
AfterSuccessfulTestHook,
AfterTestErrorHook,
AfterTestWarningHook,
AfterTestFailureHook,
AfterTestHook
{
/**
* @var string[]
* @todo Can we avoid global state?
*/
public static $testsCollection;
/** @var Spi|null */
private $originalSpi;
/** @var Spi|null */
private $spi;
/**
* @inheritDoc
*/
public function executeBeforeTest( string $test ): void {
$this->originalSpi = LoggerFactory::getProvider();
$this->spi = new LogCapturingSpi( $this->originalSpi );
LoggerFactory::registerProvider( $this->spi );
$this->log( "Start test $test" );
}
/** @inheritDoc */
public function executeAfterRiskyTest( string $test, string $message, float $time ): void {
$this->augmentTestWithLogs( $test );
}
/** @inheritDoc */
public function executeAfterIncompleteTest( string $test, string $message, float $time ): void {
$this->augmentTestWithLogs( $test );
$this->log( "Incomplete test $test: $message" );
}
/** @inheritDoc */
public function executeAfterSkippedTest( string $test, string $message, float $time ): void {
$this->augmentTestWithLogs( $test );
$this->log( "Skipped test $test: $message" );
}
/** @inheritDoc */
public function executeAfterTestError( string $test, string $message, float $time ): void {
$this->augmentTestWithLogs( $test );
$this->log( "ERROR in test $test: $message" );
}
/** @inheritDoc */
public function executeAfterTestWarning( string $test, string $message, float $time ): void {
$this->log( "Warning in test $test: $message" );
$this->augmentTestWithLogs( $test );
}
/** @inheritDoc */
public function executeAfterTestFailure( string $test, string $message, float $time ): void {
$this->log( "FAILURE in test $test: $message" );
$this->augmentTestWithLogs( $test );
}
private function augmentTestWithLogs( string $test ) {
if ( $this->spi && getenv( 'PHPUNIT_LOGS' ) !== '0' ) {
$logs = $this->spi->getLogs();
$formatted = $this->formatLogs( $logs );
self::$testsCollection[$test] = $formatted;
}
}
/** @inheritDoc */
public function executeAfterSuccessfulTest( string $test, float $time ): void {
$this->log(
sprintf( "Successful test %s, completed in %.6f seconds",
$test, $time ) );
}
/** @inheritDoc */
public function executeAfterTest( string $test, float $time ): void {
LoggerFactory::registerProvider( $this->originalSpi );
$this->originalSpi = null;
$this->spi = null;
}
/**
* Get string formatted logs generated during the last
* test to execute.
*
* @param array $logs
* @return string
*/
private function formatLogs( array $logs ) {
$message = [];
foreach ( $logs as $log ) {
if ( $log['channel'] === 'PHPUnitCommand' ) {
// Don't print the log of PHPUnit events while running PHPUnit,
// because PHPUnit is already printing those already.
continue;
}
$message[] = sprintf(
'[%s] [%s] %s %s',
$log['channel'],
$log['level'],
$log['message'],
json_encode( $log['context'] )
);
}
return implode( "\n", $message );
}
private function log( $message ) {
$spi = $this->originalSpi ?: LoggerFactory::getProvider();
$logger = $spi->getLogger( 'PHPUnit' );
$logger->debug( $message );
}
}
|