From 420305143b7ed1dec09d0a272ec820f78cc1d2c1 Mon Sep 17 00:00:00 2001 From: Andrey Savchenko Date: Tue, 20 Feb 2018 18:09:44 +0200 Subject: [PATCH] Added generic stopwatch collector and tests. --- src/Provider/Record_Provider.php | 2 +- src/Record/Hook_Record_Collector.php | 53 ++++------------ src/Record/Http_Record_Collector.php | 33 ++-------- src/Record/Stopwatch_Record_Collector.php | 73 +++++++++++++++++++++++ tests/Record/HookTest.php | 46 ++++++++++++++ tests/Record/HttpTest.php | 28 +++++++++ tests/Record/StopwatchTest.php | 51 ++++++++++++++++ 7 files changed, 215 insertions(+), 71 deletions(-) create mode 100644 src/Record/Stopwatch_Record_Collector.php create mode 100644 tests/Record/HookTest.php create mode 100644 tests/Record/HttpTest.php create mode 100644 tests/Record/StopwatchTest.php diff --git a/src/Provider/Record_Provider.php b/src/Provider/Record_Provider.php index 7bb575c..83fcca5 100644 --- a/src/Provider/Record_Provider.php +++ b/src/Provider/Record_Provider.php @@ -27,7 +27,7 @@ class Record_Provider implements ServiceProviderInterface, Bootable_Provider_Int $pimple['collectors'] = function ( Plugin $laps ) { return [ - 'hook' => new Hook_Record_Collector( $laps['hook.events'], $laps['stopwatch'] ), + 'hook' => new Hook_Record_Collector( $laps['stopwatch'], $laps['hook.events'] ), 'http' => new Http_Record_Collector( $laps['stopwatch'] ), 'sql' => new Sql_Record_Collector(), ]; diff --git a/src/Record/Hook_Record_Collector.php b/src/Record/Hook_Record_Collector.php index ce42228..ee15bf5 100644 --- a/src/Record/Hook_Record_Collector.php +++ b/src/Record/Hook_Record_Collector.php @@ -4,34 +4,28 @@ namespace Rarst\Laps\Record; use Rarst\Laps\Event\Hook_Event_Config_Interface; use Symfony\Component\Stopwatch\Stopwatch; -use Symfony\Component\Stopwatch\StopwatchEvent; /** * Processes events based on hooked starts and stops. */ -class Hook_Record_Collector implements Record_Collector_Interface { +class Hook_Record_Collector extends Stopwatch_Record_Collector { - /** @var Hook_Event_Config_Interface[] $event_configs */ + /** @var Hook_Event_Config_Interface[] $event_configs */ protected $event_configs = []; - /** @var Stopwatch $stopwatch */ - protected $stopwatch; - /** @var array $events */ protected $events = []; /** - * @param array $event_configs Starts and stops configuration. * @param Stopwatch $stopwatch Stopwatch instance. + * @param array $event_configs Starts and stops configuration. */ - public function __construct( array $event_configs, Stopwatch $stopwatch ) { + public function __construct( Stopwatch $stopwatch, array $event_configs ) { - $this->stopwatch = $stopwatch; - - $this->stopwatch->start( 'Plugins Load', 'plugin' ); + parent::__construct( $stopwatch ); + $this->start( 'Plugins Load', 'plugin' ); $this->add_events( $event_configs['core']->get_events() ); - unset( $event_configs['core'] ); $this->event_configs = $event_configs; @@ -48,9 +42,7 @@ class Hook_Record_Collector implements Record_Collector_Interface { $this->events = array_merge( $this->events, $stops ); foreach ( $stops as $hook_name => $data ) { - foreach ( array_keys( $data ) as $priority ) { - add_action( $hook_name, [ $this, 'tick' ], $priority ); } } @@ -91,12 +83,12 @@ class Hook_Record_Collector implements Record_Collector_Interface { 'category' => null, ] ); - if ( 'stop' === $event['action'] && ! $this->stopwatch->isStarted( $event['event'] ) ) { - return $input; + if ( 'start' === $event['action'] ) { + $this->start( $event['event'], $event['category'] ); + } else { + $this->stop( $event['event'] ); } - $this->stopwatch->{$event['action']}( $event['event'], $event['category'] ); - return $input; } @@ -105,29 +97,8 @@ class Hook_Record_Collector implements Record_Collector_Interface { */ public function get_records() { - if ( $this->stopwatch->isStarted( 'Toolbar' ) ) { - $this->stopwatch->stop( 'Toolbar' ); - } + $this->stopwatch->stop( 'Toolbar' ); - $events = $this->stopwatch->getSectionEvents( '__root__' ); - - foreach ( array_keys( $events ) as $name ) { - if ( $this->stopwatch->isStarted( $name ) ) { - unset( $events[ $name ] ); - } - } - - return array_map( [ $this, 'transform' ], array_keys( $events ), $events ); - } - - /** - * @param string $name Event name. - * @param StopwatchEvent $event Stopwatch event instance. - * - * @return Stopwatch_Record - */ - protected function transform( $name, StopwatchEvent $event ) { - - return new Stopwatch_Record( $name, $event ); + return parent::get_records(); } } diff --git a/src/Record/Http_Record_Collector.php b/src/Record/Http_Record_Collector.php index c997e7f..d8c81b3 100644 --- a/src/Record/Http_Record_Collector.php +++ b/src/Record/Http_Record_Collector.php @@ -3,22 +3,18 @@ namespace Rarst\Laps\Record; use Symfony\Component\Stopwatch\Stopwatch; -use Symfony\Component\Stopwatch\StopwatchEvent; /** * Captures time of network requests made with HTTP API. */ -class Http_Record_Collector implements Record_Collector_Interface { - - /** @var Stopwatch $stopwatch */ - protected $stopwatch; +class Http_Record_Collector extends Stopwatch_Record_Collector { /** * @param Stopwatch $stopwatch Stopwatch instance. */ public function __construct( Stopwatch $stopwatch ) { - $this->stopwatch = $stopwatch; + parent::__construct( $stopwatch ); add_action( 'pre_http_request', [ $this, 'pre_http_request' ], 10, 3 ); add_action( 'http_api_debug', [ $this, 'http_api_debug' ], 10, 5 ); @@ -35,7 +31,7 @@ class Http_Record_Collector implements Record_Collector_Interface { */ public function pre_http_request( $false, $args, $url ) { - $this->stopwatch->start( $url, 'http' ); + $this->start( $url, 'http' ); return $false; } @@ -55,29 +51,8 @@ class Http_Record_Collector implements Record_Collector_Interface { */ public function http_api_debug( $response, $type, $class, $args, $url ) { - $this->stopwatch->stop( $url ); + $this->stop( $url ); return $response; } - - /** - * @return Stopwatch_Record[] - */ - public function get_records() { - - $events = $this->stopwatch->getSectionEvents( '__root__' ); - - return array_map( [ $this, 'transform' ], array_keys( $events ), $events ); - } - - /** - * @param string $name Event name. - * @param StopwatchEvent $event Stopwatch event instance. - * - * @return Stopwatch_Record - */ - protected function transform( $name, StopwatchEvent $event ) { - - return new Stopwatch_Record( $name, $event ); - } } diff --git a/src/Record/Stopwatch_Record_Collector.php b/src/Record/Stopwatch_Record_Collector.php new file mode 100644 index 0000000..94a6d75 --- /dev/null +++ b/src/Record/Stopwatch_Record_Collector.php @@ -0,0 +1,73 @@ +stopwatch = $stopwatch; + } + + /** + * @param string $name The event name. + * @param string $category The event category. + * + * @return StopwatchEvent + */ + public function start( $name, $category = null ) { + return $this->stopwatch->start( $name, $category ); + } + + /** + * @param string $name The event name. + * + * @return bool|StopwatchEvent + */ + public function stop( $name ) { + + if ( $this->stopwatch->isStarted( $name ) ) { + return $this->stopwatch->stop( $name ); + } + + return false; + } + + /** + * @return Stopwatch_Record[] + */ + public function get_records() { + + $events = $this->stopwatch->getSectionEvents( '__root__' ); + + foreach ( array_keys( $events ) as $name ) { + if ( $this->stopwatch->isStarted( $name ) ) { + unset( $events[ $name ] ); + } + } + + return array_map( [ $this, 'transform' ], array_keys( $events ), $events ); + } + + /** + * @param string $name Event name. + * @param StopwatchEvent $event Stopwatch event instance. + * + * @return Stopwatch_Record + */ + protected function transform( $name, StopwatchEvent $event ) { + + return new Stopwatch_Record( $name, $event ); + } +} diff --git a/tests/Record/HookTest.php b/tests/Record/HookTest.php new file mode 100644 index 0000000..0fa8d67 --- /dev/null +++ b/tests/Record/HookTest.php @@ -0,0 +1,46 @@ + new Core_Events() ] ); + + $this->assertTrue( $stopwatch->isStarted( 'Plugins Load' ) ); + $this->assertTrue( has_action( 'after_setup_theme', [ $collector, 'after_setup_theme' ] ) ); + + $collector->after_setup_theme(); + + Functions\expect( 'current_filter' )->once()->andReturn( 'plugins_loaded' ); + Functions\expect( 'wp_parse_args' )->once()->andReturnFirstArg(); + + global $wp_filter; + + $wp_hook = $this->getMockBuilder( 'WP_Hook' ) + ->allowMockingUnknownTypes() + ->setMethods( [ 'current_priority' ] ) + ->getMock(); + + $wp_hook->method( 'current_priority' )->willReturn( - 2 ); + + $wp_filter['plugins_loaded'] = $wp_hook; + + $collector->tick(); + + $this->assertFalse( $stopwatch->isStarted( 'Plugins Load' ) ); + + $stopwatch->start( 'Toolbar' ); + $collector->get_records(); + + $this->assertFalse( $stopwatch->isStarted( 'Toolbar' ) ); + } +} diff --git a/tests/Record/HttpTest.php b/tests/Record/HttpTest.php new file mode 100644 index 0000000..38e104a --- /dev/null +++ b/tests/Record/HttpTest.php @@ -0,0 +1,28 @@ +assertTrue( has_action( 'pre_http_request', [ $collector, 'pre_http_request' ] ) ); + $this->assertTrue( has_action( 'http_api_debug', [ $collector, 'http_api_debug' ] ) ); + + $collector->pre_http_request( false, [], $url ); + + $this->assertTrue( $stopwatch->isStarted( $url ) ); + + $collector->http_api_debug( [], '', new \stdClass(), [], $url ); + + $this->assertFalse( $stopwatch->isStarted( $url ) ); + } +} diff --git a/tests/Record/StopwatchTest.php b/tests/Record/StopwatchTest.php new file mode 100644 index 0000000..f37c1ba --- /dev/null +++ b/tests/Record/StopwatchTest.php @@ -0,0 +1,51 @@ +start( 'Event', 'info' ); + $collector->start( 'Not stopped', 'info' ); + $event = $collector->stop( 'Event' ); + + $this->assertFalse( $collector->stop( 'Not event' ) ); + + $records = $collector->get_records(); + + $this->assertInternalType( 'array', $records ); + $this->assertCount( 1, $records ); + $this->assertInstanceOf( Stopwatch_Record::class, $records[0] ); + + return $event; + } + + /** + * @depends testCollector + * @covers \Rarst\Laps\Record\Stopwatch_Record + * + * @param StopwatchEvent $event Event instance. + */ + public function testRecord( StopwatchEvent $event ) { + + $record = new Stopwatch_Record( 'Event', $event ); + + $this->assertEquals( 'Event', $record->get_name() ); + $this->assertEquals( 'info', $record->get_category() ); + $this->assertEquals( $event->getOrigin(), $record->get_origin() ); + $this->assertEquals( $event->getDuration(), $record->get_duration() ); + $this->assertContains( 'Event', $record->get_description() ); + } +}