* @file
*/
-/**
- * @uses Xhprof
- * @uses AutoLoader
- * @author Bryan Davis <bd808@wikimedia.org>
- * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
- * @since 1.25
- */
class XhprofTest extends PHPUnit_Framework_TestCase {
- public function setUp() {
- if ( !function_exists( 'xhprof_enable' ) ) {
- $this->markTestSkipped( 'No xhprof support detected.' );
- }
- }
-
- /**
- * @covers Xhprof::splitKey
- * @dataProvider provideSplitKey
- */
- public function testSplitKey( $key, $expect ) {
- $this->assertSame( $expect, Xhprof::splitKey( $key ) );
- }
-
- public function provideSplitKey() {
- return [
- [ 'main()', [ null, 'main()' ] ],
- [ 'foo==>bar', [ 'foo', 'bar' ] ],
- [ 'bar@1==>bar@2', [ 'bar@1', 'bar@2' ] ],
- [ 'foo==>bar==>baz', [ 'foo', 'bar==>baz' ] ],
- [ '==>bar', [ '', 'bar' ] ],
- [ '', [ null, '' ] ],
- ];
- }
+ use MediaWikiCoversValidator;
/**
- * @covers Xhprof::__construct
- * @covers Xhprof::stop
- * @covers Xhprof::getRawData
- * @dataProvider provideRawData
- */
- public function testRawData( $flags, $keys ) {
- $xhprof = new Xhprof( [ 'flags' => $flags ] );
- $raw = $xhprof->getRawData();
- $this->assertArrayHasKey( 'main()', $raw );
- foreach ( $keys as $key ) {
- $this->assertArrayHasKey( $key, $raw['main()'] );
- }
- }
-
- public function provideRawData() {
- $tests = [
- [ 0, [ 'ct', 'wt' ] ],
- ];
-
- if ( defined( 'XHPROF_FLAGS_CPU' ) && defined( 'XHPROF_FLAGS_CPU' ) ) {
- $tests[] = [ XHPROF_FLAGS_MEMORY, [
- 'ct', 'wt', 'mu', 'pmu',
- ] ];
- $tests[] = [ XHPROF_FLAGS_CPU, [
- 'ct', 'wt', 'cpu',
- ] ];
- $tests[] = [ XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU, [
- 'ct', 'wt', 'mu', 'pmu', 'cpu',
- ] ];
- }
-
- return $tests;
- }
-
- /**
- * @covers Xhprof::pruneData
- */
- public function testInclude() {
- $xhprof = $this->getXhprofFixture( [
- 'include' => [ 'main()' ],
- ] );
- $raw = $xhprof->getRawData();
- $this->assertArrayHasKey( 'main()', $raw );
- $this->assertArrayHasKey( 'main()==>foo', $raw );
- $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw );
- $this->assertSame( 3, count( $raw ) );
- }
-
- /**
- * Validate the structure of data returned by
- * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected
- * structural changes to the returned data in lieu of using a more heavy
- * weight typed response object.
+ * Trying to enable Xhprof when it is already enabled causes an exception
+ * to be thrown.
*
- * @covers Xhprof::getInclusiveMetrics
- */
- public function testInclusiveMetricsStructure() {
- $metricStruct = [
- 'ct' => 'int',
- 'wt' => 'array',
- 'cpu' => 'array',
- 'mu' => 'array',
- 'pmu' => 'array',
- ];
- $statStruct = [
- 'total' => 'numeric',
- 'min' => 'numeric',
- 'mean' => 'numeric',
- 'max' => 'numeric',
- 'variance' => 'numeric',
- 'percent' => 'numeric',
- ];
-
- $xhprof = $this->getXhprofFixture();
- $metrics = $xhprof->getInclusiveMetrics();
-
- foreach ( $metrics as $name => $metric ) {
- $this->assertArrayStructure( $metricStruct, $metric );
-
- foreach ( $metricStruct as $key => $type ) {
- if ( $type === 'array' ) {
- $this->assertArrayStructure( $statStruct, $metric[$key] );
- if ( $name === 'main()' ) {
- $this->assertEquals( 100, $metric[$key]['percent'] );
- }
- }
- }
- }
- }
-
- /**
- * Validate the structure of data returned by
- * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected
- * structural changes to the returned data in lieu of using a more heavy
- * weight typed response object.
- *
- * @covers Xhprof::getCompleteMetrics
- */
- public function testCompleteMetricsStructure() {
- $metricStruct = [
- 'ct' => 'int',
- 'wt' => 'array',
- 'cpu' => 'array',
- 'mu' => 'array',
- 'pmu' => 'array',
- 'calls' => 'array',
- 'subcalls' => 'array',
- ];
- $statsMetrics = [ 'wt', 'cpu', 'mu', 'pmu' ];
- $statStruct = [
- 'total' => 'numeric',
- 'min' => 'numeric',
- 'mean' => 'numeric',
- 'max' => 'numeric',
- 'variance' => 'numeric',
- 'percent' => 'numeric',
- 'exclusive' => 'numeric',
- ];
-
- $xhprof = $this->getXhprofFixture();
- $metrics = $xhprof->getCompleteMetrics();
-
- foreach ( $metrics as $name => $metric ) {
- $this->assertArrayStructure( $metricStruct, $metric, $name );
-
- foreach ( $metricStruct as $key => $type ) {
- if ( in_array( $key, $statsMetrics ) ) {
- $this->assertArrayStructure(
- $statStruct, $metric[$key], $key
- );
- $this->assertLessThanOrEqual(
- $metric[$key]['total'], $metric[$key]['exclusive']
- );
- }
- }
- }
- }
-
- /**
- * @covers Xhprof::getCallers
- * @covers Xhprof::getCallees
- * @uses Xhprof
- */
- public function testEdges() {
- $xhprof = $this->getXhprofFixture();
- $this->assertSame( [], $xhprof->getCallers( 'main()' ) );
- $this->assertSame( [ 'foo', 'xhprof_disable' ],
- $xhprof->getCallees( 'main()' )
- );
- $this->assertSame( [ 'main()' ],
- $xhprof->getCallers( 'foo' )
- );
- $this->assertSame( [], $xhprof->getCallees( 'strlen' ) );
- }
-
- /**
- * @covers Xhprof::getCriticalPath
- * @uses Xhprof
- */
- public function testCriticalPath() {
- $xhprof = $this->getXhprofFixture();
- $path = $xhprof->getCriticalPath();
-
- $last = null;
- foreach ( $path as $key => $value ) {
- list( $func, $call ) = Xhprof::splitKey( $key );
- $this->assertSame( $last, $func );
- $last = $call;
- }
- $this->assertSame( $last, 'bar@1' );
- }
-
- /**
- * Get an Xhprof instance that has been primed with a set of known testing
- * data. Tests for the Xhprof class should laregly be concerned with
- * evaluating the manipulations of the data collected by xhprof rather
- * than the data collection process itself.
- *
- * The returned Xhprof instance primed will be with a data set created by
- * running this trivial program using the PECL xhprof implementation:
- * @code
- * function bar( $x ) {
- * if ( $x > 0 ) {
- * bar($x - 1);
- * }
- * }
- * function foo() {
- * for ( $idx = 0; $idx < 2; $idx++ ) {
- * bar( $idx );
- * $x = strlen( 'abc' );
- * }
- * }
- * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY );
- * foo();
- * $x = xhprof_disable();
- * var_export( $x );
- * @endcode
- *
- * @return Xhprof
- */
- protected function getXhprofFixture( array $opts = [] ) {
- $xhprof = new Xhprof( $opts );
- $xhprof->loadRawData( [
- 'foo==>bar' => [
- 'ct' => 2,
- 'wt' => 57,
- 'cpu' => 92,
- 'mu' => 1896,
- 'pmu' => 0,
- ],
- 'foo==>strlen' => [
- 'ct' => 2,
- 'wt' => 21,
- 'cpu' => 141,
- 'mu' => 752,
- 'pmu' => 0,
- ],
- 'bar==>bar@1' => [
- 'ct' => 1,
- 'wt' => 18,
- 'cpu' => 19,
- 'mu' => 752,
- 'pmu' => 0,
- ],
- 'main()==>foo' => [
- 'ct' => 1,
- 'wt' => 304,
- 'cpu' => 307,
- 'mu' => 4008,
- 'pmu' => 0,
- ],
- 'main()==>xhprof_disable' => [
- 'ct' => 1,
- 'wt' => 8,
- 'cpu' => 10,
- 'mu' => 768,
- 'pmu' => 392,
- ],
- 'main()' => [
- 'ct' => 1,
- 'wt' => 353,
- 'cpu' => 351,
- 'mu' => 6112,
- 'pmu' => 1424,
- ],
- ] );
- return $xhprof;
- }
-
- /**
- * Assert that the given array has the described structure.
- *
- * @param array $struct Array of key => type mappings
- * @param array $actual Array to check
- * @param string $label
- */
- protected function assertArrayStructure( $struct, $actual, $label = null ) {
- $this->assertInternalType( 'array', $actual, $label );
- $this->assertCount( count( $struct ), $actual, $label );
- foreach ( $struct as $key => $type ) {
- $this->assertArrayHasKey( $key, $actual );
- $this->assertInternalType( $type, $actual[$key] );
- }
+ * @expectedException Exception
+ * @expectedExceptionMessage already enabled
+ * @covers Xhprof::enable
+ */
+ public function testEnable() {
+ $xhprof = new ReflectionClass( 'Xhprof' );
+ $enabled = $xhprof->getProperty( 'enabled' );
+ $enabled->setAccessible( true );
+ $enabled->setValue( true );
+ $xhprof->getMethod( 'enable' )->invoke( null );
}
}