Repository: jkocik/laravel-profiler Branch: master Commit: cda42631f802 Files: 174 Total size: 292.3 KB Directory structure: gitextract_22nd0g50/ ├── .docker/ │ ├── etc/ │ │ └── php/ │ │ ├── entrypoint.sh │ │ ├── php-v1.ini │ │ └── php-v2.ini │ └── images/ │ └── php/ │ ├── .bashrc-v1 │ ├── .bashrc-v2 │ ├── Dockerfile-v1 │ └── Dockerfile-v2 ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── composer.json ├── config/ │ └── profiler.php ├── docker-compose.yml ├── phpunit-laravel-52.xml ├── phpunit-laravel-53.xml ├── phpunit-laravel-54.xml ├── phpunit-laravel-55.xml ├── phpunit-laravel-56.xml ├── phpunit-laravel-57.xml ├── phpunit-laravel-58.xml ├── phpunit-laravel-6.xml ├── phpunit-laravel-7.xml ├── phpunit-laravel-8.xml ├── src/ │ ├── BaseProfiler.php │ ├── Console/ │ │ ├── ClientCommand.php │ │ ├── ServerCommand.php │ │ └── StatusCommand.php │ ├── Contracts/ │ │ ├── DataProcessor.php │ │ ├── DataTracker.php │ │ ├── ExecutionContent.php │ │ ├── ExecutionData.php │ │ ├── ExecutionRequest.php │ │ ├── ExecutionResponse.php │ │ ├── ExecutionRoute.php │ │ ├── ExecutionServer.php │ │ ├── ExecutionSession.php │ │ ├── ExecutionWatcher.php │ │ ├── LaravelListener.php │ │ ├── Memory.php │ │ ├── Processor.php │ │ ├── Profiler.php │ │ ├── Timer.php │ │ └── Tracker.php │ ├── DisabledProfiler.php │ ├── Events/ │ │ ├── ExceptionHandling.php │ │ ├── ProfilerBound.php │ │ ├── ProfilerServerConnectionFailed.php │ │ ├── ProfilerServerConnectionSuccessful.php │ │ ├── ResetTrackers.php │ │ ├── Terminating.php │ │ └── Tracking.php │ ├── LaravelDataProcessor.php │ ├── LaravelDataTracker.php │ ├── LaravelExecution/ │ │ ├── ConsoleFinishedRequest.php │ │ ├── ConsoleFinishedResponse.php │ │ ├── ConsoleStartingRequest.php │ │ ├── ConsoleStartingResponse.php │ │ ├── ExceptionHandlerFromVersion7.php │ │ ├── ExceptionHandlerTillVersion6.php │ │ ├── HttpContent.php │ │ ├── HttpRequest.php │ │ ├── HttpResponse.php │ │ ├── HttpRoute.php │ │ ├── HttpServer.php │ │ ├── HttpSession.php │ │ ├── LaravelExecutionData.php │ │ ├── NullContent.php │ │ ├── NullRequest.php │ │ ├── NullResponse.php │ │ ├── NullRoute.php │ │ ├── NullServer.php │ │ └── NullSession.php │ ├── LaravelExecutionWatcher.php │ ├── LaravelListeners/ │ │ ├── AuthListener.php │ │ ├── ConsoleCommandFinishedListener.php │ │ ├── EventsListener.php │ │ ├── ExceptionListener.php │ │ ├── HttpRequestHandledListener.php │ │ ├── PerformanceListener.php │ │ ├── QueriesListener.php │ │ ├── RedisListener.php │ │ └── ViewsListener.php │ ├── LaravelProfiler.php │ ├── Processors/ │ │ ├── BroadcastingProcessor.php │ │ └── StatusCommandProcessor.php │ ├── ProfilerResolver.php │ ├── ServiceProvider.php │ ├── Services/ │ │ ├── ConfigService.php │ │ ├── ConsoleService.php │ │ ├── GeneratorService.php │ │ ├── LogService.php │ │ ├── ParamsService.php │ │ ├── Performance/ │ │ │ ├── MemoryService.php │ │ │ ├── NullTimerService.php │ │ │ ├── TimerException.php │ │ │ └── TimerService.php │ │ └── helpers.php │ └── Trackers/ │ ├── ApplicationTracker.php │ ├── AuthTracker.php │ ├── BaseTracker.php │ ├── BindingsTracker.php │ ├── ConfigTracker.php │ ├── ContentTracker.php │ ├── EventsTracker.php │ ├── ExceptionTracker.php │ ├── PathsTracker.php │ ├── PerformanceTracker.php │ ├── QueriesTracker.php │ ├── RedisTracker.php │ ├── RequestTracker.php │ ├── ResponseTracker.php │ ├── RouteTracker.php │ ├── ServerTracker.php │ ├── ServiceProvidersTracker.php │ ├── SessionTracker.php │ └── ViewsTracker.php └── tests/ ├── Feature/ │ ├── CommandsTest.php │ ├── LaravelConsoleExecutionTest.php │ ├── LaravelExecutionTest.php │ ├── LaravelHttpExecutionTest.php │ ├── LaravelNullExecutionTest.php │ ├── PerformanceTest.php │ ├── PerformanceTrackerTest.php │ ├── RegisterProfilerTest.php │ ├── RunningProfilerTest.php │ ├── TrackersResetTest.php │ └── TrackersTest.php ├── Support/ │ ├── Fixtures/ │ │ ├── DummyClassA.php │ │ ├── DummyClassB.php │ │ ├── DummyCommand.php │ │ ├── DummyContractA.php │ │ ├── DummyContractB.php │ │ ├── DummyController.php │ │ ├── DummyEventA.php │ │ ├── DummyEventB.php │ │ ├── DummyException.php │ │ ├── DummyFormRequest.php │ │ ├── PerformanceProcessor.php │ │ ├── ProcessorA.php │ │ ├── ProcessorB.php │ │ ├── TrackerA.php │ │ ├── TrackerB.php │ │ ├── dummy-view-a.blade.php │ │ └── dummy-view-b.blade.php │ ├── Framework.php │ ├── PHPMock.php │ └── TestListener.php ├── TestCase.php ├── Unit/ │ ├── LaravelExecution/ │ │ ├── ConsoleFinishedRequestTest.php │ │ ├── ConsoleStartingRequestTest.php │ │ └── ConsoleStartingResponseTest.php │ ├── Services/ │ │ ├── ConfigServiceTest.php │ │ ├── HelpersTest.php │ │ ├── ParamsServiceTest.php │ │ └── Performance/ │ │ └── TimerServiceTest.php │ └── Trackers/ │ ├── ApplicationTrackerTest.php │ ├── AuthTrackerTest.php │ ├── BindingsTrackerTest.php │ ├── ConfigTrackerTest.php │ ├── ContentTrackerTest.php │ ├── EventsTrackerTest.php │ ├── ExceptionTrackerTest.php │ ├── PathsTrackerTest.php │ ├── QueriesTrackerTest.php │ ├── RedisTrackerTest.php │ ├── RequestTrackerTest.php │ ├── ResponseTrackerTest.php │ ├── RouteTrackerTest.php │ ├── ServerTrackerTest.php │ ├── ServiceProvidersTrackerTest.php │ ├── SessionTrackerTest.php │ └── ViewsTrackerTest.php └── bootstrap/ └── phpunit.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .docker/etc/php/entrypoint.sh ================================================ #!/bin/sh redis-server --daemonize yes setfacl -dR -m u:www-data:rwX /var/www/html setfacl -R -m u:www-data:rwX /var/www/html docker-php-entrypoint $@ ================================================ FILE: .docker/etc/php/php-v1.ini ================================================ memory_limit = 256M max_execution_time = 600 ================================================ FILE: .docker/etc/php/php-v2.ini ================================================ memory_limit = 256M max_execution_time = 600 xdebug.mode=coverage ================================================ FILE: .docker/images/php/.bashrc-v1 ================================================ alias la52='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-52.xml' alias la53='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-53.xml' alias la54='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-54.xml' alias la55='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-55.xml' alias la56='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-56.xml' alias la57='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-57.xml' alias la58='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-58.xml' alias la6='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-6.xml' alias la7='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-7.xml' alias phpunit-all='la7 && la6 && la58 && la57 && la56 && la55 && la54 && la53 && la52' alias phpunit-c='la7 --coverage-html coverage' ================================================ FILE: .docker/images/php/.bashrc-v2 ================================================ alias la6='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-6.xml' alias la7='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-7.xml' alias la8='vendor/bin/phpunit --stop-on-failure -c phpunit-laravel-8.xml' alias la-all='la8 && la7 && la6' alias la-c='la8 --coverage-html coverage' ================================================ FILE: .docker/images/php/Dockerfile-v1 ================================================ FROM php:7.3.10-fpm COPY ./.bashrc-v1 /root/.bashrc RUN apt-get update > /dev/null && apt-get install -y \ acl \ unzip \ libzip-dev \ zlib1g-dev \ libpng-dev \ libjpeg-dev \ nodejs \ redis-server RUN docker-php-ext-install zip pdo_mysql bcmath gd > /dev/null RUN pecl install xdebug > /dev/null \ && docker-php-ext-enable xdebug > /dev/null RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer > /dev/null RUN rm -rf /var/lib/apt/lists/* ================================================ FILE: .docker/images/php/Dockerfile-v2 ================================================ FROM php:8.0.6-fpm COPY ./.bashrc-v2 /root/.bashrc RUN apt-get update > /dev/null && apt-get install -y \ acl \ unzip \ libzip-dev \ zlib1g-dev \ libpng-dev \ libjpeg-dev \ nodejs \ redis-server RUN docker-php-ext-install zip pdo_mysql bcmath gd > /dev/null RUN pecl install xdebug > /dev/null \ && docker-php-ext-enable xdebug > /dev/null RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer > /dev/null RUN rm -rf /var/lib/apt/lists/* ================================================ FILE: .gitignore ================================================ /client /coverage /frameworks /vendor .phpunit.result.cache composer.lock ================================================ FILE: .travis.yml ================================================ language: php php: - 7.3.24 - 7.4.0 - 8.0 services: - redis-server before_script: - composer install --no-interaction script: - vendor/bin/phpunit -c phpunit-laravel-6.xml --coverage-clover build/logs/clover.xml - vendor/bin/phpunit -c phpunit-laravel-7.xml - vendor/bin/phpunit -c phpunit-laravel-8.xml after_success: - travis_retry php vendor/bin/php-coveralls -v ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) Janusz Kocik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## Laravel Profiler [![Build Status](https://travis-ci.org/jkocik/laravel-profiler.svg?branch=master)](https://travis-ci.org/jkocik/laravel-profiler) [![Coverage Status](https://coveralls.io/repos/github/jkocik/laravel-profiler/badge.svg?branch=master)](https://coveralls.io/github/jkocik/laravel-profiler?branch=master) The aim of this project is to track console and web Laravel framework execution and give developers better understanding what is going on under the hood. Laravel Profiler is designed for Laravel Framework. ![Laravel Profiler](https://drive.google.com/uc?export=view&id=12TSAEW1butnLfmFxO3Pw4GhF96B8PUSk) ### Supported versions | Laravel Framework version you have | Laravel Profiler version you should use | | ---------------------------------- | --------------------------------------- | | 5.2.x - 5.8.x | 1.x | | 6.x - 8.x | 2.x | ### How does it work? Profiler delivers data about Laravel framework execution: - when **tests are run** (PHPUnit, Laravel Dusk) - when Laravel is executed via **console** (artisan) - when Laravel is executed via **browser request** - when Laravel is executed via web request not expecting HTML response (**API**) - on any other **action that terminates** Laravel framework. Profiler does not add any routes to your application and does not modify the content of the response. Profiler is divided into 3 parts: - Profiler Package - PHP package for Laravel (this repository) - Profiler Client - Single Page Application to review data delivered by Profiler Package - Profiler Server - bridge between Profiler Package and Profiler Client. Profiler Client and Profiler Server both live in [laravel-profiler-client](https://github.com/jkocik/laravel-profiler-client) repository #### Data flow Profiler Package tracks Laravel execution and sends collected data to Profiler Server using HTTP. Profiler Server passes data to Profiler Client using WebSockets. #### Trackers Data tracked, collected and delivered to Profiler Client are: - auth - redis - route - views - events - session - exceptions - server status - database queries - performance metrics - request (web) / input (console) - response (web) / output (console) - application (Laravel status, config, loaded service providers, container bindings, framework paths) Profiler and its trackers do their job after request / artisan command is finished. That keeps your framework execution time and peak of memory usage as close to real values (without Profiler impact) as possible. ## Installation and configuration ### Step 1: Install Profiler Package Requirements: PHP 7.2+ It is recommended to install Profiler Package only for development ```shell composer require jkocik/laravel-profiler --dev ``` ### Step 2: Publish configuration file Run command ```shell php artisan vendor:publish --provider="JKocik\Laravel\Profiler\ServiceProvider" ``` ... and check config/profiler.php file for Profiler settings. ### Step 3: Install Profiler Server and Profiler Client It is recommended to install Profiler Server and Profiler Client only for development ```shell npm install laravel-profiler-client --save-dev ``` ### Step 4: Run Profiler Server and Profiler Client _Windows users: If you have any issue with running Profiler Server or Profiler Client check Installation options / issues section below._ Run command ```shell php artisan profiler:server ``` and a) for your local machine ```shell php artisan profiler:client ``` After that your browser should have new tab opened with Profiler Client connected to Profiler Server. b) for Docker, Vagrant or any other machine different from local ```shell php artisan profiler:client -m ``` ... and open new browser tab according to instructions in console. Remember that you need to connect Profiler Client to Profiler Server yourself because by default Profiler Client uses localhost. You can do that in Profiler Client interface. ### Step 5: Verify installation Run command ```shell php artisan profiler:status ``` ... to check Profiler status and see first data of Laravel execution in Profiler Client. ### Installation options / issues a) If you have any issue with running Profiler Server or Profiler Client use npm scripts instead of artisan commands. Add new scripts to your package.json file ```json "scripts": { "profiler-server": "node node_modules/laravel-profiler-client/server/server.js http=8099 ws=1901", "profiler-client": "http-server node_modules/laravel-profiler-client/dist/ -o -s", "ps": "npm run profiler-server", "pc": "npm run profiler-client" } ``` ... then run Profiler Server ```shell npm run ps ``` ... and Profiler Client ```shell npm run pc ``` b) If you don't want to open new browser tab every time you run Profiler Client command use manual option ```shell php artisan profiler:client -m ``` c) If default ports used by Profiler are taken on your machine configure them in config/profiler.php file. ### Done! You are ready to use Laravel Profiler. Enjoy! ### Usage #### Performance metrics Profiler delivers basic performance metrics including peak of memory usage and Laravel execution time. You can extend metrics by using Profiler helper functions: ```php profiler_start('my time metric name'); // my code to track execution time profiler_finish('my time metric name'); ``` Then check results in Profiler Client (Performance > Custom tab). You should keep unique metric names otherwise duplicates will be skipped and reported as an error (in a way according to your exception handling settings in config/profiler.php file). _Important notice: remove Profiler helper functions from your code before moving to production or any environment without Profiler installed._ #### Laravel Profiler for testing environment When testing Profiler will deliver the same data as for regular request / artisan command. However application should be terminated. Lets see two default tests Laravel is shipped with: ```php public function testBasicTest() { $response = $this->get('/'); $response->assertStatus(200); } ``` First test will terminate application and Profiler will work as expected. However second test ```php public function testBasicTest() { $this->assertTrue(true); } ``` ... will not provide any data because this time application is not terminated. You can force Profiler to work by adding terminate method: ```php public function testBasicTest() { $this->assertTrue(true); $this->app->terminate(); } ``` If you want to reset Profiler trackers you can use Profiler helper: ```php public function testBasicTest() { factory(User::class)->create(); profiler_reset(); // act and assert } ``` _Important notice related to testing environment: peak of memory usage can not be tracked for each test separately so is not shown in Profiler Client._ #### Using together with Laravel Debugbar It is not recommended using Laravel Profiler and Laravel Debugbar together. Profiler will finish its work after Debugbar and Profiler report of framework execution time and peak of memory usage will be increased by Debugbar activity. Use Profiler or Debugbar one at a time. ================================================ FILE: composer.json ================================================ { "name": "jkocik/laravel-profiler", "description": "Profiler for Laravel Framework", "keywords": ["laravel", "profiler", "debugbar"], "homepage": "https://github.com/jkocik/laravel-profiler", "license": "MIT", "authors": [ { "name": "Janusz Kocik", "email": "janusz.kocik@gmail.com" } ], "require": { "php": ">=7.2", "guzzlehttp/guzzle": "^5.0 || ^6.0 || ^7.0" }, "require-dev": { "mockery/mockery": "^1.0", "php-mock/php-mock": "^2.0", "php-coveralls/php-coveralls": "^2.1", "predis/predis": "^1.1", "fzaninotto/faker": "^1.5", "phpunit/phpunit": "^8" }, "autoload": { "psr-4": { "JKocik\\Laravel\\Profiler\\": "src/" }, "files": [ "src/Services/helpers.php" ] }, "autoload-dev": { "psr-4": { "JKocik\\Laravel\\Profiler\\Tests\\": "tests/" } }, "extra": { "laravel": { "providers": [ "JKocik\\Laravel\\Profiler\\ServiceProvider" ] } } } ================================================ FILE: config/profiler.php ================================================ env('PROFILER_ENABLED', true), /* |-------------------------------------------------------------------------- | Override general Laravel Profiler enable / disable setting |-------------------------------------------------------------------------- | | Can disable Profiler on particular env. Profiler is disabled by default | on production (be aware that installation on production is not recommended). | Setting takes effect only if above (enabled) is set to true. | */ 'enabled_overrides' => [ 'production' => false, // 'testing' => false, // 'local' => false, ], /* |-------------------------------------------------------------------------- | Profiler trackers |-------------------------------------------------------------------------- | | Trackers collect data of framework execution. You can decide what data | you want to collect by commenting / uncommenting particular trackers. | */ 'trackers' => [ \JKocik\Laravel\Profiler\Trackers\ConfigTracker::class, // App > Config tab \JKocik\Laravel\Profiler\Trackers\ServiceProvidersTracker::class, // App > Service Providers tab \JKocik\Laravel\Profiler\Trackers\BindingsTracker::class, // App > Bindings tab \JKocik\Laravel\Profiler\Trackers\PathsTracker::class, // App > Paths tab \JKocik\Laravel\Profiler\Trackers\SessionTracker::class, // Request > Session tab \JKocik\Laravel\Profiler\Trackers\RouteTracker::class, // Request > Route tab \JKocik\Laravel\Profiler\Trackers\ServerTracker::class, // Request > Server tab \JKocik\Laravel\Profiler\Trackers\ContentTracker::class, // Response > Content and JSON tabs \JKocik\Laravel\Profiler\Trackers\ViewsTracker::class, // Views tab \JKocik\Laravel\Profiler\Trackers\EventsTracker::class, // Events tab \JKocik\Laravel\Profiler\Trackers\QueriesTracker::class, // Queries tab // \JKocik\Laravel\Profiler\Trackers\RedisTracker::class, // Redis tab (from Laravel 5.7) \JKocik\Laravel\Profiler\Trackers\AuthTracker::class, // Auth tab \JKocik\Laravel\Profiler\Trackers\ExceptionTracker::class, // Exception tab ], /* |-------------------------------------------------------------------------- | Profiler Server and Profiler Client connections |-------------------------------------------------------------------------- | | These settings let you set up connections between Profiler Package | (this Laravel package) and Profiler Server using HTTP protocol | and finally pass data from Profiler Server to Profiler Client | (Single Page Application accessible via browser) using WebSockets. | */ 'server_http' => [ 'address' => 'http://localhost', 'port' => '8099', ], 'server_sockets' => [ 'port' => '1901', ], /* |-------------------------------------------------------------------------- | Profiler processors |-------------------------------------------------------------------------- | | Processors process data collected by trackers. Default processor | broadcasts data through Profiler Server to Profiler Client. | */ 'processors' => [ \JKocik\Laravel\Profiler\Processors\BroadcastingProcessor::class, ], 'turn_off_processors_for_paths' => [ 'telescope', '_debugbar', ], /* |-------------------------------------------------------------------------- | Data passed to tracked items |-------------------------------------------------------------------------- | | That can be very heavy when your views or events receive a lot of data. | Avoid using it on testing env specially when running whole test suite. | */ 'data' => [ 'views' => false, 'events' => false, ], /* |-------------------------------------------------------------------------- | Grouping |-------------------------------------------------------------------------- | | There can be a lot of the same events fired one by one. Grouping can | help you review them on better organized list of events. | */ 'group' => [ 'events' => true, ], /* |-------------------------------------------------------------------------- | Handle exceptions |-------------------------------------------------------------------------- | | Profiler processors and helper functions can throw exceptions. | They are logged by default to let you know about current issues | like problems with connection to Profiler Server. | | Handle exceptions settings are [int]: | 0 - catch exceptions and do not report them | 1 - catch exceptions and report them in logs | 666 - do not catch exceptions, let them be thrown | */ 'handle_exceptions' => 1, ]; ================================================ FILE: docker-compose.yml ================================================ version: '3.5' services: profiler_v1: build: dockerfile: Dockerfile-v1 context: ./.docker/images/php container_name: profiler_v1 hostname: profiler_v1 entrypoint: sh /bin/entrypoint.sh php-fpm volumes: - ./.docker/etc/php/entrypoint.sh:/bin/entrypoint.sh:ro - ./.docker/etc/php/php-v1.ini:/usr/local/etc/php/php.ini - .:/var/www/html profiler_v2: build: dockerfile: Dockerfile-v2 context: ./.docker/images/php container_name: profiler_v2 hostname: profiler_v2 entrypoint: sh /bin/entrypoint.sh php-fpm volumes: - ./.docker/etc/php/entrypoint.sh:/bin/entrypoint.sh:ro - ./.docker/etc/php/php-v2.ini:/usr/local/etc/php/php.ini - .:/var/www/html ================================================ FILE: phpunit-laravel-52.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-53.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-54.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-55.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-56.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-57.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-58.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-6.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ./src/LaravelExecution/ExceptionHandlerFromVersion7.php ================================================ FILE: phpunit-laravel-7.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: phpunit-laravel-8.xml ================================================ ./tests/Feature ./tests/Unit ./src/ ================================================ FILE: src/BaseProfiler.php ================================================ app = $app; } /** * @return void */ public function resetTrackers(): void { event(new ResetTrackers()); } /** * @return void */ public function listenForBoot(): void { $this->app->beforeBootstrapping(BootProviders::class, function () { $this->commands(); $this->boot(); }); } /** * @return void */ abstract protected function boot(): void; /** * @return void */ private function commands(): void { Event::listen(ArtisanStarting::class, function (ArtisanStarting $event) { $event->artisan->resolveCommands([ StatusCommand::class, ServerCommand::class, ClientCommand::class, ]); }); } } ================================================ FILE: src/Console/ClientCommand.php ================================================ consoleService = $consoleService; } /** * @return void */ public function handle(): void { $this->line('Starting Profiler Client ...'); passthru($this->consoleService->profilerClientCmd($this->option('manual'))); } } ================================================ FILE: src/Console/ServerCommand.php ================================================ consoleService = $consoleService; } /** * @return void */ public function handle(): void { $this->line('Starting Profiler Server ...'); passthru($this->consoleService->profilerServerCmd()); } } ================================================ FILE: src/Console/StatusCommand.php ================================================ configService = $configService; $this->consoleService = $consoleService; } /** * @return void */ public function handle(): void { $this->configService->overrideProcessors([ StatusCommandProcessor::class, ]); $this->printProfilerStatus(); if (! $this->configService->isProfilerEnabled()) { return; } $this->printTrackersStatus(); $this->printConnectionStatus(); } /** * @return void */ protected function printProfilerStatus(): void { $this->line("1) {$this->consoleService->envInfo()}"); $this->info($this->consoleService->profilerStatusInfo()); } /** * @return void */ protected function printTrackersStatus(): void { $this->line(''); $this->line("2) {$this->consoleService->trackersStatusInfo()}"); $this->configService->trackers()->each(function ($tracker) { $this->info("- {$tracker}"); }); $this->comment($this->consoleService->trackersCommentLine1()); $this->comment($this->consoleService->trackersCommentLine2()); } /** * @return void */ protected function printConnectionStatus(): void { $this->line(''); $this->line("3) {$this->consoleService->connectionStatusInfo()}"); Event::listen(ProfilerServerConnectionSuccessful::class, function (ProfilerServerConnectionSuccessful $event) { $this->info($this->consoleService->connectionSuccessfulInfo()); $this->info($this->consoleService->connectionSuccessfulSocketsInfo($event->socketsPort)); $this->info($this->consoleService->connectionSuccessfulClientsInfo($event->countClients)); $this->connectionStatusIsUnknown = false; }); Event::listen(ProfilerServerConnectionFailed::class, function () { $this->error($this->error($this->consoleService->connectionFailedInfo())); $this->connectionStatusIsUnknown = false; }); app()->terminating(function () { if (! $this->connectionStatusIsUnknown) { return; } $this->error($this->consoleService->connectionStatusUnknownInfo()); }); } } ================================================ FILE: src/Contracts/DataProcessor.php ================================================ bind(); } /** * @return void */ protected function bind(): void { $this->app->singleton(Timer::class, function ($app) { return $app->make(NullTimerService::class); }); event(ProfilerBound::class); } } ================================================ FILE: src/Events/ExceptionHandling.php ================================================ exception = $exception; } } ================================================ FILE: src/Events/ProfilerBound.php ================================================ socketsPort = $socketsPort; $this->countClients = $countClients; } } ================================================ FILE: src/Events/ResetTrackers.php ================================================ app = $app; $this->logService = $logService; $this->configService = $configService; } /** * @param DataTracker $dataTracker * @return void */ public function process(DataTracker $dataTracker): void { if ($this->shouldNotProcess($dataTracker)) { return; } $this->configService->processors()->each(function (string $processor) use ($dataTracker) { try { $this->make($processor)->process($dataTracker); } catch (Exception $e) { $this->logService->error($e); } }); } /** * @param string $processor * @return Processor */ protected function make(string $processor): Processor { return $this->app->make($processor); } /** * @param DataTracker $dataTracker * @return bool */ protected function shouldNotProcess(DataTracker $dataTracker): bool { if (! $dataTracker->meta()->has('path')) { return false; } return $this->configService->pathsToTurnOffProcessors()->map(function ($path) use ($dataTracker) { return stripos($dataTracker->meta()->get('path'), $path) !== false; })->contains(true); } } ================================================ FILE: src/LaravelDataTracker.php ================================================ app = $app; $this->configService = $configService; $this->trackers = new Collection(); $this->meta = new Collection(); $this->data = new Collection(); } /** * @return void */ public function track(): void { $this->bootTrackers(Collection::make([ ApplicationTracker::class, PerformanceTracker::class, RequestTracker::class, ResponseTracker::class, ])); $this->bootTrackers($this->configService->trackers()); } /** * @return void */ public function terminate(): void { $this->trackers->each(function (Tracker $tracker) { $tracker->terminate(); $this->meta = $this->meta->merge($tracker->meta()); $this->data = $this->data->merge($tracker->data()); }); } /** * @return Collection */ public function meta(): Collection { return $this->meta; } /** * @return Collection */ public function data(): Collection { return $this->data; } /** * @param Collection $trackers * @return void */ protected function bootTrackers(Collection $trackers): void { $trackers->each(function (string $tracker) { $this->trackers->push($this->app->make($tracker)); }); } } ================================================ FILE: src/LaravelExecution/ConsoleFinishedRequest.php ================================================ command = $command; $this->input = $input; } /** * @return Collection */ public function meta(): Collection { return Collection::make([ 'type' => 'command-finished', 'path' => $this->command, ]); } /** * @return Collection */ public function data(): Collection { return Collection::make([ 'arguments' => $this->input->getArguments(), 'options' => $this->input->getOptions(), ]); } } ================================================ FILE: src/LaravelExecution/ConsoleFinishedResponse.php ================================================ exitCode = $exitCode; } /** * @return Collection */ public function meta(): Collection { return Collection::make([ 'status' => $this->exitCode, ]); } /** * @return Collection */ public function data(): Collection { return Collection::make(); } } ================================================ FILE: src/LaravelExecution/ConsoleStartingRequest.php ================================================ 'command-starting', ]); } /** * @return Collection */ public function data(): Collection { return Collection::make(); } } ================================================ FILE: src/LaravelExecution/ConsoleStartingResponse.php ================================================ null, ]); } /** * @return Collection */ public function data(): Collection { return Collection::make(); } } ================================================ FILE: src/LaravelExecution/ExceptionHandlerFromVersion7.php ================================================ response = $response; } /** * @return Collection */ public function meta(): Collection { return Collection::make(); } /** * @return Collection */ public function data(): Collection { return Collection::make([ 'content' => $this->response->getContent(), ]); } } ================================================ FILE: src/LaravelExecution/HttpRequest.php ================================================ request = $request; } /** * @return Collection */ public function meta(): Collection { return Collection::make([ 'type' => 'http', 'method' => $this->request->method(), 'path' => $this->request->path(), 'ajax' => $this->request->ajax(), 'json' => $this->request->isJson(), ]); } /** * @return Collection */ public function data(): Collection { return Collection::make([ 'pjax' => $this->request->pjax(), 'url' => $this->request->url(), 'query' => $this->request->query(), 'ip' => $this->request->ip(), 'header' => $this->request->header(), 'input' => $this->request->input(), 'files' => $this->files(), 'cookie' => $this->request->cookie(), ]); } /** * @return Collection */ protected function files(): Collection { $files = Collection::make($this->request->allFiles()); return $this->filesMap($files); } /** * @param Collection $files * @return Collection */ protected function filesMap(Collection $files): Collection { return $files->map(function ($file) { if (is_array($file)) { $files = Collection::make($file); return $this->filesMap($files); } return [get_class($file) => $this->file($file)]; }); } /** * @param UploadedFile $file * @return array */ protected function file(UploadedFile $file): array { return [ 'client original name' => $file->getClientOriginalName(), 'client original extension' => $file->getClientOriginalExtension(), 'client mime type' => $file->getClientMimeType(), 'client size' => $this->clientSize($file), 'path' => $file->path(), ]; } /** * @param UploadedFile $file * @return int */ protected function clientSize(UploadedFile $file): int { return method_exists($file, 'getClientSize') ? $file->getClientSize() : $file->getSize(); } } ================================================ FILE: src/LaravelExecution/HttpResponse.php ================================================ response = $response; } /** * @return Collection */ public function meta(): Collection { return Collection::make([ 'status' => $this->response->getStatusCode(), 'status_text' => $this->getStatusText(), ]); } /** * @return Collection */ public function data(): Collection { return Collection::make([ 'headers' => $this->response->headers->all(), ]); } /** * @return string */ protected function getStatusText(): string { return $this->response::$statusTexts[$this->response->getStatusCode()] ?? 'unknown status'; } } ================================================ FILE: src/LaravelExecution/HttpRoute.php ================================================ route = $route; } /** * @return Collection */ public function meta(): Collection { return Collection::make(); } /** * @return Collection */ public function data(): Collection { return Collection::make([ 'methods' => $this->route->methods(), 'uri' => $this->route->uri(), 'name' => $this->route->getName(), 'middleware' => $this->route->middleware(), 'parameters' => $this->route->parameters(), 'prefix' => $this->route->getPrefix(), 'uses' => $this->uses(), ]); } /** * @return array */ protected function uses(): array { $uses = $this->route->getAction(); try { if ($this->isClosureIn($uses)) { return $this->closure($uses); } if ($this->isControllerIn($uses)) { return $this->controller($uses); } } catch (ReflectionException $e) {} return []; } /** * @param array $uses * @return bool */ protected function isClosureIn(array $uses): bool { return isset($uses['uses']) && $uses['uses'] instanceof Closure; } /** * @param array $uses * @return array */ protected function closure(array $uses): array { $action = new ReflectionFunction($uses['uses']); return [ 'closure' => $action->getFileName() . ':' . $action->getStartLine() . '-' . $action->getEndLine(), 'form_request' => $this->formRequest($action->getParameters()), ]; } /** * @param array $uses * @return bool */ protected function isControllerIn(array $uses): bool { return isset($uses['uses']) && count(explode('@', $uses['uses'])) == 2; } /** * @param array $uses * @return array */ protected function controller(array $uses): array { list($controller, $method) = explode('@', $uses['uses']); $action = new ReflectionMethod($controller, $method); return [ 'controller' => $uses['uses'] . ':' . $action->getStartLine() . '-' . $action->getEndLine(), 'form_request' => $this->formRequest($action->getParameters()), ]; } /** * @param array $parameters * @return string */ protected function formRequest(array $parameters): string { $formRequest = Collection::make($parameters)->filter(function (ReflectionParameter $parameter) { return $parameter->getType() && is_subclass_of($parameter->getType()->getName(), FormRequest::class); })->first(); return $formRequest ? $formRequest->getType()->getName() : ''; } } ================================================ FILE: src/LaravelExecution/HttpServer.php ================================================ request = $request; } /** * @return Collection */ public function meta(): Collection { return Collection::make(); } /** * @return Collection */ public function data(): Collection { return Collection::make( $this->request->server() ); } } ================================================ FILE: src/LaravelExecution/HttpSession.php ================================================ session = $session; } /** * @return Collection */ public function meta(): Collection { return Collection::make(); } /** * @return Collection */ public function data(): Collection { return Collection::make($this->session->all()); } } ================================================ FILE: src/LaravelExecution/LaravelExecutionData.php ================================================ setRequest(new NullRequest()); $this->setRoute(new NullRoute()); $this->setSession(new NullSession()); $this->setServer(new NullServer()); $this->setResponse(new NullResponse()); $this->setContent(new NullContent()); } /** * @param ExecutionRequest $request * @return void */ public function setRequest(ExecutionRequest $request): void { $this->request = $request; } /** * @return ExecutionRequest */ public function request(): ExecutionRequest { return $this->request; } /** * @param ExecutionRoute $route * @return void */ public function setRoute(ExecutionRoute $route): void { $this->route = $route; } /** * @return ExecutionRoute */ public function route(): ExecutionRoute { return $this->route; } /** * @param ExecutionSession $session * @return void */ public function setSession(ExecutionSession $session): void { $this->session = $session; } /** * @return ExecutionSession */ public function session(): ExecutionSession { return $this->session; } /** * @param ExecutionServer $server * @return void */ public function setServer(ExecutionServer $server): void { $this->server = $server; } /** * @return ExecutionServer */ public function server(): ExecutionServer { return $this->server; } /** * @param ExecutionResponse $response * @return void */ public function setResponse(ExecutionResponse $response): void { $this->response = $response; } /** * @return ExecutionResponse */ public function response(): ExecutionResponse { return $this->response; } /** * @param ExecutionContent $content * @return void */ public function setContent(ExecutionContent $content): void { $this->content = $content; } /** * @return ExecutionContent */ public function content(): ExecutionContent { return $this->content; } } ================================================ FILE: src/LaravelExecution/NullContent.php ================================================ null, ]); } /** * @return Collection */ public function data(): Collection { return Collection::make(); } } ================================================ FILE: src/LaravelExecution/NullResponse.php ================================================ httpRequestHandledListener = $httpRequestHandledListener; $this->consoleCommandFinishedListener = $consoleCommandFinishedListener; } /** * @return void */ public function watch(): void { $this->httpRequestHandledListener->listen(); $this->consoleCommandFinishedListener->listen(); } } ================================================ FILE: src/LaravelListeners/AuthListener.php ================================================ user = $logout->user; }); } /** * @return User|null */ public function user(): ?Model { return $this->user ?? Auth::user(); } } ================================================ FILE: src/LaravelListeners/ConsoleCommandFinishedListener.php ================================================ executionData = $executionData; } /** * @return void */ public function listen(): void { Event::listen(\Illuminate\Console\Events\ArtisanStarting::class, function ($event) { $this->executionData->setRequest(new ConsoleStartingRequest()); $this->executionData->setResponse(new ConsoleStartingResponse()); }); Event::listen(\Illuminate\Console\Events\CommandFinished::class, function ($event) { $this->executionData->setRequest(new ConsoleFinishedRequest($event->command, $event->input)); $this->executionData->setResponse(new ConsoleFinishedResponse($event->exitCode)); }); } } ================================================ FILE: src/LaravelListeners/EventsListener.php ================================================ dispatcher = $dispatcher; $this->configService = $configService; } /** * @return void */ public function listen(): void { $this->listenEvents(); $this->listenResetTrackers(); } /** * @return Collection */ public function events(): Collection { return Collection::make($this->events); } /** * @return int */ public function count(): int { return $this->count; } /** * @return void */ protected function listenEvents(): void { $this->dispatcher->listen('*', function ($event, $payload = null) { $name = $this->resolveName($event, $payload); if ($this->shouldSkip($name)) { return; } $this->count++; if ($this->shouldGroup($name)) { return $this->groupToPreviousEvent(); } $this->previousEventName = $name; array_push($this->events, $this->resolveEvent($name, $event, $payload)); }); } /** * @return void */ protected function listenResetTrackers(): void { $this->dispatcher->listen(ResetTrackers::class, function () { $this->events = []; $this->previousEventName = ''; $this->count = 0; }); } /** * @param string $name * @param $event * @param $payload * @return array */ protected function resolveEvent(string $name, $event, $payload): array { if ($this->configService->isEventsDataEnabled()) { return [$event, $payload, $name, 1]; } return [null, null, $name, 1]; } /** * @param $event * @param $payload * @return string */ protected function resolveName($event, $payload): string { return is_array($payload) ? $event : $this->dispatcher->firing(); } /** * @param string $name * @return bool */ protected function shouldGroup(string $name): bool { return $this->configService->isEventsGroupEnabled() && $name == $this->previousEventName; } /** * @return void */ protected function groupToPreviousEvent(): void { $this->events[count($this->events) - 1][3]++; } /** * @param string $name * @return bool */ protected function shouldSkip(string $name): bool { $shouldSkip = Collection::make([ 'bootstrapped: ' . \Illuminate\Foundation\Bootstrap\BootProviders::class, \JKocik\Laravel\Profiler\Events\ExceptionHandling::class, \JKocik\Laravel\Profiler\Events\ProfilerBound::class, \JKocik\Laravel\Profiler\Events\ResetTrackers::class, \JKocik\Laravel\Profiler\Events\Terminating::class, \JKocik\Laravel\Profiler\Events\Tracking::class, ]); return $shouldSkip->contains($name); } } ================================================ FILE: src/LaravelListeners/ExceptionListener.php ================================================ exception = $exceptionHandling->exception; }); } public function exception(): ?Throwable { return $this->exception; } } ================================================ FILE: src/LaravelListeners/HttpRequestHandledListener.php ================================================ executionData = $executionData; } /** * @return void */ public function listen(): void { /** @codeCoverageIgnoreStart */ Event::listen('kernel.handled', function (Request $request, Response $response) { $this->executionData->setRequest(new HttpRequest($request)); $this->executionData->setRoute($this->routeOf($request)); $this->executionData->setSession(new HttpSession(session())); $this->executionData->setServer(new HttpServer($request)); $this->executionData->setResponse(new HttpResponse($response)); $this->executionData->setContent(new HttpContent($response)); }); /** @codeCoverageIgnoreEnd */ Event::listen(\Illuminate\Foundation\Http\Events\RequestHandled::class, function ($event) { $this->executionData->setRequest(new HttpRequest($event->request)); $this->executionData->setRoute($this->routeOf($event->request)); $this->executionData->setSession(new HttpSession(session())); $this->executionData->setServer(new HttpServer($event->request)); $this->executionData->setResponse(new HttpResponse($event->response)); $this->executionData->setContent(new HttpContent($event->response)); }); } /** * @param Request $request * @return ExecutionRoute */ protected function routeOf(Request $request): ExecutionRoute { return $request->route() ? new HttpRoute($request->route()) : new NullRoute(); } } ================================================ FILE: src/LaravelListeners/PerformanceListener.php ================================================ app = $app; $this->timer = $timer; $this->memory = $memory; } /** * @return void */ public function listen(): void { $this->listenHttp(); $this->listenConsole(); } /** * @return void */ protected function listenHttp(): void { Event::listen(Tracking::class, function () { $this->timer->startLaravel(); }); $this->app->booting(function () { $this->timer->start('boot'); }); $this->app->booted(function () { $this->timer->finish('boot'); $this->timer->start($this->resolveRouteName()); }); Event::listen(RouteMatched::class, function () { $this->timer->finish($this->resolveRouteName()); $this->timer->start('request'); }); /** @codeCoverageIgnoreStart */ Event::listen('kernel.handled', function () { $this->timer->finish('request'); $this->timer->start('response'); }); /** @codeCoverageIgnoreEnd */ Event::listen(RequestHandled::class, function () { $this->timer->finish('request'); $this->timer->start('response'); }); Event::listen(Terminating::class, function () { $this->memory->recordPeak(); $this->timer->finish('response'); $this->timer->finishLaravel(); }); } /** * @return void */ protected function listenConsole(): void { Event::listen(ArtisanStarting::class, function () { $this->timer->start('command'); }); Event::listen(Terminating::class, function () { $this->timer->finish('command'); }); } /** * @return string */ protected function resolveRouteName(): string { if ($this->app->runningUnitTests()) { return 'setup'; } return 'route'; } } ================================================ FILE: src/LaravelListeners/QueriesListener.php ================================================ listenQueries(); $this->listenTransactions(); $this->listenResetTrackers(); } /** * @return Collection */ public function queries(): Collection { return Collection::make($this->queries); } /** * @return int */ public function count(): int { return $this->count; } /** * @return void */ protected function listenQueries(): void { Event::listen(QueryExecuted::class, function (QueryExecuted $event) { $this->count++; list($bindings, $bindingsQuoted) = $this->formatBindings($event); array_push($this->queries, [ 'query', $event->sql, $event->time, $event->connection->getDatabaseName(), $event->connectionName, $bindings, $bindingsQuoted, ]); }); } /** * @return void */ protected function listenTransactions(): void { Event::listen(TransactionBeginning::class, function (TransactionBeginning $event) { array_push($this->queries, [ 'transaction-begin', $event->connection->getDatabaseName(), $event->connectionName, ]); }); Event::listen(TransactionCommitted::class, function (TransactionCommitted $event) { array_push($this->queries, [ 'transaction-commit', $event->connection->getDatabaseName(), $event->connectionName, ]); }); Event::listen(TransactionRolledBack::class, function (TransactionRolledBack $event) { array_push($this->queries, [ 'transaction-rollback', $event->connection->getDatabaseName(), $event->connectionName, ]); }); } /** * @return void */ protected function listenResetTrackers(): void { Event::listen(ResetTrackers::class, function () { $this->queries = []; $this->count = 0; }); } /** * @param QueryExecuted $event * @return array */ protected function formatBindings(QueryExecuted $event): array { $preparedBindings = $event->connection->prepareBindings($event->bindings); foreach ($preparedBindings as $key => $binding) { $bindings[$key] = $this->truncate($binding); $bindingsQuoted[$key] = $this->quote($event, $bindings[$key]); } return [ $bindings ?? [], $bindingsQuoted ?? [], ]; } /** * @param $binding * @return mixed */ protected function truncate($binding) { if (is_string($binding) && strlen($binding) > 255) { return substr($binding, 0, 255) . '...{truncated}'; } return $binding; } /** * @param QueryExecuted $event * @param $binding * @return mixed */ protected function quote(QueryExecuted $event, $binding) { if (is_int($binding) || is_float($binding) || is_object($binding)) { return $binding; } return $event->connection->getPdo()->quote($binding); } } ================================================ FILE: src/LaravelListeners/RedisListener.php ================================================ listenCommands(); $this->listenResetTrackers(); } /** * @return Collection */ public function commands(): Collection { return Collection::make($this->commands); } /** * @return int */ public function count(): int { return $this->count; } /** * @return void */ protected function listenCommands(): void { Event::listen(CommandExecuted::class, function (CommandExecuted $event) { $this->count++; array_push($this->commands, [ $event->command, $event->time, $event->connectionName, $event->parameters, ]); }); } /** * @return void */ protected function listenResetTrackers(): void { Event::listen(ResetTrackers::class, function () { $this->commands = []; $this->count = 0; }); } } ================================================ FILE: src/LaravelListeners/ViewsListener.php ================================================ listenViews(); $this->listenResetTrackers(); } /** * @return Collection */ public function views(): Collection { return Collection::make($this->views); } /** * @return void */ protected function listenViews(): void { Event::listen('composing:*', function (...$view) { array_push($this->views, $this->resolveView($view)); }); } /** * @return void */ protected function listenResetTrackers(): void { Event::listen(ResetTrackers::class, function () { $this->views = []; }); } /** * @param array $view * @return View */ protected function resolveView(array $view): View { return $view[1][0] ?? $view[0]; } } ================================================ FILE: src/LaravelProfiler.php ================================================ bind(); $this->track(); $this->listenForTerminating(); } /** * @return void */ protected function bind(): void { $this->app->bind(DataTracker::class, LaravelDataTracker::class); $this->app->bind(DataProcessor::class, LaravelDataProcessor::class); $this->app->bind(ExecutionWatcher::class, LaravelExecutionWatcher::class); $this->app->singleton(ExecutionData::class, function ($app) { return $app->make(LaravelExecutionData::class); }); $this->app->singleton(Timer::class, function ($app) { return $app->make(TimerService::class); }); $this->app->singleton(Memory::class, function ($app) { return $app->make(MemoryService::class); }); event(new ProfilerBound()); } /** * @return void */ protected function track(): void { $this->app->make(ExecutionWatcher::class)->watch(); $this->dataTracker = $this->app->make(DataTracker::class); $this->dataTracker->track(); event(new Tracking()); } /** * @return void */ protected function listenForTerminating(): void { $this->app->afterBootstrapping(BootProviders::class, function () { $this->registerTerminating(); }); } /** * @return void */ protected function registerTerminating(): void { $this->app->terminating(function () { event(new Terminating()); $this->dataTracker->terminate(); $this->app->make(DataProcessor::class)->process($this->dataTracker); }); } } ================================================ FILE: src/Processors/BroadcastingProcessor.php ================================================ client = $client; $this->configService = $configService; } /** * @param DataTracker $dataTracker * @return void */ public function process(DataTracker $dataTracker): void { $this->broadcast( $dataTracker, $this->configService->serverHttpConnectionUrl() ); } /** * @param DataTracker $dataTracker * @param string $url * @return Response * @throws \GuzzleHttp\Exception\GuzzleException */ protected function broadcast(DataTracker $dataTracker, string $url): Response { return $this->client->request('POST', $url, [ 'json' => [ 'meta' => $dataTracker->meta()->toArray(), 'data' => $dataTracker->data()->toArray(), ], ]); } } ================================================ FILE: src/Processors/StatusCommandProcessor.php ================================================ broadcast( $dataTracker, $this->configService->serverHttpConnectionUrl() . '/status' ); $body = json_decode($response->getBody()); event(new ProfilerServerConnectionSuccessful($body->sockets, $body->clients)); } catch (ConnectException $e) { event(new ProfilerServerConnectionFailed()); throw $e; } } } ================================================ FILE: src/ProfilerResolver.php ================================================ app = $app; $this->configService = $configService; } /** * @return Profiler */ public function resolve(): Profiler { if (! $this->configService->isProfilerEnabled()) { return $this->app->make(DisabledProfiler::class); } return $this->app->make(LaravelProfiler::class); } } ================================================ FILE: src/ServiceProvider.php ================================================ mergeConfigFrom(static::profilerConfigPath(), 'profiler'); $this->app->singleton(Profiler::class, function ($app) { return $app->make(ProfilerResolver::class)->resolve(); }); $this->app->make(Profiler::class)->listenForBoot(); } /** * @return void */ public function boot(): void { $this->allowConfigFileToBePublished(); } /** * @return void */ public function allowConfigFileToBePublished(): void { $this->publishes([ static::profilerConfigPath() => config_path('profiler.php'), ]); } /** * @return string */ public static function profilerConfigPath(): string { return __DIR__ . '/../config/profiler.php'; } } ================================================ FILE: src/Services/ConfigService.php ================================================ app = $app; $this->config = $config; } /** * @return bool */ public function isProfilerEnabled(): bool { $enabledOverrides = Collection::make($this->config->get('profiler.enabled_overrides')); $envToDisable = $enabledOverrides->filter(function ($enabled) { return ! $enabled; })->keys(); if ($this->app->environment($envToDisable->toArray())) { return false; } return $this->config->get('profiler.enabled') === true; } /** * @return Collection */ public function trackers(): Collection { return Collection::make($this->config->get('profiler.trackers')); } /** * @return Collection */ public function processors(): Collection { return Collection::make($this->config->get('profiler.processors')); } /** * @param array $processors */ public function overrideProcessors(array $processors): void { $this->config->set('profiler.processors', $processors); } /** * @return Collection */ public function pathsToTurnOffProcessors(): Collection { return Collection::make($this->config->get('profiler.turn_off_processors_for_paths')); } /** * @return string */ public function serverHttpConnectionUrl(): string { $address = $this->config->get('profiler.server_http.address'); $port = $this->config->get('profiler.server_http.port'); return $address . ':' . $port; } /** * @return string */ public function serverHttpPort(): string { return $this->config->get('profiler.server_http.port'); } /** * @return string */ public function serverSocketsPort(): string { return $this->config->get('profiler.server_sockets.port'); } /** * @return bool */ public function isViewsDataEnabled(): bool { return $this->config->get('profiler.data.views'); } /** * @return bool */ public function isEventsDataEnabled(): bool { return $this->config->get('profiler.data.events'); } /** * @return bool */ public function isEventsGroupEnabled(): bool { return $this->config->get('profiler.group.events'); } /** * @param int $level * @return bool */ public function handleExceptions(int $level): bool { return $this->config->get('profiler.handle_exceptions') === $level; } } ================================================ FILE: src/Services/ConsoleService.php ================================================ app = $app; $this->configService = $configService; } /** * @return string */ public function envInfo(): string { return "Your current environment is: {$this->app->environment()}"; } /** * @return string */ public function profilerStatusInfo(): string { $status = $this->configService->isProfilerEnabled() ? 'enabled' : 'disabled'; return "Laravel Profiler is: {$status}"; } /** * @return string */ public function trackersStatusInfo(): string { return "You have {$this->configService->trackers()->count()} tracker(s) turned on"; } /** * @return string */ public function trackersCommentLine1(): string { return 'There are 14 trackers available out of the box'; } /** * @return string */ public function trackersCommentLine2(): string { return 'turn them on and off in profiler.php configuration file'; } /** * @return string */ public function connectionStatusInfo(): string { return "Trying to connect to Profiler Server on {$this->configService->serverHttpConnectionUrl()} ..."; } /** * @return string */ public function connectionSuccessfulInfo(): string { return 'Connected successfully'; } /** * @param int $socketsPort * @return string */ public function connectionSuccessfulSocketsInfo(int $socketsPort): string { return "Profiler Server sockets listening on port: {$socketsPort}"; } /** * @param int $countClients * @return string */ public function connectionSuccessfulClientsInfo(int $countClients): string { return "You have {$countClients} Profiler Client(s) connected at the moment"; } /** * @return string */ public function connectionFailedInfo(): string { return 'Connection failed'; } /** * @return string */ public function connectionStatusUnknownInfo(): string { return 'BroadcastingProcessor did not report connection status, connection status is unknown'; } /** * @return string */ public function profilerServerCmd(): string { $http = $this->configService->serverHttpPort(); $ws = $this->configService->serverSocketsPort(); return "node node_modules/laravel-profiler-client/server/server.js http={$http} ws={$ws}"; } /** * @param bool $manual * @return string */ public function profilerClientCmd(bool $manual): string { $options = $manual ? '' : ' -o -s'; return "node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/{$options}"; } } ================================================ FILE: src/Services/GeneratorService.php ================================================ configService = $configService; } /** * @param Exception $e * @throws Exception * @return void */ public function error(Exception $e): void { if ($this->configService->handleExceptions(self::HANDLE_EXCEPTIONS_THROW)) { throw $e; } if ($this->configService->handleExceptions(self::HANDLE_EXCEPTIONS_LOG)) { Log::error($e); } } } ================================================ FILE: src/Services/ParamsService.php ================================================ resolveObject($param); } if (is_array($param)) { return array_map(function ($item) { return $this->resolve($item); }, $param); } return $param; } /** * @param array $params * @return array */ public function resolveFlattenFromArray(array $params): array { return array_map(function ($param) { return $this->resolveFlatten($param); }, $params); } /** * @param $param * @return string */ protected function resolveFlatten($param): string { if ($param instanceof Collection) { return get_class($param) . ': ' . $param->count() . ' item(s)'; } if (is_object($param)) { return get_class($param); } if (is_array($param)) { return 'array: ' . count($param) . ' item(s)'; } return gettype($param); } /** * @param $param * @return array|string */ protected function resolveObject($param) { if (method_exists($param, 'toArray')) { return $this->resolve($param->toArray()); } return get_class($param); } } ================================================ FILE: src/Services/Performance/MemoryService.php ================================================ app = $app; $this->memory = Collection::make(); } /** * @return void */ public function recordPeak(): void { $this->memory->put('peak', memory_get_peak_usage()); } /** * @return Collection */ public function all(): Collection { return $this->memory; } } ================================================ FILE: src/Services/Performance/NullTimerService.php ================================================ app = $app; $this->time = Collection::make(); } /** * @param string $name * @return void */ public function start(string $name): void { $this->time->put($name, [ 'start' => $this->now(), ]); } /** * @param string $name * @return void */ public function finish(string $name): void { $this->time->put($name, array_merge($this->getByName($name), [ 'finish' => $this->now(), ])); } /** * @param string $name * @return void * @throws TimerException */ public function startCustom(string $name): void { $customName = $this->customNamePrefix . $name; $this->guardTimerAlreadyStarted($customName); $this->start($customName); } /** * @param string $name * @return void * @throws TimerException */ public function finishCustom(string $name): void { $customName = $this->customNamePrefix . $name; $this->guardTimerAlreadyFinished($customName); $this->guardTimerNotStartedYet($customName); $this->finish($customName); } /** * @return void */ public function startLaravel(): void { $this->time->put('laravel', [ 'start' => $this->laravelStartTimeOrNow(), ]); } /** * @return void */ public function finishLaravel(): void { $this->finish('laravel'); } /** * @param string $name * @return float */ public function milliseconds(string $name): float { return $this->millisecondsOf( $this->getByName($name) ); } /** * @param string $name * @return float */ public function millisecondsCustom(string $name): float { return $this->milliseconds($this->customNamePrefix . $name); } /** * @return array */ public function all(): array { return $this->time->filter(function ($item) { return $this->isCompleted($item); })->map(function ($item) { return $this->millisecondsOf($item); })->toArray(); } /** * @return float */ protected function now(): float { return \microtime(true); } /** * @return float */ protected function laravelStartTimeOrNow(): float { return defined('LARAVEL_START') && ! $this->app->environment('testing') ? LARAVEL_START : $this->now(); } /** * @param string $name * @return array */ protected function getByName(string $name): array { return $this->time->first(function ($a, $b) use ($name) { return $a === $name || $b === $name; }) ?? []; } /** * @param array $item * @return float */ protected function millisecondsOf(array $item): float { if (! $this->isCompleted($item)) { return -1; } return ($item['finish'] - $item['start']) * 1000; } /** * @param array $item * @return bool */ protected function isCompleted(array $item): bool { return isset($item['start']) && isset($item['finish']); } /** * @param string $name * @return void * @throws TimerException */ protected function guardTimerAlreadyStarted(string $name): void { if ($this->time->has($name)) { throw new TimerException("Laravel Profiler custom time tracker for {$name} already exists and can not be started twice"); } } /** * @param string $name * @return void * @throws TimerException */ protected function guardTimerAlreadyFinished(string $name): void { if ($this->isCompleted($this->getByName($name))) { throw new TimerException("Laravel Profiler custom time tracker for {$name} already exists and can not be finished twice"); } } /** * @param string $name * @return void * @throws TimerException */ protected function guardTimerNotStartedYet(string $name): void { if (! $this->time->has($name)) { throw new TimerException("Laravel Profiler custom time tracker for {$name} is not started yet"); } } } ================================================ FILE: src/Services/helpers.php ================================================ make(Timer::class)->startCustom($name); } catch (TimerException $e) { app()->make(LogService::class)->error($e); } } } if (! function_exists('profiler_finish')) { function profiler_finish(string $name): void { try { app()->make(Timer::class)->finishCustom($name); } catch (TimerException $e) { app()->make(LogService::class)->error($e); } } } if (! function_exists('profiler_reset')) { function profiler_reset(): void { app()->make(Profiler::class)->resetTrackers(); } } ================================================ FILE: src/Trackers/ApplicationTracker.php ================================================ generatorService = $generatorService; } /** * @return void */ public function terminate(): void { $this->meta->put('execution_at', time()); $this->meta->put('id', $this->generatorService->unique32CharsId()); $this->meta->put('laravel_version', $this->app->version()); $this->meta->put('php_version', phpversion()); $this->meta->put('env', $this->app->environment()); $this->meta->put('is_running_in_console', $this->app->runningInConsole()); $this->data->put('application', Collection::make([ 'locale' => $this->app->getLocale(), 'configuration_is_cached' => $this->app->configurationIsCached(), 'routes_are_cached' => $this->app->routesAreCached(), 'is_down_for_maintenance' => $this->app->isDownForMaintenance(), 'should_skip_middleware' => $this->app->shouldSkipMiddleware(), ])); } } ================================================ FILE: src/Trackers/AuthTracker.php ================================================ authListener = $authListener; $this->authListener->listen(); } /** * @return void */ public function terminate(): void { $this->data->put('auth', $this->authListener->user()); } } ================================================ FILE: src/Trackers/BaseTracker.php ================================================ app = $app; $this->meta = new Collection(); $this->data = new Collection(); } /** * @return Collection */ public function meta(): Collection { return $this->meta; } /** * @return Collection */ public function data(): Collection { return $this->data; } } ================================================ FILE: src/Trackers/BindingsTracker.php ================================================ abstracts()->map(function ($abstract) { try { $resolved = $this->resolved($abstract); } catch (BindingResolutionException $e) {} return [ 'abstract' => $abstract, 'resolved' => $resolved ?? null, ]; }); $this->data->put('bindings', $bindings); } /** * @return Collection */ protected function abstracts(): Collection { return Collection::make( array_keys($this->app->getBindings()) ); } /** * @param string $abstract * @return string * @throws BindingResolutionException */ protected function resolved(string $abstract): string { if (! $this->app->resolved($abstract)) { throw new BindingResolutionException(); } $concrete = $this->app->make($abstract); if (is_object($concrete)) { return get_class($concrete); } return gettype($concrete); } } ================================================ FILE: src/Trackers/ConfigTracker.php ================================================ data->put('config', $this->config()); } /** * @return Collection */ protected function config(): Collection { return Collection::make( $this->hideSecretValues( $this->app->make('config')->all() ) ); } /** * @param array $config * @return array */ protected function hideSecretValues(array $config): array { $keys = array_keys($config); return array_map(function ($value) use (&$keys) { $key = array_shift($keys); if (is_array($value)) { return $this->hideSecretValues($value); } if (is_string($value) && preg_match('/^(password|key|secret)$/i', $key)) { $value = str_repeat('*', strlen($value)); } return $value; }, $config); } } ================================================ FILE: src/Trackers/ContentTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $content = $this->executionData->content(); $this->meta = $content->meta(); $this->data->put('content', $content->data()->get('content')); } } ================================================ FILE: src/Trackers/EventsTracker.php ================================================ paramsService = $paramsService; $this->configService = $configService; $this->eventsListener = $eventsListener; $this->eventsListener->listen(); } /** * @return void */ public function terminate(): void { $events = $this->eventsListener->events()->map(function ($item) { list($event, $payload, $name, $count) = $item; if ($this->shouldTrackData($count)) { return [ 'name' => $name, 'count' => $count, 'data' => $this->resolveData($event, $payload), ]; } return [ 'name' => $name, 'count' => $count, ]; }); $this->meta->put('events_count', $this->eventsListener->count()); $this->data->put('events', $events); } /** * @param int $count * @return bool */ protected function shouldTrackData(int $count): bool { return $this->configService->isEventsDataEnabled() && $count == 1; } /** * @param $event * @param $payload * @return Collection */ protected function resolveData($event, $payload): Collection { $event = is_array($payload) ? $payload[0] : $event; $class = new \ReflectionClass($event); $publicProps = Collection::make( $class->getProperties(\ReflectionProperty::IS_PUBLIC) ); if (method_exists($publicProps, 'mapWithKeys')) { return $this->propsMapWithKeys($publicProps, $event); } return $this->propsMap($publicProps, $event); // @codeCoverageIgnore } /** * @param Collection $publicProps * @param $event * @return Collection */ protected function propsMapWithKeys(Collection $publicProps, $event): Collection { return $publicProps->mapWithKeys(function ($prop) use ($event) { return [ $prop->name => $this->paramsService->resolve($event->{$prop->name}), ]; }); } /** * @codeCoverageIgnore * * @param Collection $publicProps * @param $event * @return Collection */ protected function propsMap(Collection $publicProps, $event): Collection { return $publicProps->map(function ($prop) use ($event) { return [ $prop->name => $this->paramsService->resolve($event->{$prop->name}), ]; })->flatten(1); } } ================================================ FILE: src/Trackers/ExceptionTracker.php ================================================ exceptionListener = $exceptionListener; $this->exceptionListener->listen(); $this->bindExceptionHandler($app); } /** * @param Application $app * @return void */ protected function bindExceptionHandler(Application $app): void { $version = (int) $app->version(); $handler = $version < 7 ? ExceptionHandlerTillVersion6::class : ExceptionHandlerFromVersion7::class; // @codeCoverageIgnore $app->singleton(\App\Exceptions\Handler::class, $handler); } /** * @return void */ public function terminate(): void { $exception = $this->exceptionListener->exception() ? $this->exception() : null; $this->data->put('exception', $exception); } /** * @return Collection */ protected function exception(): Collection { $exception = $this->exceptionListener->exception(); return Collection::make([ 'message' => $exception->getMessage(), 'exception' => get_class($exception), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'trace' => Collection::make($exception->getTrace())->map(function ($trace) { return Arr::except($trace, ['args', 'type']); }), ]); } } ================================================ FILE: src/Trackers/PathsTracker.php ================================================ paths()->map(function ($path, $name) { return [ 'name' => $name, 'path' => $path, ]; })->values(); $this->data->put('paths', $paths); } /** * @return Collection */ protected function paths(): Collection { return Collection::make([ 'app_path' => $this->app->path(), 'base_path' => $this->app->basePath(), 'lang_path' => $this->app->langPath(), 'config_path' => $this->app->configPath(), 'public_path' => $this->app->publicPath(), 'storage_path' => $this->app->storagePath(), 'resource_path' => $this->resourcePath(), 'database_path' => $this->app->databasePath(), 'bootstrap_path' => $this->app->bootstrapPath(), 'cached_config_path' => $this->app->getCachedConfigPath(), 'cached_routes_path' => $this->app->getCachedRoutesPath(), 'cached_services_path' => $this->app->getCachedServicesPath(), 'cached_packages_path' => $this->getCachedPackagesPath(), 'environment_file_path' => $this->app->environmentFilePath(), ])->filter(function ($item) { return !! $item; }); } /** * @return string */ protected function resourcePath(): string { return method_exists($this->app, 'resourcePath') ? $this->app->resourcePath() : ''; } /** * @return string */ protected function getCachedPackagesPath(): string { return method_exists($this->app, 'getCachedPackagesPath') ? $this->app->getCachedPackagesPath() : ''; } } ================================================ FILE: src/Trackers/PerformanceTracker.php ================================================ timer = $timer; $this->memory = $memory; $performanceListener->listen(); } /** * @return void */ public function terminate(): void { $this->data->put('performance', Collection::make([ 'timer' => $this->timer->all(), 'memory' => $this->memory->all(), ])); } } ================================================ FILE: src/Trackers/QueriesTracker.php ================================================ queriesListener = $queriesListener; $this->queriesListener->listen(); } /** * @return void */ public function terminate(): void { $queries = $this->queriesListener->queries()->map(function ($item) { if ($this->isTransactionType($item[0])) { return $this->terminateTransaction($item); } return $this->terminateQuery($item); }); $this->meta->put('queries_count', $this->queriesListener->count()); $this->data->put('queries', $queries); } /** * @param array $item * @return array */ protected function terminateTransaction(array $item): array { list($type, $database, $name) = $item; return [ 'type' => $type, 'database' => $database, 'name' => $name, ]; } /** * @param array $item * @return array */ protected function terminateQuery(array $item): array { list($type, $sql, $time, $database, $name, $bindings, $bindingsQuoted) = $item; $formattedSql = $this->formatSql($sql); return [ 'type' => $type, 'sql' => $formattedSql, 'bindings' => $bindings, 'time' => $time, 'database' => $database, 'name' => $name, 'query' => $this->queryWithBindings($bindingsQuoted, $formattedSql), ]; } /** * @param string $type * @return bool */ protected function isTransactionType(string $type): bool { $transactionTypes = [ 'transaction-begin', 'transaction-commit', 'transaction-rollback', ]; return in_array($type, $transactionTypes); } /** * @param string $sql * @return string */ protected function formatSql(string $sql): string { return preg_replace('/"/', '`', $sql); } /** * @param array $bindingsQuoted * @param string $formattedSql * @return string */ protected function queryWithBindings(array $bindingsQuoted, string $formattedSql): string { foreach ($bindingsQuoted as $key => $binding) { $formattedSql = preg_replace($this->bindingRegex($key), $binding, $formattedSql, 1); } return $formattedSql; } /** * @param $key * @return string */ protected function bindingRegex($key): string { return is_int($key) ? "/\?/" : "/:{$key}/"; } } ================================================ FILE: src/Trackers/RedisTracker.php ================================================ enableRedisEvents(); $this->redisListener = $redisListener; $this->redisListener->listen(); } /** * @return void */ public function terminate(): void { $commands = $this->redisListener->commands()->map(function ($item) { return $this->terminateCommands($item); }); $this->meta->put('redis_count', $this->redisListener->count()); $this->meta->put('redis_can_be_tracked', $this->redisCanBeTracked); $this->data->put('redis', $commands); } /** * @param array $item * @return array */ protected function terminateCommands(array $item): array { list($command, $time, $name, $parameters) = $item; return [ 'command' => $command, 'time' => $time, 'name' => $name, 'parameters' => $parameters, ]; } /** * @return void */ protected function enableRedisEvents(): void { $manager = $this->app->make('redis'); if (! method_exists($manager, 'enableEvents')) { return; // @codeCoverageIgnore } $this->redisCanBeTracked = true; $manager->enableEvents(); } } ================================================ FILE: src/Trackers/RequestTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $request = $this->executionData->request(); $this->meta = $request->meta(); $this->data->put('request', $request->data()); } } ================================================ FILE: src/Trackers/ResponseTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $response = $this->executionData->response(); $this->meta = $response->meta(); $this->data->put('response', $response->data()); } } ================================================ FILE: src/Trackers/RouteTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $route = $this->executionData->route(); $this->meta = $route->meta(); $this->data->put('route', $route->data()); } } ================================================ FILE: src/Trackers/ServerTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $server = $this->executionData->server(); $this->meta = $server->meta(); $this->data->put('server', $server->data()); } } ================================================ FILE: src/Trackers/ServiceProvidersTracker.php ================================================ data->put('service_providers', $this->loadedProviders()); } /** * @return Collection */ protected function loadedProviders(): Collection { return Collection::make( array_keys($this->app->getLoadedProviders()) ); } } ================================================ FILE: src/Trackers/SessionTracker.php ================================================ executionData = $executionData; } /** * @return void */ public function terminate(): void { $session = $this->executionData->session(); $this->meta = $session->meta(); $this->data->put('session', $session->data()); } } ================================================ FILE: src/Trackers/ViewsTracker.php ================================================ configService = $configService; $this->paramsService = $paramsService; $this->viewsListener = $viewsListener; $this->viewsListener->listen(); } /** * @return void */ public function terminate(): void { $views = $this->viewsListener->views()->map(function (View $view) { if ($this->configService->isViewsDataEnabled()) { return [ 'name' => $view->name(), 'path' => $view->getPath(), 'data' => $view->getData(), ]; } return [ 'name' => $view->name(), 'path' => $view->getPath(), 'params' => $this->paramsService->resolveFlattenFromArray($view->getData()), ]; })->values(); $this->data->put('views', $views); } } ================================================ FILE: tests/Feature/CommandsTest.php ================================================ tapLaravelVersionFrom(5.7, function () { $this->artisan('profiler:status') ->expectsOutput('1) Your current environment is: ' . $this->app->environment()) ->expectsOutput('Laravel Profiler is: enabled'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); } /** @test */ function lists_trackers_if_profiler_is_enabled() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.trackers', [ TrackerA::class, TrackerB::class, ]); }); $this->tapLaravelVersionFrom(5.7, function () { $this->artisan('profiler:status') ->expectsOutput('2) You have 2 tracker(s) turned on') ->expectsOutput('- ' . TrackerA::class) ->expectsOutput('- ' . TrackerB::class) ->expectsOutput("There are {$this->countAllConfigurableTrackers()} trackers available out of the box") ->expectsOutput('turn them on and off in profiler.php configuration file'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); } /** @test */ function switches_processor_to_status_processor() { $this->artisan('profiler:status'); $configService = $this->app->make(ConfigService::class); $this->assertCount(1, $configService->processors()); $this->assertEquals(StatusCommandProcessor::class, $configService->processors()->first()); } /** @test */ function status_processor_handles_when_connection_to_profiler_server_is_successful() { $this->tapLaravelVersionFrom(5.4, function () { Event::fake(); $response = Mockery::mock(Response::class); $response->shouldReceive('getBody')->once()->andReturn('{"sockets": 1234, "clients": 9}'); $client = Mockery::mock(Client::class); $client->shouldReceive('request')->once()->andReturn($response); $configService = Mockery::mock(ConfigService::class); $configService->shouldReceive('serverHttpConnectionUrl')->once(); $processor = new StatusCommandProcessor($client, $configService); $processor->process($this->app->make(DataTracker::class)); Event::assertNotDispatched(ProfilerServerConnectionFailed::class); Event::assertDispatched(ProfilerServerConnectionSuccessful::class, function ($event) { return $event->socketsPort === 1234 && $event->countClients === 9; }); }); $this->tapLaravelVersionTill(5.3, function () { $this->assertTrue(true); }); } /** @test */ function status_processor_handles_when_connection_to_profiler_server_failed() { $this->tapLaravelVersionFrom(5.4, function () { Event::fake(); $client = Mockery::mock(Client::class); $client->shouldReceive('request')->once()->andThrows(new ConnectException('', new Request('method', ''))); try { $processor = new StatusCommandProcessor($client, $this->app->make(ConfigService::class)); $processor->process($this->app->make(DataTracker::class)); } catch (ConnectException $e) { Event::assertDispatched(ProfilerServerConnectionFailed::class); Event::assertNotDispatched(ProfilerServerConnectionSuccessful::class); return; } $this->fail('ConnectException should be thrown'); }); $this->tapLaravelVersionTill(5.3, function () { $this->assertTrue(true); }); } /** @test */ function tells_if_connection_to_profiler_server_is_successful() { $this->tapLaravelVersionFrom(7, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); $this->tapLaravelVersionBetween(5.7, 6, function () { $realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class)); $consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing(); $consoleService->shouldReceive('connectionStatusInfo') ->once() ->andReturn($realConsoleService->connectionStatusInfo()); $consoleService->shouldReceive('connectionSuccessfulInfo') ->once() ->andReturn($realConsoleService->connectionSuccessfulInfo()); $consoleService->shouldReceive('connectionSuccessfulSocketsInfo') ->once() ->andReturn($realConsoleService->connectionSuccessfulSocketsInfo(1234)); $consoleService->shouldReceive('connectionSuccessfulClientsInfo') ->once() ->andReturn($realConsoleService->connectionSuccessfulClientsInfo(9)); $consoleService->shouldNotReceive('connectionFailedInfo'); $consoleService->shouldNotReceive('connectionStatusUnknownInfo'); $this->app->instance(ConsoleService::class, $consoleService); $this->app->terminating(function () { event(new ProfilerServerConnectionSuccessful(1234, 9)); }); $this->artisan('profiler:status') ->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...') ->expectsOutput('Connected successfully') ->expectsOutput('Profiler Server sockets listening on port: 1234') ->expectsOutput("You have 9 Profiler Client(s) connected at the moment"); $this->turnOffProcessors(); $this->app->terminate(); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); } /** @test */ function tells_if_connection_to_profiler_server_failed() { $this->tapLaravelVersionFrom(7, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); $this->tapLaravelVersionBetween(5.7, 6, function () { $realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class)); $consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing(); $consoleService->shouldReceive('connectionStatusInfo') ->once() ->andReturn($realConsoleService->connectionStatusInfo()); $consoleService->shouldNotReceive('connectionSuccessfulInfo'); $consoleService->shouldReceive('connectionFailedInfo') ->once() ->andReturn($realConsoleService->connectionFailedInfo()); $consoleService->shouldNotReceive('connectionStatusUnknownInfo'); $this->app->instance(ConsoleService::class, $consoleService); $this->app->terminating(function () { event(new ProfilerServerConnectionFailed()); }); $this->artisan('profiler:status') ->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...') ->expectsOutput('Connection failed'); $this->turnOffProcessors(); $this->app->terminate(); $consoleService->shouldNotHaveReceived('connectionUnknownInfo'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); } /** @test */ function tells_if_connection_to_profiler_server_has_unknown_status() { $this->tapLaravelVersionFrom(7, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); $this->tapLaravelVersionBetween(5.7, 6, function () { $realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class)); $consoleService = Mockery::mock(ConsoleService::class)->shouldIgnoreMissing(); $consoleService->shouldReceive('connectionStatusInfo') ->once() ->andReturn($realConsoleService->connectionStatusInfo()); $consoleService->shouldNotReceive('connectionSuccessfulInfo'); $consoleService->shouldNotReceive('connectionFailedInfo'); $consoleService->shouldReceive('connectionStatusUnknownInfo') ->once() ->andReturn($realConsoleService->connectionStatusUnknownInfo()); $this->app->instance(ConsoleService::class, $consoleService); $this->artisan('profiler:status') ->expectsOutput('3) Trying to connect to Profiler Server on http://localhost:8099 ...') ->expectsOutput('BroadcastingProcessor did not report connection status, connection status is unknown'); $this->turnOffProcessors(); $this->app->terminate(); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); } /** @test */ function tells_status_if_profiler_is_disabled() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.enabled', false); }); $configService = Mockery::spy(ConfigService::class)->shouldIgnoreMissing(); $this->app->instance(ConfigService::class, $configService); $this->tapLaravelVersionFrom(5.7, function () { $this->artisan('profiler:status') ->expectsOutput('1) Your current environment is: ' . $this->app->environment()) ->expectsOutput('Laravel Profiler is: disabled'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:status'); $this->assertTrue(true); }); $configService->shouldNotHaveReceived('trackers'); } /** @test */ function can_start_profiler_server() { $consoleService = Mockery::spy(ConsoleService::class); $this->app->instance(ConsoleService::class, $consoleService); $this->artisan('profiler:server'); $consoleService->shouldHaveReceived('profilerServerCmd')->once(); } /** @test */ function can_start_profiler_server_with_configured_ports() { $configService = Mockery::mock(ConfigService::class); $configService->shouldReceive('serverHttpPort')->once()->andReturn('1234'); $configService->shouldReceive('serverSocketsPort')->once()->andReturn('9876'); $this->app->instance(ConfigService::class, $configService); $consoleService = $this->app->make(ConsoleService::class); $this->assertEquals( 'node node_modules/laravel-profiler-client/server/server.js http=1234 ws=9876', $consoleService->profilerServerCmd() ); } /** @test */ function tells_starting_message_for_profiler_server() { $this->tapLaravelVersionFrom(5.7, function () { $this->artisan('profiler:server') ->expectsOutput('Starting Profiler Server ...'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:server'); $this->assertTrue(true); }); } /** @test */ function can_start_profiler_client() { $realConsoleService = $this->app->make(ConsoleService::class); $consoleService = Mockery::mock(ConsoleService::class); $consoleService->shouldReceive('profilerClientCmd')->once()->with(false); $this->app->instance(ConsoleService::class, $consoleService); Artisan::call('profiler:client'); $this->assertEquals( 'node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/ -o -s', $realConsoleService->profilerClientCmd(false) ); } /** @test */ function can_start_profiler_client_with_manual_option() { $consoleService = Mockery::mock(ConsoleService::class); $consoleService->shouldReceive('profilerClientCmd')->twice()->with(true); $this->app->instance(ConsoleService::class, $consoleService); Artisan::call('profiler:client', ['--manual' => true]); Artisan::call('profiler:client', ['-m' => true]); $realConsoleService = new ConsoleService($this->app, $this->app->make(ConfigService::class)); $this->assertEquals( 'node_modules/.bin/http-server node_modules/laravel-profiler-client/dist/', $realConsoleService->profilerClientCmd(true) ); } /** @test */ function tells_starting_message_for_profiler_client() { $this->tapLaravelVersionFrom(5.7, function () { $this->artisan('profiler:client') ->expectsOutput('Starting Profiler Client ...'); }); $this->tapLaravelVersionTill(5.6, function () { $this->artisan('profiler:client'); $this->assertTrue(true); }); } /** * @var array */ protected $beforeApplicationDestroyedCallbacks = []; /** * @param callable $callback */ protected function beforeApplicationDestroyed(callable $callback) { $this->beforeApplicationDestroyedCallbacks[] = $callback; } } ================================================ FILE: tests/Feature/LaravelConsoleExecutionTest.php ================================================ turnOffProcessors(); $this->executionData = $this->app->make(ExecutionData::class); $this->app->make(Kernel::class)->registerCommand(new DummyCommand($this->testExitCode)); } /** @test */ function has_console_request() { Artisan::call('dummy-command'); $request = $this->executionData->request(); $this->tapLaravelVersionTill(5.4, function () use ($request) { $this->assertInstanceOf(ConsoleStartingRequest::class, $request); }); $this->tapLaravelVersionFrom(5.5, function () use ($request) { $this->assertInstanceOf(ConsoleFinishedRequest::class, $request); }); } /** @test */ function has_request_type() { Artisan::call('dummy-command'); $request = $this->executionData->request(); $this->tapLaravelVersionTill(5.4, function () use ($request) { $this->assertEquals('command-starting', $request->meta()->get('type')); }); $this->tapLaravelVersionFrom(5.5, function () use ($request) { $this->assertEquals('command-finished', $request->meta()->get('type')); }); } /** @test */ function has_request_method() { Artisan::call('dummy-command'); $request = $this->executionData->request(); $this->tapLaravelVersionTill(5.4, function () use ($request) { $this->assertArrayNotHasKey('path', $request->meta()); }); $this->tapLaravelVersionFrom(5.5, function () use ($request) { $this->assertEquals('dummy-command', $request->meta()->get('path')); }); } /** @test */ function has_request_arguments() { Artisan::call('dummy-command', ['user' => 'Abc']); $request = $this->executionData->request(); $this->tapLaravelVersionTill(5.4, function () use ($request) { $this->assertArrayNotHasKey('arguments', $request->data()); }); $this->tapLaravelVersionFrom(5.5, function () use ($request) { $this->assertEquals('dummy-command', $request->data()->get('arguments')['command']); $this->assertEquals('Abc', $request->data()->get('arguments')['user']); }); } /** @test */ function has_request_options() { Artisan::call('dummy-command', ['--number' => 5]); $request = $this->executionData->request(); $this->tapLaravelVersionTill(5.4, function () use ($request) { $this->assertArrayNotHasKey('options', $request->data()); }); $this->tapLaravelVersionFrom(5.5, function () use ($request) { $this->assertEquals(5, $request->data()->get('options')['number']); }); } /** @test */ function has_null_route() { Artisan::call('dummy-command'); $route = $this->executionData->route(); $this->assertInstanceOf(NullRoute::class, $route); } /** @test */ function has_null_session() { Artisan::call('dummy-command'); $session = $this->executionData->session(); $this->assertInstanceOf(NullSession::class, $session); } /** @test */ function has_null_server() { Artisan::call('dummy-command'); $server = $this->executionData->server(); $this->assertInstanceOf(NullServer::class, $server); } /** @test */ function has_console_response() { Artisan::call('dummy-command'); $response = $this->executionData->response(); $this->tapLaravelVersionTill(5.4, function () use ($response) { $this->assertInstanceOf(ConsoleStartingResponse::class, $response); }); $this->tapLaravelVersionFrom(5.5, function () use ($response) { $this->assertInstanceOf(ConsoleFinishedResponse::class, $response); }); } /** @test */ function console_response_has_only_status() { Artisan::call('dummy-command'); $response = $this->executionData->response(); $this->tapLaravelVersionTill(5.4, function () use ($response) { $this->assertArrayHasKey('status', $response->meta()); $this->assertNull($response->meta()->get('status')); $this->assertCount(1, $response->meta()); $this->assertCount(0, $response->data()); }); $this->tapLaravelVersionFrom(5.5, function () use ($response) { $this->assertEquals($this->testExitCode, $response->meta()->get('status')); $this->assertCount(1, $response->meta()); $this->assertCount(0, $response->data()); }); } /** @test */ function has_null_content() { Artisan::call('dummy-command'); $content = $this->executionData->content(); $this->assertInstanceOf(NullContent::class, $content); } } ================================================ FILE: tests/Feature/LaravelExecutionTest.php ================================================ turnOffProcessors(); } /** @test */ function laravel_execution_data_is_singleton() { $executionDataA = $this->app->make(ExecutionData::class); $executionDataB = $this->app->make(ExecutionData::class); $this->assertSame($executionDataA, $executionDataB); } } ================================================ FILE: tests/Feature/LaravelHttpExecutionTest.php ================================================ turnOffProcessors(); $this->executionData = $this->app->make(ExecutionData::class); } /** @test */ function has_http_request() { $this->get('/'); $request = $this->executionData->request(); $this->assertInstanceOf(HttpRequest::class, $request); } /** @test */ function has_request_type() { $this->get('/'); $request = $this->executionData->request(); $this->assertEquals('http', $request->meta()->get('type')); } /** @test */ function has_request_method() { $this->post('/', []); $request = $this->executionData->request(); $this->assertEquals('POST', $request->meta()->get('method')); } /** @test */ function has_request_path() { $this->get('/abc/xyz'); $request = $this->executionData->request(); $this->assertEquals('abc/xyz', $request->meta()->get('path')); } /** @test */ function has_request_is_ajax() { $this->get('/'); $this->assertFalse($this->executionData->request()->meta()->get('ajax')); $this->get('/', ['X-Requested-With' => 'XMLHttpRequest']); $this->assertTrue($this->executionData->request()->meta()->get('ajax')); } /** @test */ function has_request_is_json() { $this->get('/'); $this->assertFalse($this->executionData->request()->meta()->get('json')); $this->get('/', ['Content-Type' => 'application/json']); $this->assertTrue($this->executionData->request()->meta()->get('json')); } /** @test */ function has_request_is_pjax() { $this->get('/'); $this->assertFalse($this->executionData->request()->data()->get('pjax')); $this->get('/', ['X-PJAX' => true]); $this->assertTrue($this->executionData->request()->data()->get('pjax')); } /** @test */ function has_request_url() { $this->get('/abc?ab=xy'); $request = $this->executionData->request(); $this->assertEquals("{$this->app->make('request')->root()}/abc", $request->data()->get('url')); } /** @test */ function has_request_query() { $this->get('/abc?ab=xy'); $this->assertEquals(['ab' => 'xy'], $this->executionData->request()->data()->get('query')); } /** @test */ function can_have_empty_request_query() { $this->get('/'); $this->assertEquals([], $this->executionData->request()->data()->get('query')); } /** @test */ function has_request_ip() { $this->get('/'); $request = $this->executionData->request(); $this->assertEquals($this->app->make('request')->ip(), $request->data()->get('ip')); } /** @test */ function has_request_server() { $this->get('/'); $server = $this->executionData->server(); $this->assertCount(0, $server->meta()); $this->assertEquals($this->app->make('request')->server(), $server->data()->toArray()); } /** @test */ function has_request_header() { $this->get('/'); $request = $this->executionData->request(); $this->assertEquals($this->app->make('request')->header(), $request->data()->get('header')); } /** @test */ function has_request_input() { $this->post('/', [ 'key-a' => 'val-a', 'key-b' => 'val-b', ]); $request = $this->executionData->request(); $this->assertEquals('val-a', $request->data()->get('input')['key-a']); $this->assertEquals('val-b', $request->data()->get('input')['key-b']); } /** @test */ function has_request_all_files() { $this->tapLaravelVersionTill(5.3, function () { $this->assertTrue(true); }); $this->tapLaravelVersionBetween(5.4, 6, function () { $fileA = UploadedFile::fake()->image('file-val-a.png'); $fileB = UploadedFile::fake()->image('file-val-b.png'); $typeA = get_class($fileA); $typeB = get_class($fileB); $this->post('/', [ 'file-key-a' => $fileA, 'file-key-b' => $fileB, ]); $request = $this->executionData->request(); $this->assertEquals([ 'client original name' => $fileA->getClientOriginalName(), 'client original extension' => $fileA->getClientOriginalExtension(), 'client mime type' => $fileA->getClientMimeType(), 'client size' => $fileA->getClientSize(), 'path' => $fileA->path(), ], $request->data()->get('files')['file-key-a'][$typeA]); $this->assertEquals([ 'client original name' => $fileB->getClientOriginalName(), 'client original extension' => $fileB->getClientOriginalExtension(), 'client mime type' => $fileB->getClientMimeType(), 'client size' => $fileB->getClientSize(), 'path' => $fileB->path(), ], $request->data()->get('files')['file-key-b'][$typeB]); }); $this->tapLaravelVersionFrom(7, function () { $fileA = UploadedFile::fake()->image('file-val-a.png'); $fileB = UploadedFile::fake()->image('file-val-b.png'); $typeA = get_class($fileA); $typeB = get_class($fileB); $this->post('/', [ 'file-key-a' => $fileA, 'file-key-b' => $fileB, ]); $request = $this->executionData->request(); $this->assertEquals([ 'client original name' => $fileA->getClientOriginalName(), 'client original extension' => $fileA->getClientOriginalExtension(), 'client mime type' => $fileA->getClientMimeType(), 'client size' => $fileA->getSize(), 'path' => $fileA->path(), ], $request->data()->get('files')['file-key-a'][$typeA]); $this->assertEquals([ 'client original name' => $fileB->getClientOriginalName(), 'client original extension' => $fileB->getClientOriginalExtension(), 'client mime type' => $fileB->getClientMimeType(), 'client size' => $fileB->getSize(), 'path' => $fileB->path(), ], $request->data()->get('files')['file-key-b'][$typeB]); }); } /** @test */ function has_request_all_files_if_they_are_in_array() { $this->tapLaravelVersionTill(5.3, function () { $this->assertTrue(true); }); $this->tapLaravelVersionFrom(5.4, function () { $fileA = UploadedFile::fake()->image('file-val-a.png'); $fileB = UploadedFile::fake()->image('file-val-b.png'); $fileX = UploadedFile::fake()->image('file-val-x.png'); $fileY = UploadedFile::fake()->image('file-val-y.png'); $typeA = get_class($fileA); $typeB = get_class($fileB); $typeX = get_class($fileX); $typeY = get_class($fileY); $this->post('/', [ 'file-key-1' => [ 'a' => $fileA, 'b' => $fileB, ], 'file-key-2' => [ 'subkey' => [ 'x' => $fileX, 'y' => $fileY, ], ], ]); $request = $this->executionData->request(); $this->assertContains($fileA->path(), $request->data()->get('files')['file-key-1']['a'][$typeA]); $this->assertContains($fileB->path(), $request->data()->get('files')['file-key-1']['b'][$typeB]); $this->assertContains($fileX->path(), $request->data()->get('files')['file-key-2']['subkey']['x'][$typeX]); $this->assertContains($fileY->path(), $request->data()->get('files')['file-key-2']['subkey']['y'][$typeY]); }); } /** @test */ function has_request_cookie() { $this->tapLaravelVersionTill('5.4', function () { $this->call('GET', '/', [], ['cookie-key-a' => Crypt::encrypt('cookie-val-a')]); $request = $this->executionData->request(); $this->assertStringContainsString('cookie-val-a', $request->data()->get('cookie')['cookie-key-a']); }); $this->tapLaravelVersionBetween('5.5', '5.5', function () { $this->call('GET', '/', [], ['cookie-key-a' => [Crypt::encrypt('cookie-val-a')]]); $request = $this->executionData->request(); $this->assertStringContainsString('cookie-val-a', Crypt::decrypt($request->data()->get('cookie')['cookie-key-a'][0])); }); $this->tapLaravelVersionBetween('5.6', '5.8', function () { $this->call('GET', '/', [], ['cookie-key-a' => Crypt::encrypt('cookie-val-a')]); $request = $this->executionData->request(); $this->assertStringContainsString('cookie-val-a', $request->data()->get('cookie')['cookie-key-a']); }); $this->tapLaravelVersionFrom('6', function () { $this->call('GET', '/', [], ['cookie-key-a' => [Crypt::encrypt('cookie-val-a')]]); $request = $this->executionData->request(); $this->assertStringContainsString('cookie-val-a', Crypt::decrypt($request->data()->get('cookie')['cookie-key-a'][0])); }); } /** @test */ function has_http_route() { $this->get('/'); $route = $this->executionData->route(); $this->assertInstanceOf(HttpRoute::class, $route); } /** @test */ function has_null_route_when_route_is_not_matched() { $this->get('/not-found'); $route = $this->executionData->route(); $this->assertInstanceOf(NullRoute::class, $route); } /** @test */ function has_route_methods() { Route::get('route-a/{id}', function ($id) { return $id; }); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals(['GET', 'HEAD'], $route->data()->get('methods')); } /** @test */ function has_route_uri() { Route::get('route-a/{id}', function ($id) { return $id; }); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals('route-a/{id}', $route->data()->get('uri')); } /** @test */ function has_route_name() { Route::get('route-a/{id}', function ($id) { return $id; })->name('route.a.with.id'); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals('route.a.with.id', $route->data()->get('name')); } /** @test */ function has_route_middleware() { Route::get('route-a/{id}', function ($id) { return $id; })->middleware('auth'); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals(['auth'], $route->data()->get('middleware')); } /** @test */ function has_route_parameters() { Route::get('route-a/{id}', function ($id) { return $id; }); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals(['id' => '123'], $route->data()->get('parameters')); } /** @test */ function has_route_prefix() { Route::group(['prefix' => 'admin'], function () { Route::get('route-a/{id}', function ($id) { return $id; }); }); $this->get('/admin/route-a/123'); $route = $this->executionData->route(); $this->assertEquals('admin', $route->data()->get('prefix')); } /** @test */ function has_route_closure_action() { $uses = function (DummyClassA $a, DummyFormRequest $request) { return $request->get('id'); }; $action = new ReflectionFunction($uses); Route::get('route-a/{id}', $uses); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertStringContainsString( 'LaravelHttpExecutionTest.php:' . $action->getStartLine() . '-' . $action->getEndLine(), $route->data()->get('uses')['closure'] ); $this->assertEquals( DummyFormRequest::class, $route->data()->get('uses')['form_request'] ); } /** @test */ function has_route_controller_action() { Route::get('route-a/{id}', '\JKocik\Laravel\Profiler\Tests\Support\Fixtures\DummyController@dummyAction'); $action = new ReflectionMethod(DummyController::class, 'dummyAction'); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertStringContainsString( 'DummyController@dummyAction:' . $action->getStartLine() . '-' . $action->getEndLine(), $route->data()->get('uses')['controller'] ); $this->assertEquals( DummyFormRequest::class, $route->data()->get('uses')['form_request'] ); } /** @test */ function has_route_without_form_request_if_form_request_is_not_defined() { $uses = function ($id) { return $id; }; Route::get('route-a/{id}', $uses); $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals('', $route->data()->get('uses')['form_request']); } /** @test */ function has_route_with_not_existing_controller() { Route::get('route-a/{id}', '\JKocik\Laravel\Profiler\Tests\Support\Fixtures\NotExistingController@dummyAction'); $this->tapLaravelVersionTill(5.2, function () { $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertInstanceOf(NullRoute::class, $route); }); $this->tapLaravelVersionBetween(5.3, 5.3, function () { try { $this->get('/route-a/123'); } catch (ReflectionException $e) { $this->assertTrue(true); } }); $this->tapLaravelVersionFrom(5.4, function () { $this->get('/route-a/123'); $route = $this->executionData->route(); $this->assertEquals([], $route->data()->get('uses')); }); } /** @test */ function has_http_session() { $this->get('/'); $session = $this->executionData->session(); $this->assertInstanceOf(HttpSession::class, $session); } /** @test */ function has_http_session_data() { $this->withSession([ 'abc' => 123, 'xyz' => 789, ])->get('/'); $session = $this->executionData->session(); $this->assertEquals(123, $session->data()->get('abc')); $this->assertEquals(789, $session->data()->get('xyz')); } /** @test */ function has_http_response() { $this->get('/'); $response = $this->executionData->response(); $this->assertInstanceOf(HttpResponse::class, $response); } /** @test */ function has_response_status() { $this->get('/i-can-not-find-that-page'); $response = $this->executionData->response(); $this->assertEquals(404, $response->meta()->get('status')); $this->assertEquals('Not Found', $response->meta()->get('status_text')); } /** @test */ function can_have_response_unknown_status() { Route::get('unknown', function () { abort(419); }); $this->get('/unknown'); $response = $this->executionData->response(); $this->assertEquals(419, $response->meta()->get('status')); $this->assertEquals('unknown status', $response->meta()->get('status_text')); } /** @test */ function has_response_headers() { $this->get('/'); $response = $this->executionData->response(); $this->assertArrayHasKey('content-type', $response->data()->get('headers')); } /** @test */ function has_response_content() { $this->get('/'); $content = $this->executionData->content(); $this->assertCount(0, $content->meta()); $this->assertStringNotContainsString('HTTP/1.1 200 OK', $content->data()->get('content')); $this->assertStringContainsString('', $content->data()->get('content')); $this->assertStringContainsString('', $content->data()->get('content')); } } ================================================ FILE: tests/Feature/LaravelNullExecutionTest.php ================================================ turnOffProcessors(); $this->executionData = $this->app->make(ExecutionData::class); } /** @test */ function has_null_request() { $request = $this->executionData->request(); $this->assertInstanceOf(NullRequest::class, $request); } /** @test */ function null_request_has_only_type() { $request = $this->executionData->request(); $this->assertTrue($request->meta()->has('type')); $this->assertNull($request->meta()->get('type')); $this->assertCount(1, $request->meta()); $this->assertCount(0, $request->data()); } /** @test */ function has_null_route() { $route = $this->executionData->route(); $this->assertInstanceOf(NullRoute::class, $route); } /** @test */ function null_route_is_empty() { $route = $this->executionData->route(); $this->assertCount(0, $route->meta()); $this->assertCount(0, $route->data()); } /** @test */ function has_null_session() { $session = $this->executionData->session(); $this->assertInstanceOf(NullSession::class, $session); } /** @test */ function null_session_is_empty() { $session = $this->executionData->session(); $this->assertCount(0, $session->meta()); $this->assertCount(0, $session->data()); } /** @test */ function has_null_server() { $server = $this->executionData->server(); $this->assertInstanceOf(NullServer::class, $server); } /** @test */ function null_server_is_empty() { $server = $this->executionData->server(); $this->assertCount(0, $server->meta()); $this->assertCount(0, $server->data()); } /** @test */ function has_null_response() { $response = $this->executionData->response(); $this->assertInstanceOf(NullResponse::class, $response); } /** @test */ function null_response_is_empty() { $response = $this->executionData->response(); $this->assertCount(0, $response->meta()); $this->assertCount(0, $response->data()); } /** @test */ function has_null_content() { $content = $this->executionData->content(); $this->assertInstanceOf(NullContent::class, $content); } /** @test */ function null_content_is_empty() { $content = $this->executionData->content(); $this->assertCount(0, $content->meta()); $this->assertCount(0, $content->data()); } } ================================================ FILE: tests/Feature/PerformanceTest.php ================================================ app->make(Timer::class); $timerB = $this->app->make(Timer::class); $this->assertInstanceOf(TimerService::class, $timerA); $this->assertSame($timerA, $timerB); } /** @test */ function disabled_profiler_has_singleton_null_timer() { putenv('PROFILER_ENABLED=false'); $_ENV['PROFILER_ENABLED'] = false; $this->app = $this->app(); $timerA = $this->app->make(Timer::class); $timerB = $this->app->make(Timer::class); $this->assertInstanceOf(NullTimerService::class, $timerA); $this->assertSame($timerA, $timerB); } /** @test */ function memory_is_singleton() { $memoryA = $this->app->make(Memory::class); $memoryB = $this->app->make(Memory::class); $this->assertInstanceOf(Memory::class, $memoryA); $this->assertSame($memoryA, $memoryB); } /** * @return void */ protected function tearDown(): void { parent::tearDown(); putenv('PROFILER_ENABLED'); unset($_ENV['PROFILER_ENABLED']); } } ================================================ FILE: tests/Feature/PerformanceTrackerTest.php ================================================ addFixturePerformanceProcessor(); } /** * @return void */ protected function addFixturePerformanceProcessor(): void { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.processors', [ PerformanceProcessor::class, ]); $app->singleton(PerformanceProcessor::class, function () { return new PerformanceProcessor(); }); }); } /** @test */ function has_laravel_total_execution_time() { $this->app->terminate(); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertTrue($processor->performance->has('timer')); $this->assertGreaterThan(0, $timer->milliseconds('laravel')); $this->assertEquals($timer->milliseconds('laravel'), $processor->performance->get('timer')['laravel']); } /** @test */ function has_booting_time() { $this->app->terminate(); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('boot')); $this->assertEquals($timer->milliseconds('boot'), $processor->performance->get('timer')['boot']); } /** @test */ function has_route_time() { $this->get('/'); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('route')); $this->assertEquals($timer->milliseconds('route'), $processor->performance->get('timer')['route']); } /** @test */ function has_setup_time_instead_of_route_when_testing() { $this->tapLaravelVersionTill(6, function () { putenv('APP_ENV=testing'); $_ENV['APP_ENV'] = 'testing'; $this->app = $this->app(); $this->addFixturePerformanceProcessor(); $this->get('/'); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('setup')); $this->assertEquals($timer->milliseconds('setup'), $processor->performance->get('timer')['setup']); }); $this->tapLaravelVersionFrom(7, function () { $this->assertTrue(true); }); } /** @test */ function has_handle_request_time() { $this->get('/'); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('request')); $this->assertEquals($timer->milliseconds('request'), $processor->performance->get('timer')['request']); } /** @test */ function has_send_response_and_terminate_time() { $this->get('/'); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('response')); $this->assertEquals($timer->milliseconds('response'), $processor->performance->get('timer')['response']); } /** @test */ function has_console_time() { $this->app->make(Kernel::class)->registerCommand(new DummyCommand(0)); Artisan::call('dummy-command'); $this->app->terminate(); $timer = $this->app->make(Timer::class); $processor = $this->app->make(PerformanceProcessor::class); $this->assertGreaterThan(0, $timer->milliseconds('command')); $this->assertEquals($timer->milliseconds('command'), $processor->performance->get('timer')['command']); } /** @test */ function has_memory_peak() { $this->app->terminate(); $processor = $this->app->make(PerformanceProcessor::class); $this->assertEquals(PHPMock::MEMORY_USAGE, $processor->performance->get('memory')['peak']); } /** * @return void */ protected function tearDown(): void { parent::tearDown(); putenv('APP_ENV=local'); unset($_ENV['APP_ENV']); } } ================================================ FILE: tests/Feature/RegisterProfilerTest.php ================================================ timer = $timer; $this->dataTracker = $dataTracker; $this->dataProcessor = $dataProcessor; } public function register(): void { Event::listen(ProfilerBound::class, function () { $this->app->singleton(Timer::class, function () { return $this->timer; }); $this->app->singleton(DataTracker::class, function () { return $this->dataTracker; }); $this->app->singleton(DataProcessor::class, function () { return $this->dataProcessor; }); }); parent::register(); } }; $app->afterBootstrapping(RegisterProviders::class, function () use ($app, $provider) { $app->register($provider); }); $app->make(Kernel::class)->bootstrap(); } /** @test */ function loads_profiler_config_file() { $config = $this->app->make('config'); $this->assertTrue($config->has('profiler')); } /** @test */ function allows_config_file_to_be_published() { $this->assertArrayHasKey( ServiceProvider::profilerConfigPath(), ServiceProvider::pathsToPublish() ); } /** @test */ function profiler_is_enabled_by_default() { putenv('APP_ENV=test-profiler'); $_ENV['APP_ENV'] = 'test-profiler'; $this->app = $this->app(); $config = $this->app->make('config'); $this->assertTrue($config->get('profiler.enabled')); $this->assertInstanceOf(LaravelProfiler::class, $this->app->make(Profiler::class)); } /** @test */ function profiler_can_be_disabled_in_env_file() { putenv('APP_ENV=test-profiler'); putenv('PROFILER_ENABLED=false'); $_ENV['APP_ENV'] = 'test-profiler'; $_ENV['PROFILER_ENABLED'] = false; $this->app = $this->app(); $config = $this->app->make('config'); $this->assertFalse($config->get('profiler.enabled')); $this->assertInstanceOf(DisabledProfiler::class, $this->app->make(Profiler::class)); } /** @test */ function profiler_can_be_disabled_in_config_file_for_specific_environment() { putenv('APP_ENV=local'); putenv('PROFILER_ENABLED=true'); $_ENV['APP_ENV'] = 'local'; $_ENV['PROFILER_ENABLED'] = true; $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.enabled_overrides', ['local' => false]); }); $this->assertInstanceOf(DisabledProfiler::class, $this->app->make(Profiler::class)); } /** @test */ function enabled_profiler_tracks_laravel() { $timer = Mockery::spy(Timer::class); $dataTracker = Mockery::spy(DataTracker::class); $dataProcessor = Mockery::spy(DataProcessor::class); $httpRequestHandledListener = Mockery::spy(HttpRequestHandledListener::class); $consoleCommandFinishedListener = Mockery::spy(ConsoleCommandFinishedListener::class); $this->app = $this->appBeforeBootstrap(); $this->app->instance(HttpRequestHandledListener::class, $httpRequestHandledListener); $this->app->instance(ConsoleCommandFinishedListener::class, $consoleCommandFinishedListener); $this->registerServiceProviderWith($this->app, $timer, $dataTracker, $dataProcessor); $this->app->terminate(); $this->assertInstanceOf(LaravelProfiler::class, $this->app->make(Profiler::class)); $this->assertSame($timer, $this->app->make(Timer::class)); $this->assertSame($dataTracker, $this->app->make(DataTracker::class)); $dataTracker->shouldHaveReceived('track'); $dataTracker->shouldHaveReceived('terminate'); $this->assertSame($dataProcessor, $this->app->make(DataProcessor::class)); $dataProcessor->shouldHaveReceived('process'); $httpRequestHandledListener->shouldHaveReceived('listen'); $consoleCommandFinishedListener->shouldHaveReceived('listen'); } /** @test */ function disabled_profiler_does_not_track_laravel() { putenv('PROFILER_ENABLED=false'); $_ENV['PROFILER_ENABLED'] = false; $timer = Mockery::spy(Timer::class); $dataTracker = Mockery::spy(DataTracker::class); $dataProcessor = Mockery::spy(DataProcessor::class); $httpRequestHandledListener = Mockery::spy(HttpRequestHandledListener::class); $consoleCommandFinishedListener = Mockery::spy(ConsoleCommandFinishedListener::class); $this->app = $this->appBeforeBootstrap(); $this->app->instance(HttpRequestHandledListener::class, $httpRequestHandledListener); $this->app->instance(ConsoleCommandFinishedListener::class, $consoleCommandFinishedListener); $this->registerServiceProviderWith($this->app, $timer, $dataTracker, $dataProcessor); $this->app->terminate(); $this->assertInstanceOf(DisabledProfiler::class, $this->app->make(Profiler::class)); $this->assertSame($timer, $this->app->make(Timer::class)); $this->assertSame($dataTracker, $this->app->make(DataTracker::class)); $dataTracker->shouldNotHaveReceived('track'); $dataTracker->shouldNotHaveReceived('terminate'); $this->assertSame($dataProcessor, $this->app->make(DataProcessor::class)); $dataProcessor->shouldNotHaveReceived('process'); $httpRequestHandledListener->shouldNotHaveReceived('listen'); $consoleCommandFinishedListener->shouldNotHaveReceived('listen'); } /** @test */ function enabled_profiler_is_booted_before_all_service_providers_are_booted() { $eventsExecuted = 0; $this->app = $this->appBeforeBootstrap(); $this->app->afterBootstrapping(RegisterProviders::class, function () use (&$eventsExecuted) { $this->app->register(ServiceProvider::class); $this->assertFalse($this->app->resolved(Timer::class)); $eventsExecuted++; }); $this->app->booting(function () use (&$eventsExecuted) { $this->assertInstanceOf(TimerService::class, $this->app->make(Timer::class)); $eventsExecuted++; }); $this->app->make(Kernel::class)->bootstrap(); $this->assertEquals(2, $eventsExecuted); } /** @test */ function disabled_profiler_is_booted_before_all_service_providers_are_booted() { putenv('PROFILER_ENABLED=false'); $_ENV['PROFILER_ENABLED'] = false; $eventsExecuted = 0; $this->app = $this->appBeforeBootstrap(); $this->app->afterBootstrapping(RegisterProviders::class, function () use (&$eventsExecuted) { $this->app->register(ServiceProvider::class); $this->assertFalse($this->app->resolved(Timer::class)); $eventsExecuted++; }); $this->app->booting(function () use (&$eventsExecuted) { $this->assertInstanceOf(NullTimerService::class, $this->app->make(Timer::class)); $eventsExecuted++; }); $this->app->make(Kernel::class)->bootstrap(); $this->assertEquals(2, $eventsExecuted); } /** @test */ function enabled_profiler_registers_terminating_callback_after_all_service_providers_are_booted() { $executedBefore = false; $this->app = $this->appBeforeBootstrap(); $this->app->afterBootstrapping(RegisterProviders::class, function () use (&$order) { $this->app->register(ServiceProvider::class); $this->app->register(new class($this->app) extends \Illuminate\Support\ServiceProvider { public function register() {} public function boot() { $this->app->terminating(function () { event('another-executed-before', [new \stdClass()]); }); } }); }); $this->app->make(Kernel::class)->bootstrap(); $this->turnOffProcessors(); Event::listen('another-executed-before', function () use (&$executedBefore) { $executedBefore = true; }); Event::listen(Terminating::class, function () use (&$executedBefore) { $this->assertTrue($executedBefore); }); $this->app->terminate(); } /** * @return void */ protected function tearDown(): void { parent::tearDown(); putenv('APP_ENV=local'); putenv('PROFILER_ENABLED'); unset($_ENV['APP_ENV']); unset($_ENV['PROFILER_ENABLED']); } } ================================================ FILE: tests/Feature/RunningProfilerTest.php ================================================ app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.trackers', [ TrackerA::class, TrackerB::class, ]); $app->make('config')->set('profiler.processors', [ ProcessorA::class, ProcessorB::class, ]); $app->singleton(ProcessorA::class, function () { return new ProcessorA(); }); $app->singleton(ProcessorB::class, function () { return new ProcessorB(); }); }); $processorA = $this->app->make(ProcessorA::class); $processorB = $this->app->make(ProcessorB::class); $this->assertNotEquals('meta-value', $processorA->meta->get('meta-key')); $this->assertNotEquals('meta-value', $processorB->meta->get('meta-key')); $this->assertNotEquals('data-value', $processorA->data->get('data-key')); $this->assertNotEquals('data-value', $processorB->data->get('data-key')); $this->app->terminate(); $this->assertEquals('meta-value', $processorA->meta->get('meta-key')); $this->assertEquals('meta-value', $processorB->meta->get('meta-key')); $this->assertEquals('data-value', $processorA->data->get('data-key')); $this->assertEquals('data-value', $processorB->data->get('data-key')); } /** @test */ function collected_data_are_broadcast_by_default() { $config = $this->app->make(ConfigService::class); $client = Mockery::mock(Client::class); $client->shouldReceive('request')->withArgs(function ($arg1, $arg2, $arg3) use ($config) { return $arg1 === 'POST' && $arg2 === $config->serverHttpConnectionUrl() && is_array($arg3['json']['meta']) && is_array($arg3['json']['data']); })->once()->andReturn(new Response()); $this->app->instance(Client::class, $client); $this->app->terminate(); $this->assertSame($client, $this->app->make(Client::class)); } /** @test */ function collected_data_are_not_processed_for_debugbar() { $client = Mockery::mock(Client::class); $client->shouldNotReceive('request'); $this->app->instance(Client::class, $client); $this->get('_debugbar/assets/javascript'); } /** @test */ function collected_data_are_not_processed_for_telescope() { $client = Mockery::mock(Client::class); $client->shouldNotReceive('request'); $this->app->instance(Client::class, $client); $this->get('telescope/telescope-api/models'); } /** @test */ function processors_exceptions_are_caught_and_logged_if_configured() { $processor = Mockery::mock(ProcessorA::class); $processor->shouldReceive('process')->once(); $this->app = $this->appWith(function (Application $app) use ($processor) { $app->make('config')->set('profiler.handle_exceptions', 1); $app->make('config')->set('profiler.processors', [ BroadcastingProcessor::class, BroadcastingProcessor::class, ProcessorA::class, ]); $app->singleton(ProcessorA::class, function () use ($processor) { return $processor; }); }); Log::shouldReceive('error') ->times(2) ->with(Exception::class); $this->app->terminate(); } /** @test */ function processors_exceptions_are_thrown_if_configured() { $processor = Mockery::spy(ProcessorA::class); $this->app = $this->appWith(function (Application $app) use ($processor) { $app->make('config')->set('profiler.handle_exceptions', 666); $app->make('config')->set('profiler.processors', [ BroadcastingProcessor::class, ProcessorA::class, ]); $app->singleton(ProcessorA::class, function () use ($processor) { return $processor; }); }); try { $this->app->terminate(); } catch (Exception $e) { $processor->shouldNotHaveReceived('process'); return; } $this->fail('Exception should be thrown'); } /** @test */ function processors_exceptions_are_caught_and_not_logged_if_configured() { $processor = Mockery::mock(ProcessorA::class); $processor->shouldReceive('process')->once(); $this->app = $this->appWith(function (Application $app) use ($processor) { $app->make('config')->set('profiler.handle_exceptions', 0); $app->make('config')->set('profiler.processors', [ BroadcastingProcessor::class, BroadcastingProcessor::class, ProcessorA::class, ]); $app->singleton(ProcessorA::class, function () use ($processor) { return $processor; }); }); Log::shouldReceive('error') ->times(0); $this->app->terminate(); } /** @test */ function processors_exceptions_are_caught_and_not_logged_if_configured_incorrectly() { $processor = Mockery::mock(ProcessorA::class); $processor->shouldReceive('process')->once(); $this->app = $this->appWith(function (Application $app) use ($processor) { $app->make('config')->set('profiler.handle_exceptions', -1); $app->make('config')->set('profiler.processors', [ BroadcastingProcessor::class, BroadcastingProcessor::class, ProcessorA::class, ]); $app->singleton(ProcessorA::class, function () use ($processor) { return $processor; }); }); Log::shouldReceive('error') ->times(0); $this->app->terminate(); } } ================================================ FILE: tests/Feature/TrackersResetTest.php ================================================ assertFalse($fired); profiler_reset(); $this->assertTrue($fired); } /** @test */ function profiler_reset_function_can_be_executed_even_profiler_is_disabled() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.enabled', false); }); $fired = false; Event::listen(ResetTrackers::class, function () use (&$fired) { $fired = true; }); $this->assertFalse($fired); profiler_reset(); $this->assertTrue($fired); } } ================================================ FILE: tests/Feature/TrackersTest.php ================================================ app->make('config')->get('profiler.trackers'); $applicationTracker = Mockery::mock(ApplicationTracker::class); $applicationTracker->shouldReceive('terminate')->once(); $applicationTracker->shouldReceive('meta')->once()->andReturn(collect()); $applicationTracker->shouldReceive('data')->once()->andReturn(collect()); $this->app = $this->appWith(function (Application $app) use ($applicationTracker) { $app->make('config')->set('profiler.trackers', []); $app->make('config')->set('profiler.processors', []); $app->singleton(ApplicationTracker::class, function () use ($applicationTracker) { return $applicationTracker; }); }); $this->app->terminate(); $this->assertNotContains(ApplicationTracker::class, $defaultTrackers); $this->assertSame($applicationTracker, $this->app->make(ApplicationTracker::class)); } /** @test */ function request_tracker_is_required() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $requestTracker = Mockery::mock(RequestTracker::class); $requestTracker->shouldReceive('terminate')->once(); $requestTracker->shouldReceive('meta')->once()->andReturn(collect()); $requestTracker->shouldReceive('data')->once()->andReturn(collect()); $this->app = $this->appWith(function (Application $app) use ($requestTracker) { $app->make('config')->set('profiler.trackers', []); $app->make('config')->set('profiler.processors', []); $app->singleton(RequestTracker::class, function () use ($requestTracker) { return $requestTracker; }); }); $this->app->terminate(); $this->assertNotContains(RequestTracker::class, $defaultTrackers); $this->assertSame($requestTracker, $this->app->make(RequestTracker::class)); } /** @test */ function response_tracker_is_required() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $responseTracker = Mockery::mock(ResponseTracker::class); $responseTracker->shouldReceive('terminate')->once(); $responseTracker->shouldReceive('meta')->once()->andReturn(collect()); $responseTracker->shouldReceive('data')->once()->andReturn(collect()); $this->app = $this->appWith(function (Application $app) use ($responseTracker) { $app->make('config')->set('profiler.trackers', []); $app->make('config')->set('profiler.processors', []); $app->singleton(ResponseTracker::class, function () use ($responseTracker) { return $responseTracker; }); }); $this->app->terminate(); $this->assertNotContains(ResponseTracker::class, $defaultTrackers); $this->assertSame($responseTracker, $this->app->make(ResponseTracker::class)); } /** @test */ function performance_tracker_is_required() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $performanceTracker = Mockery::mock(PerformanceTracker::class); $performanceTracker->shouldReceive('terminate')->once(); $performanceTracker->shouldReceive('meta')->once()->andReturn(collect()); $performanceTracker->shouldReceive('data')->once()->andReturn(collect()); $this->app = $this->appWith(function (Application $app) use ($performanceTracker) { $app->make('config')->set('profiler.trackers', []); $app->make('config')->set('profiler.processors', []); $app->singleton(PerformanceTracker::class, function () use ($performanceTracker) { return $performanceTracker; }); }); $this->app->terminate(); $this->assertNotContains(PerformanceTracker::class, $defaultTrackers); $this->assertSame($performanceTracker, $this->app->make(PerformanceTracker::class)); } /** @test */ function paths_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(PathsTracker::class, $defaultTrackers); } /** @test */ function service_providers_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ServiceProvidersTracker::class, $defaultTrackers); } /** @test */ function bindings_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(BindingsTracker::class, $defaultTrackers); } /** @test */ function config_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ConfigTracker::class, $defaultTrackers); } /** @test */ function session_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(SessionTracker::class, $defaultTrackers); } /** @test */ function route_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(RouteTracker::class, $defaultTrackers); } /** @test */ function views_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ViewsTracker::class, $defaultTrackers); } /** @test */ function events_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(EventsTracker::class, $defaultTrackers); } /** @test */ function queries_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(QueriesTracker::class, $defaultTrackers); } /** @test */ function server_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ServerTracker::class, $defaultTrackers); } /** @test */ function content_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ContentTracker::class, $defaultTrackers); } /** @test */ function auth_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(AuthTracker::class, $defaultTrackers); } /** @test */ function exception_tracker_is_enabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertContains(ExceptionTracker::class, $defaultTrackers); } /** @test */ function redis_tracker_is_disabled_by_default() { $defaultTrackers = $this->app->make('config')->get('profiler.trackers'); $this->assertNotContains(RedisTracker::class, $defaultTrackers); } } ================================================ FILE: tests/Support/Fixtures/DummyClassA.php ================================================ testExitCode = $testExitCode; } /** * @var string */ protected $signature = 'dummy-command {user?} {--number=}'; /** * @var string */ protected $description = 'Display dummy message'; /** * @return void */ public function handle() { $this->comment('Dummy Command Message'); return $this->testExitCode; } } ================================================ FILE: tests/Support/Fixtures/DummyContractA.php ================================================ get('id'); } } ================================================ FILE: tests/Support/Fixtures/DummyEventA.php ================================================ user = $user; $this->usersA = $usersA; $this->usersB = $usersB; $this->dummyClasses = $dummyClasses; $this->dataA = $dataA; $this->dataB = $dataB; } } ================================================ FILE: tests/Support/Fixtures/DummyException.php ================================================ 'required', ]; } } ================================================ FILE: tests/Support/Fixtures/PerformanceProcessor.php ================================================ performance = $dataTracker->data()->get('performance'); } } ================================================ FILE: tests/Support/Fixtures/ProcessorA.php ================================================ meta = new Collection(); $this->data = new Collection(); } /** * @param DataTracker $dataTracker * @return void */ public function process(DataTracker $dataTracker): void { $this->data = $dataTracker->data(); $this->meta = $dataTracker->meta(); } } ================================================ FILE: tests/Support/Fixtures/ProcessorB.php ================================================ meta->put('meta-key', 'meta-value'); } /** * @return void */ public function terminate(): void { } } ================================================ FILE: tests/Support/Fixtures/TrackerB.php ================================================ data->put('data-key', 'data-value'); } } ================================================ FILE: tests/Support/Fixtures/dummy-view-a.blade.php ================================================ ================================================ FILE: tests/Support/Fixtures/dummy-view-b.blade.php ================================================ ================================================ FILE: tests/Support/Framework.php ================================================ version()); } /** * @return string */ public function dir(): string { return "laravel-{$this->versionWithoutDot()}"; } /** * @return string */ public function composerPackage(): string { return "laravel/laravel:{$this->version()}.*"; } } ================================================ FILE: tests/Support/PHPMock.php ================================================ addMock(self::timeMock()->build()); $phpMock->addMock(self::passthruMock()->build()); $phpMock->addMock(self::phpVersionMock()->build()); $phpMock->addMock(self::memoryUsageMock()->build()); return $phpMock; } /** * @return MockBuilder */ protected static function timeMock(): MockBuilder { return (new MockBuilder()) ->setNamespace('JKocik\Laravel\Profiler\Trackers') ->setName('time') ->setFunctionProvider(new FixedValueFunction(self::TIME)); } /** * @return MockBuilder */ protected static function passthruMock(): MockBuilder { return (new MockBuilder()) ->setNamespace('JKocik\Laravel\Profiler\Console') ->setName('passthru') ->setFunctionProvider(new FixedValueFunction('')); } /** * @return MockBuilder */ protected static function phpVersionMock(): MockBuilder { return (new MockBuilder()) ->setNamespace('JKocik\Laravel\Profiler\Trackers') ->setName('phpversion') ->setFunctionProvider(new FixedValueFunction(self::PHP_VERSION)); } /** * @return MockBuilder */ protected static function memoryUsageMock(): MockBuilder { return (new MockBuilder()) ->setNamespace('JKocik\Laravel\Profiler\Services\Performance') ->setName('memory_get_peak_usage') ->setFunctionProvider(new FixedValueFunction(self::MEMORY_USAGE)); } } ================================================ FILE: tests/Support/TestListener.php ================================================ versionPrinted) { $this->printVersion($test); } } /** * @return void */ protected function printVersion(Test $test): void { fwrite(STDERR, "APP: {$test->appBeforeBootstrap()->version()}\n"); $this->versionPrinted = true; } } ================================================ FILE: tests/TestCase.php ================================================ dir() . '/bootstrap/app.php'; } /** * @return void */ protected function setUp(): void { $this->enablePhpMock(); $this->app = $this->app(); } /** * @return void */ protected function tearDown(): void { $this->disablePhpMock(); } /** * @return Application */ protected function app(): Application { $app = $this->appBeforeBootstrap(); $app->afterBootstrapping(RegisterProviders::class, function () use ($app) { $app->register(ServiceProvider::class); }); $app->make(Kernel::class)->bootstrap(); return $app; } /** * @param Closure $beforeServiceProvider * @return Application */ protected function appWith(Closure $beforeServiceProvider): Application { $app = $this->appBeforeBootstrap(); $app->afterBootstrapping(RegisterProviders::class, function () use ($app, $beforeServiceProvider) { $beforeServiceProvider($app); $app->register(ServiceProvider::class); }); $app->make(Kernel::class)->bootstrap(); return $app; } /** * @return string */ protected function userClass(): string { return $this->app->make('config')->get('auth.providers.users.model'); } /** * @return object */ protected function factoryUser(): object { if (function_exists('factory')) { return factory($this->userClass()); } return $this->userClass()::factory(); } /** * @param array $attributes * @return Model */ protected function user(array $attributes = []): Model { $userClass = $this->app->make('config')->get('auth.providers.users.model'); return new $userClass($attributes); } /** * @return void */ protected function turnOffProcessors(): void { $this->app->make('config')->set('profiler.processors', []); } /** * @return void */ protected function enablePhpMock(): void { $this->phpMock = PHPMock::phpMock(); $this->phpMock->enable(); } /** * @return void */ protected function disablePhpMock(): void { $this->phpMock->disable(); } /** * @param float $version * @param Closure $callback * @return void */ protected function tapLaravelVersionTill(float $version, Closure $callback): void { if (TESTS_FRAMEWORK_VERSION <= $version) { $callback->__invoke(); } } /** * @param float $version * @param Closure $callback * @return void */ protected function tapLaravelVersionFrom(float $version, Closure $callback): void { if (TESTS_FRAMEWORK_VERSION >= $version) { $callback->__invoke(); } } /** * @param float $versionFrom * @param float $versionTill * @param Closure $callback * @return void */ protected function tapLaravelVersionBetween(float $versionFrom, float $versionTill, Closure $callback): void { if (TESTS_FRAMEWORK_VERSION >= $versionFrom && TESTS_FRAMEWORK_VERSION <= $versionTill) { $callback->__invoke(); } } } ================================================ FILE: tests/Unit/LaravelExecution/ConsoleFinishedRequestTest.php ================================================ assertNull($consoleFinishedRequest->meta()->get('path')); } } ================================================ FILE: tests/Unit/LaravelExecution/ConsoleStartingRequestTest.php ================================================ assertEquals('command-starting', $consoleStartingRequest->meta()->get('type')); $this->assertCount(0, $consoleStartingRequest->data()); } } ================================================ FILE: tests/Unit/LaravelExecution/ConsoleStartingResponseTest.php ================================================ assertNull($consoleStartingResponse->meta()->get('type')); $this->assertCount(0, $consoleStartingResponse->data()); } } ================================================ FILE: tests/Unit/Services/ConfigServiceTest.php ================================================ app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.trackers', [ TrackerA::class, TrackerB::class, ]); }); $trackers = $this->app->make(ConfigService::class)->trackers(); $this->assertTrue($trackers->contains(TrackerA::class)); $this->assertTrue($trackers->contains(TrackerB::class)); } /** @test */ function returns_processors() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.processors', [ ProcessorA::class, ProcessorB::class, ]); }); $processors = $this->app->make(ConfigService::class)->processors(); $this->assertTrue($processors->contains(ProcessorA::class)); $this->assertTrue($processors->contains(ProcessorB::class)); } /** @test */ function returns_server_http_connection_url() { $url = $this->app->make(ConfigService::class)->serverHttpConnectionUrl(); $this->assertEquals('http://localhost:8099', $url); } /** @test */ function returns_server_http_port() { $port = $this->app->make(ConfigService::class)->serverHttpPort(); $this->assertEquals('8099', $port); } /** @test */ function returns_server_sockets_port() { $port = $this->app->make(ConfigService::class)->serverSocketsPort(); $this->assertEquals('1901', $port); } /** @test */ function returns_handle_exceptions() { $handleDefault = $this->app->make(ConfigService::class)->handleExceptions( LogService::HANDLE_EXCEPTIONS_LOG ); $this->assertTrue($handleDefault); } } ================================================ FILE: tests/Unit/Services/HelpersTest.php ================================================ assertTrue(true); } } ================================================ FILE: tests/Unit/Services/ParamsServiceTest.php ================================================ app->make(ParamsService::class); $this->assertEquals(1, $paramsService->resolve(1)); $this->assertEquals('something', $paramsService->resolve('something')); $this->assertEquals(['a', 'b'], $paramsService->resolve(['a', 'b'])); $this->assertEquals(true, $paramsService->resolve(true)); $this->assertEquals(false, $paramsService->resolve(false)); } /** @test */ function returns_array_of_object_param_if_is_available() { $paramsService = $this->app->make(ParamsService::class); $user = $this->user(['email' => 'a@example.com']); $this->assertEquals($user->toArray(), $paramsService->resolve($user)); } /** @test */ function returns_class_name_of_object_param_if_array_is_not_available() { $paramsService = $this->app->make(ParamsService::class); $dummyClassA = new DummyClassA(); $this->assertEquals(DummyClassA::class, $paramsService->resolve($dummyClassA)); } /** @test */ function can_resolve_array_of_objects() { $paramsService = $this->app->make(ParamsService::class); $dummyClassA = new DummyClassA(); $dummyClassB = new DummyClassB(); $this->assertEquals([ DummyClassA::class, DummyClassB::class, ], $paramsService->resolve([$dummyClassA, $dummyClassB])); } } ================================================ FILE: tests/Unit/Services/Performance/TimerServiceTest.php ================================================ app->make(TimerService::class); $timer->start('testA'); $timer->finish('testA'); $timer->start('testB'); usleep(10 * 1000); $timer->finish('testB'); $timer->start('testC'); usleep(200 * 1000); $timer->finish('testC'); $this->assertGreaterThanOrEqual(0, $timer->milliseconds('testA')); $this->assertGreaterThanOrEqual(10, $timer->milliseconds('testB')); $this->assertGreaterThanOrEqual(200, $timer->milliseconds('testC')); } /** @test */ function counts_laravel_execution_time() { $appL = Mockery::mock(Application::class); $appL->shouldReceive('environment')->with('testing')->andReturn(false)->once(); $appT = Mockery::mock(Application::class); $appT->shouldReceive('environment')->with('testing')->andReturn(true)->once(); $timerA1 = new TimerService($appL); $timerB1 = new TimerService($appT); $timerA2 = new TimerService($appL); $timerB2 = new TimerService($appT); $millisecondsWithLaravelStartDefined = \microtime(true) * 1000; $timerA1->startLaravel(); $timerA1->finishLaravel(); $timerB1->startLaravel(); $timerB1->finishLaravel(); define('LARAVEL_START', 0); $timerA2->startLaravel(); $timerA2->finishLaravel(); $timerB2->startLaravel(); $timerB2->finishLaravel(); $this->assertLessThan($millisecondsWithLaravelStartDefined, $timerA1->milliseconds('laravel')); $this->assertGreaterThanOrEqual($millisecondsWithLaravelStartDefined, $timerA2->milliseconds('laravel')); $this->assertLessThan($millisecondsWithLaravelStartDefined, $timerB1->milliseconds('laravel')); $this->assertLessThan($millisecondsWithLaravelStartDefined, $timerB2->milliseconds('laravel')); } /** @test */ function returns_all_finished_times() { $timer = $this->app->make(TimerService::class); $timer->start('testA'); $timer->finish('testA'); $timer->start('testB'); $timer->finish('testB'); $timer->start('testC'); $this->assertArrayHasKey('testA', $timer->all()); $this->assertArrayHasKey('testB', $timer->all()); $this->assertArrayNotHasKey('testC', $timer->all()); $this->assertEquals($timer->milliseconds('testA'), $timer->all()['testA']); $this->assertEquals($timer->milliseconds('testB'), $timer->all()['testB']); } /** @test */ function returns_negative_value_when_timer_for_specific_label_is_not_completed() { $timer = $this->app->make(TimerService::class); $timer->start('testA'); $this->assertEquals(-1, $timer->milliseconds('testA')); } /** @test */ function allows_custom_timer_for_application_developers_but_keep_it_in_different_namespace() { $timer = $this->app->make(TimerService::class); $timer->startCustom('testA'); $timer->finishCustom('testA'); $this->assertGreaterThan(0, $timer->millisecondsCustom('testA')); $this->assertNotEquals($timer->milliseconds('testA'), $timer->millisecondsCustom('testA')); } /** @test */ function returns_empty_values_for_null_timer() { $timer = new NullTimerService(); $timer->startCustom('testA'); $timer->finishCustom('testA'); $this->assertEquals(-1, $timer->millisecondsCustom('testA')); } /** @test */ function the_same_custom_timer_can_not_be_started_more_than_once() { try { $timer = $this->app->make(TimerService::class); $timer->startCustom('testA'); $timer->startCustom('testA'); } catch (TimerException $e) { $this->assertTrue(true); return; } $this->fail('TimerException should be thrown'); } /** @test */ function the_same_custom_timer_can_not_be_finished_more_than_once() { try { $timer = $this->app->make(TimerService::class); $timer->startCustom('testA'); $timer->finishCustom('testA'); $timer->finishCustom('testA'); } catch (TimerException $e) { $this->assertTrue(true); return; } $this->fail('TimerException should be thrown'); } /** @test */ function custom_timer_can_not_be_finished_if_is_not_started_before() { try { $timer = $this->app->make(TimerService::class); $timer->finishCustom('testA'); } catch (TimerException $e) { $this->assertTrue(true); return; } $this->fail('TimerException should be thrown'); } /** @test */ function custom_timer_is_used_by_helper_functions() { profiler_start('testA'); profiler_finish('testA'); $timer = $this->app->make(Timer::class); $this->assertGreaterThan(0, $timer->millisecondsCustom('testA')); } /** @test */ function custom_timer_functions_exceptions_are_caught_and_logged_if_configured() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.handle_exceptions', 1); }); Log::shouldReceive('error') ->times(2) ->with(TimerException::class); profiler_start('testA'); profiler_start('testA'); profiler_finish('testB'); } /** @test */ function custom_timer_functions_exceptions_are_thrown_if_configured() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.handle_exceptions', 666); }); Log::shouldReceive('error') ->times(0) ->with(TimerException::class); try { profiler_start('testA'); profiler_start('testA'); } catch (TimerException $e) { $this->assertTrue(true); return; } $this->fail('TimerException should be thrown'); } /** @test */ function custom_timer_functions_exceptions_are_caught_and_not_logged_if_configured() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.handle_exceptions', 0); }); Log::shouldReceive('error') ->times(0); profiler_start('testA'); profiler_start('testA'); profiler_finish('testB'); } /** @test */ function custom_timer_functions_exceptions_are_caught_and_not_logged_if_configured_incorrectly() { $this->app = $this->appWith(function (Application $app) { $app->make('config')->set('profiler.handle_exceptions', -1); }); Log::shouldReceive('error') ->times(0); profiler_start('testA'); profiler_start('testA'); profiler_finish('testB'); } } ================================================ FILE: tests/Unit/Trackers/ApplicationTrackerTest.php ================================================ app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('execution_at')); $this->assertEquals(PHPMock::TIME, $tracker->meta()->get('execution_at')); } /** @test */ function has_profiler_single_execution_id() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('id')); $this->assertRegExp('/^[a-z0-9]{32}$/', $tracker->meta()->get('id')); } /** @test */ function profiler_single_execution_id_is_unique() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $firstId = $tracker->meta()->get('id'); $tracker->terminate(); $secondId = $tracker->meta()->get('id'); $this->assertNotEquals($firstId, $secondId); } /** @test */ function has_laravel_version() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('laravel_version')); $this->assertEquals($this->app->version(), $tracker->meta()->get('laravel_version')); } /** @test */ function has_php_version() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('php_version')); $this->assertEquals(PHPMock::PHP_VERSION, $tracker->meta()->get('php_version')); } /** @test */ function has_env() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('env')); $this->assertEquals('local', $tracker->meta()->get('env')); } /** @test */ function has_is_running_in_console() { $app = Mockery::mock(Application::class)->shouldIgnoreMissing(); $app->shouldReceive('runningInConsole')->once()->andReturn(false); $this->app->instance(Application::class, $app); $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $this->assertTrue($tracker->meta()->has('is_running_in_console')); $this->assertFalse($tracker->meta()->get('is_running_in_console')); } /** @test */ function has_locale() { $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $application = $tracker->data()->get('application'); $this->assertTrue($application->has('locale')); $this->assertEquals($this->app->getLocale(), $application->get('locale')); } /** @test */ function has_configuration_is_cached() { $app = Mockery::mock(Application::class)->shouldIgnoreMissing(); $app->shouldReceive('configurationIsCached')->once()->andReturn(true); $this->app->instance(Application::class, $app); $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $application = $tracker->data()->get('application'); $this->assertTrue($application->has('configuration_is_cached')); $this->assertTrue($application->get('configuration_is_cached')); } /** @test */ function has_routes_are_cached() { $app = Mockery::mock(Application::class)->shouldIgnoreMissing(); $app->shouldReceive('routesAreCached')->once()->andReturn(true); $this->app->instance(Application::class, $app); $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $application = $tracker->data()->get('application'); $this->assertTrue($application->has('routes_are_cached')); $this->assertTrue($application->get('routes_are_cached')); } /** @test */ function has_is_down_for_maintenance() { $app = Mockery::mock(Application::class)->shouldIgnoreMissing(); $app->shouldReceive('isDownForMaintenance')->once()->andReturn(true); $this->app->instance(Application::class, $app); $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $application = $tracker->data()->get('application'); $this->assertTrue($application->has('is_down_for_maintenance')); $this->assertTrue($application->get('is_down_for_maintenance')); } /** @test */ function has_should_skip_middleware() { $app = Mockery::mock(Application::class)->shouldIgnoreMissing(); $app->shouldReceive('shouldSkipMiddleware')->once()->andReturn(true); $this->app->instance(Application::class, $app); $tracker = $this->app->make(ApplicationTracker::class); $tracker->terminate(); $application = $tracker->data()->get('application'); $this->assertTrue($application->has('should_skip_middleware')); $this->assertTrue($application->get('should_skip_middleware')); } } ================================================ FILE: tests/Unit/Trackers/AuthTrackerTest.php ================================================ app->make(AuthTracker::class); $user = $this->factoryUser()->create(['email' => 'user@example.com']); Auth::login($user); $tracker->terminate(); $auth = $tracker->data()->get('auth'); $this->assertEquals($user->email, $auth->email); } /** @test */ function has_auth_user_even_user_is_logging_out() { $tracker = $this->app->make(AuthTracker::class); $user = $this->factoryUser()->create([ 'email' => 'login.me@example.com', ]); Auth::login($user); Auth::logout(); $tracker->terminate(); $auth = $tracker->data()->get('auth'); $this->assertEquals($user->email, $auth->email); } /** @test */ function has_null_auth_user_if_user_is_not_logged_in() { $tracker = $this->app->make(AuthTracker::class); $tracker->terminate(); $auth = $tracker->data()->get('auth'); $this->assertNull($auth); } } ================================================ FILE: tests/Unit/Trackers/BindingsTrackerTest.php ================================================ app->make(BindingsTracker::class); $tracker->terminate(); $bindings = $tracker->data()->get('bindings'); $this->assertNotNull($bindings); $this->assertCount(count($bindings), $this->app->getBindings()); $this->assertSame(0, $bindings->keys()[0]); $this->assertContains($bindings->first()['abstract'], array_keys($this->app->getBindings())); } /** @test */ function tracks_how_container_resolves_bindings() { $this->app->bind(DummyContractA::class, DummyClassA::class); $this->app->bind(DummyContractB::class, DummyClassB::class); $this->app->make(DummyContractB::class); $tracker = $this->app->make(BindingsTracker::class); $tracker->terminate(); $bindings = $tracker->data()->get('bindings'); $this->assertNull($bindings->where('abstract', DummyContractA::class)->first()['resolved']); $this->assertEquals(DummyClassB::class, $bindings->where('abstract', DummyContractB::class)->first()['resolved']); } } ================================================ FILE: tests/Unit/Trackers/ConfigTrackerTest.php ================================================ app->make(ConfigTracker::class); $tracker->terminate(); $config = $tracker->data()->get('config'); $this->assertNotNull($config); $this->assertEquals(collect($this->app->make('config')->all())->keys(), $config->keys()); } /** @test */ function has_hidden_secret_config_data() { config()->set('my-config.password', '1'); config()->set('my-config.next-config-level.password', '12'); config()->set('my-config.next-config-level.even-deeper.password', '123'); config()->set('my-config.PASSWORD', '1234'); config()->set('my-config.key', '12345'); config()->set('my-config.secret', '123456'); config()->set('my-config.value_password', '1234567'); config()->set('my-config.some_password_value', '12345678'); config()->set('my-config.password-value', '123456789'); $tracker = $this->app->make(ConfigTracker::class); $tracker->terminate(); $config = $tracker->data()->get('config')->toArray(); $this->assertEquals('*', $config['my-config']['password']); $this->assertEquals('**', $config['my-config']['next-config-level']['password']); $this->assertEquals('***', $config['my-config']['next-config-level']['even-deeper']['password']); $this->assertEquals('****', $config['my-config']['PASSWORD']); $this->assertEquals('*****', $config['my-config']['key']); $this->assertEquals('******', $config['my-config']['secret']); $this->assertEquals('1234567', $config['my-config']['value_password']); $this->assertEquals('12345678', $config['my-config']['some_password_value']); $this->assertEquals('123456789', $config['my-config']['password-value']); } } ================================================ FILE: tests/Unit/Trackers/ContentTrackerTest.php ================================================ shouldIgnoreMissing(); $content->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $content->shouldReceive('data')->andReturn(collect()); $this->app->make(ExecutionData::class)->setContent($content); $tracker = $this->app->make(ContentTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_content_data() { $content = Mockery::mock(ExecutionContent::class)->shouldIgnoreMissing(); $content->shouldReceive('data')->once()->andReturn(collect([ 'content' => '', ])); $this->app->make(ExecutionData::class)->setContent($content); $tracker = $this->app->make(ContentTracker::class); $tracker->terminate(); $this->assertEquals('', $tracker->data()->get('content')); } } ================================================ FILE: tests/Unit/Trackers/EventsTrackerTest.php ================================================ app->make(EventsTracker::class); $dispatcher = $this->app->make(Dispatcher::class); $this->tapLaravelVersionTill(5.3, function () use ($dispatcher) { $dispatcher->fire('testing: tracker', [new \stdClass()]); }); $this->tapLaravelVersionFrom(5.4, function () use ($dispatcher) { $dispatcher->dispatch('testing: tracker', [new \stdClass()]); }); event(new DummyEventA()); $tracker->terminate(); $events = $tracker->data()->get('events'); $this->assertNotNull($events); $this->assertTrue($events->contains('name', 'testing: tracker')); $this->assertTrue($events->contains('name', DummyEventA::class)); $this->assertEquals(2, $tracker->meta()->get('events_count')); } /** @test */ function has_data_of_fired_events() { $this->app->make('config')->set('profiler.data.events', true); $this->app->make('config')->set('profiler.group.events', false); $tracker = $this->app->make(EventsTracker::class); $user = $this->user(['email' => 'a@example.com']); $usersA = collect([$this->user(['email' => 'b@example.com']), $this->user(['email' => 'c@example.com'])]); $usersB = [$this->user(['email' => 'd@example.com']), $this->user(['email' => collect(['email' => 'e@example.com'])])]; $dummyClasses = [new DummyClassA(), new DummyClassB()]; $dataA = ['a' => 1, 'c' => 2]; $dataB = 'c'; event(new DummyEventB($user, $usersA, $usersB, $dummyClasses, $dataA, $dataB)); $tracker->terminate(); $events = $tracker->data()->get('events'); $eventB = $events->where('name', DummyEventB::class)->first(); $this->assertEquals(['email' => 'a@example.com'], $eventB['data']['user']); $this->assertEquals([ 0 => ['email' => 'b@example.com'], 1 => ['email' => 'c@example.com'], ], $eventB['data']['usersA']); $this->assertEquals([ 0 => ['email' => 'd@example.com'], 1 => ['email' => ['email' => 'e@example.com']], ], $eventB['data']['usersB']); $this->assertEquals([DummyClassA::class, DummyClassB::class], $eventB['data']['dummyClasses']); $this->assertEquals(['a' => 1, 'c' => 2], $eventB['data']['dataA']); $this->assertEquals('c', $eventB['data']['dataB']); } /** @test */ function has_not_data_of_fired_events_if_data_tracking_is_disabled_in_config() { $this->app->make('config')->set('profiler.group.events', false); $tracker = $this->app->make(EventsTracker::class); $user = $this->user(['email' => 'a@example.com']); $usersA = collect([$this->user(['email' => 'b@example.com']), $this->user(['email' => 'c@example.com'])]); $usersB = [$this->user(['email' => 'd@example.com']), $this->user(['email' => 'e@example.com'])]; $dummyClasses = [new DummyClassA(), new DummyClassB()]; $dataA = ['a' => 1, 'c' => 2]; $dataB = 'c'; event(new DummyEventB($user, $usersA, $usersB, $dummyClasses, $dataA, $dataB)); $tracker->terminate(); $events = $tracker->data()->get('events'); $eventB = $events->where('name', DummyEventB::class)->first(); $this->assertArrayNotHasKey('data', $eventB); } /** @test */ function can_group_events_with_the_same_name() { $this->app->make('config')->set('profiler.data.events', true); $tracker = $this->app->make(EventsTracker::class); $dispatcher = $this->app->make(Dispatcher::class); $this->tapLaravelVersionTill(5.3, function () use ($dispatcher) { $dispatcher->fire('testing: eventA', [new \stdClass()]); $dispatcher->fire('testing: eventB', [new \stdClass()]); $dispatcher->fire('testing: eventB', [new \stdClass()]); $dispatcher->fire('testing: eventC', [new \stdClass()]); $dispatcher->fire('testing: eventC', [new \stdClass()]); $dispatcher->fire('testing: eventC', [new \stdClass()]); $dispatcher->fire('testing: eventC', [new \stdClass()]); $dispatcher->fire('testing: eventD', [new \stdClass()]); }); $this->tapLaravelVersionFrom(5.4, function () use ($dispatcher) { $dispatcher->dispatch('testing: eventA', [new \stdClass()]); $dispatcher->dispatch('testing: eventB', [new \stdClass()]); $dispatcher->dispatch('testing: eventB', [new \stdClass()]); $dispatcher->dispatch('testing: eventC', [new \stdClass()]); $dispatcher->dispatch('testing: eventC', [new \stdClass()]); $dispatcher->dispatch('testing: eventC', [new \stdClass()]); $dispatcher->dispatch('testing: eventC', [new \stdClass()]); $dispatcher->dispatch('testing: eventD', [new \stdClass()]); }); $tracker->terminate(); $events = $tracker->data()->get('events'); $this->assertEquals([ 'name' => 'testing: eventA', 'count' => 1, 'data' => collect([]), ], $events->pull(0)); $this->assertEquals([ 'name' => 'testing: eventB', 'count' => 2, ], $events->pull(1)); $this->assertEquals([ 'name' => 'testing: eventC', 'count' => 4, ], $events->pull(2)); $this->assertEquals([ 'name' => 'testing: eventD', 'count' => 1, 'data' => collect([]), ], $events->pull(3)); $this->assertEquals(8, $tracker->meta()->get('events_count')); } /** @test */ function does_not_group_events_if_events_group_is_disabled_in_config() { $this->app->make('config')->set('profiler.data.events', true); $this->app->make('config')->set('profiler.group.events', false); $tracker = $this->app->make(EventsTracker::class); $dispatcher = $this->app->make(Dispatcher::class); $this->tapLaravelVersionTill(5.3, function () use ($dispatcher) { $dispatcher->fire('testing: eventA', [new \stdClass()]); $dispatcher->fire('testing: eventB', [new \stdClass()]); $dispatcher->fire('testing: eventB', [new \stdClass()]); }); $this->tapLaravelVersionFrom(5.4, function () use ($dispatcher) { $dispatcher->dispatch('testing: eventA', [new \stdClass()]); $dispatcher->dispatch('testing: eventB', [new \stdClass()]); $dispatcher->dispatch('testing: eventB', [new \stdClass()]); }); $tracker->terminate(); $events = $tracker->data()->get('events'); $this->assertEquals([ 'name' => 'testing: eventA', 'count' => 1, 'data' => collect([]), ], $events->pull(0)); $this->assertEquals([ 'name' => 'testing: eventB', 'count' => 1, 'data' => collect([]), ], $events->pull(1)); $this->assertEquals([ 'name' => 'testing: eventB', 'count' => 1, 'data' => collect([]), ], $events->pull(2)); $this->assertEquals(3, $tracker->meta()->get('events_count')); } /** @test */ function does_not_track_laravel_profiler_internal_events() { $tracker = $this->app->make(EventsTracker::class); event(new ExceptionHandling(new Exception())); event(new ProfilerBound()); event(new ResetTrackers()); event(new Terminating()); event(new Tracking()); $tracker->terminate(); $this->assertEquals(0, $tracker->meta()->get('events_count')); } /** @test */ function does_not_track_laravel_framework_events() { $tracker = $this->app->make(EventsTracker::class); event('bootstrapped: ' . \Illuminate\Foundation\Bootstrap\BootProviders::class, [new \stdClass()]); $tracker->terminate(); $this->assertEquals(0, $tracker->meta()->get('events_count')); } /** @test */ function can_reset_events() { $tracker = $this->app->make(EventsTracker::class); event(new DummyEventA()); event(new DummyEventA()); event(new DummyEventA()); profiler_reset(); event(new DummyEventA()); $tracker->terminate(); $this->assertEquals(1, $tracker->meta()->get('events_count')); $this->assertCount(1, $tracker->data()->get('events')); } } ================================================ FILE: tests/Unit/Trackers/ExceptionTrackerTest.php ================================================ turnOffProcessors(); } /** @test */ function has_exception() { Event::listen(ExceptionHandling::class, function (ExceptionHandling $exceptionHandling) { $this->exception = $exceptionHandling->exception; }); $tracker = $this->app->make(ExceptionTracker::class); $this->get('/i-can-not-find-that-page'); $tracker->terminate(); $exception = $tracker->data()->get('exception'); $this->assertSame($this->exception->getMessage(), $exception->get('message')); $this->assertSame(NotFoundHttpException::class, $exception->get('exception')); $this->assertSame($this->exception->getFile(), $exception->get('file')); $this->assertSame($this->exception->getLine(), $exception->get('line')); $this->assertEquals(collect($this->exception->getTrace())->map(function ($trace) { return Arr::except($trace, ['args', 'type']); }), $exception->get('trace')); } /** @test */ function has_not_exception_on_correct_framework_execution() { $tracker = $this->app->make(ExceptionTracker::class); $this->get('/'); $tracker->terminate(); $exception = $tracker->data()->get('exception'); $this->assertNull($exception); } /** @test */ function calls_regular_laravel_exception_handler() { $this->tapLaravelVersionTill(5.4, function () { $this->assertTrue(true); }); $this->tapLaravelVersionFrom(5.5, function () { $mock = Mockery::spy(DummyException::class); Route::get('route-ex', function () use ($mock) { throw $mock; }); $tracker = $this->app->make(ExceptionTracker::class); $this->get('/route-ex'); $mock->shouldHaveReceived('report')->once(); }); } } ================================================ FILE: tests/Unit/Trackers/PathsTrackerTest.php ================================================ app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->path(), $paths->where('name', 'app_path')->first()['path']); $this->assertSame(0, $paths->keys()[0]); } /** @test */ function has_base_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->basePath(), $paths->where('name', 'base_path')->first()['path']); } /** @test */ function has_lang_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->langPath(), $paths->where('name', 'lang_path')->first()['path']); } /** @test */ function has_config_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->configPath(), $paths->where('name', 'config_path')->first()['path']); } /** @test */ function has_public_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->publicPath(), $paths->where('name', 'public_path')->first()['path']); } /** @test */ function has_storage_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->storagePath(), $paths->where('name', 'storage_path')->first()['path']); } /** @test */ function has_database_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->databasePath(), $paths->where('name', 'database_path')->first()['path']); } /** @test */ function has_resource_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->tapLaravelVersionTill(5.2, function () use ($paths) { $this->assertCount(0, $paths->where('name', 'resource_path')); }); $this->tapLaravelVersionFrom(5.3, function () use ($paths) { $this->assertEquals($this->app->resourcePath(), $paths->where('name', 'resource_path')->first()['path']); }); } /** @test */ function has_bootstrap_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->bootstrapPath(), $paths->where('name', 'bootstrap_path')->first()['path']); } /** @test */ function has_cached_config_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->getCachedConfigPath(), $paths->where('name', 'cached_config_path')->first()['path']); } /** @test */ function has_cached_routes_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->getCachedRoutesPath(), $paths->where('name', 'cached_routes_path')->first()['path']); } /** @test */ function has_cached_services_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->getCachedServicesPath(), $paths->where('name', 'cached_services_path')->first()['path']); } /** @test */ function has_cached_packages_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->tapLaravelVersionTill(5.4, function () use ($paths) { $this->assertCount(0, $paths->where('name', 'cached_packages_path')); }); $this->tapLaravelVersionFrom(5.5, function () use ($paths) { $this->assertEquals($this->app->getCachedPackagesPath(), $paths->where('name', 'cached_packages_path')->first()['path']); }); } /** @test */ function has_environment_file_path() { $tracker = $this->app->make(PathsTracker::class); $tracker->terminate(); $paths = $tracker->data()->get('paths'); $this->assertEquals($this->app->environmentFilePath(), $paths->where('name', 'environment_file_path')->first()['path']); } } ================================================ FILE: tests/Unit/Trackers/QueriesTrackerTest.php ================================================ app->make(QueriesTracker::class); $this->factoryUser()->create([ 'name' => 'Joe', 'email' => 'joe@example.com', ]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertNotNull($queries); $this->assertStringContainsString('query', $queries->first()['type']); $this->assertStringContainsString('insert into `users` (`name`, `email`', $queries->first()['sql']); $this->assertContains('joe@example.com', $queries->first()['bindings']); $this->assertArrayHasKey('time', $queries->first()); $this->assertEquals(':memory:', $queries->first()['database']); $this->assertEquals('sqlite', $queries->first()['name']); $this->assertStringContainsString('insert into `users` (`name`, `email`', $queries->first()['query']); $this->assertStringContainsString("values ('Joe', 'joe@example.com'", $queries->first()['query']); } /** @test */ function has_committed_transactions() { $tracker = $this->app->make(QueriesTracker::class); DB::transaction(function () { $this->factoryUser()->create(); }); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString('transaction-begin', $queries->first()['type']); $this->assertEquals(':memory:', $queries->first()['database']); $this->assertEquals('sqlite', $queries->first()['name']); $this->assertStringContainsString('transaction-commit', $queries->last()['type']); $this->assertEquals(':memory:', $queries->last()['database']); $this->assertEquals('sqlite', $queries->last()['name']); } /** @test */ function has_rolled_back_transactions() { $tracker = $this->app->make(QueriesTracker::class); try { DB::transaction(function () { throw new Exception(); }); } catch (Exception $e) {} $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString('transaction-rollback', $queries->last()['type']); $this->assertEquals(':memory:', $queries->last()['database']); $this->assertEquals('sqlite', $queries->last()['name']); } /** @test */ function can_count_queries() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users'); $this->factoryUser()->create(); $tracker->terminate(); $this->assertEquals(2, $tracker->meta()->get('queries_count')); } /** @test */ function can_count_queries_without_transactions() { $tracker = $this->app->make(QueriesTracker::class); DB::transaction(function () { DB::select('select * from users'); $this->factoryUser()->create(); }); $tracker->terminate(); $this->assertEquals(2, $tracker->meta()->get('queries_count')); } /** @test */ function has_bindings_keys_names_if_specified() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users where email = :email and name = :name', ['email' => 'abc@example.com', 'name' => 1]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertArrayHasKey('email', $queries->first()['bindings']); $this->assertArrayHasKey('name', $queries->first()['bindings']); } /** @test */ function has_query_bindings_for_int_and_float_values() { $tracker = $this->app->make(QueriesTracker::class); $this->userClass()::whereEmail(1)->first(); $this->userClass()::whereEmail(1.1)->first(); $this->userClass()::whereEmail('1')->first(); $this->userClass()::whereEmail('1.1')->first(); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString("where `email` = 1", $queries->shift()['query']); $this->assertStringContainsString("where `email` = 1.1", $queries->shift()['query']); $this->assertStringContainsString("where `email` = '1'", $queries->shift()['query']); $this->assertStringContainsString("where `email` = '1.1'", $queries->shift()['query']); } /** @test */ function has_query_bindings_for_null_values() { $tracker = $this->app->make(QueriesTracker::class); $this->userClass()::whereNull('email')->first(); $this->userClass()::whereNotNull('email')->first(); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString("where `email` is null", $queries->shift()['query']); $this->assertStringContainsString("where `email` is not null", $queries->shift()['query']); } /** @test */ function has_query_bindings_for_bool_values() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users where 1 = :first and 0 = :second', ['first' => true, 'second' => false]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->tapLaravelVersionFrom(5.5, function () use ($queries) { $this->assertStringContainsString("where 1 = 1 and 0 = 0", $queries->first()['query']); $this->assertSame(1, $queries->first()['bindings']['first']); $this->assertSame(0, $queries->first()['bindings']['second']); }); $this->tapLaravelVersionTill(5.4, function () use ($queries) { $this->assertStringContainsString("where 1 = '1' and 0 = 0", $queries->first()['query']); $this->assertSame(true, $queries->first()['bindings']['first']); $this->assertSame(0, $queries->first()['bindings']['second']); }); } /** @test */ function has_query_bindings_names_as_string() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users where email = :email and name = :name', ['email' => 'abc@example.com', 'name' => 1]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString("where email = 'abc@example.com' and name = 1", $queries->first()['query']); } /** @test */ function has_query_bindings_objects() { $dateTime = Carbon::now(); $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users where email = :email', ['email' => $dateTime]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString("where email = '{$dateTime->toDateTimeString()}'", $queries->first()['query']); } /** @test */ function has_query_bindings_truncated_if_binding_string_is_long() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users where email = :email', ['email' => str_repeat('a', 255)]); DB::select('select * from users where email = :email', ['email' => str_repeat('a', 256)]); $tracker->terminate(); $queries = $tracker->data()->get('queries'); $this->assertStringContainsString("where email = '". str_repeat('a', 255) ."'", $queries->first()['query']); $this->assertContains(str_repeat('a', 255), $queries->first()['bindings']); $this->assertStringContainsString("where email = '". str_repeat('a', 255) ."...{truncated}'", $queries->last()['query']); $this->assertContains(str_repeat('a', 255) . '...{truncated}', $queries->last()['bindings']); } /** @test */ function can_reset_queries() { $tracker = $this->app->make(QueriesTracker::class); DB::select('select * from users'); DB::select('select * from users'); DB::select('select * from users'); profiler_reset(); DB::select('select * from users'); $tracker->terminate(); $this->assertEquals(1, $tracker->meta()->get('queries_count')); $this->assertCount(1, $tracker->data()->get('queries')); } } ================================================ FILE: tests/Unit/Trackers/RedisTrackerTest.php ================================================ app->make(RedisTracker::class); $this->app->make('redis')->set('name', 'Laravel Profiler'); $tracker->terminate(); $redis = $tracker->data()->get('redis'); $this->assertNotNull($redis); $this->tapLaravelVersionTill(5.6, function () use ($redis) { $this->assertEquals([], $redis->all()); }); $this->tapLaravelVersionFrom(5.7, function () use ($redis) { $this->assertEquals('set', $redis->first()['command']); $this->assertEquals('default', $redis->first()['name']); $this->assertEquals(['name', 'Laravel Profiler'], $redis->first()['parameters']); $this->assertArrayHasKey('time', $redis->first()); }); } /** @test */ function can_count_commands() { $tracker = $this->app->make(RedisTracker::class); $this->app->make('redis')->set('name', 'Laravel Profiler'); $this->app->make('redis')->set('action', 'testing'); $tracker->terminate(); $this->tapLaravelVersionTill(5.6, function () use ($tracker) { $this->assertEquals(0, $tracker->meta()->get('redis_count')); }); $this->tapLaravelVersionFrom(5.7, function () use ($tracker) { $this->assertEquals(2, $tracker->meta()->get('redis_count')); }); } /** @test */ function knows_if_laravel_is_able_to_track_redis() { $tracker = $this->app->make(RedisTracker::class); $tracker->terminate(); $this->tapLaravelVersionTill(5.6, function () use ($tracker) { $this->assertFalse($tracker->meta()->get('redis_can_be_tracked')); }); $this->tapLaravelVersionFrom(5.7, function () use ($tracker) { $this->assertTrue($tracker->meta()->get('redis_can_be_tracked')); }); } /** @test */ function can_reset_commands() { $tracker = $this->app->make(RedisTracker::class); $this->app->make('redis')->set('name', 'Laravel Profiler'); $this->app->make('redis')->set('name', 'Laravel Profiler'); $this->app->make('redis')->set('name', 'Laravel Profiler'); profiler_reset(); $this->app->make('redis')->set('name', 'Laravel Profiler'); $tracker->terminate(); $this->tapLaravelVersionTill(5.6, function () { $this->assertTrue(true); }); $this->tapLaravelVersionFrom(5.7, function () use ($tracker) { $this->assertEquals(1, $tracker->meta()->get('redis_count')); $this->assertCount(1, $tracker->data()->get('redis')); }); } } ================================================ FILE: tests/Unit/Trackers/RequestTrackerTest.php ================================================ shouldIgnoreMissing(); $request->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $this->app->make(ExecutionData::class)->setRequest($request); $tracker = $this->app->make(RequestTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_request_data() { $request = Mockery::mock(ExecutionRequest::class)->shouldIgnoreMissing(); $request->shouldReceive('data')->once()->andReturn(collect([ ['name' => 'key-x', 'value' => 'val-x'], ['name' => 'key-y', 'value' => 'val-y'], ['name' => 'key-z', 'value' => 'val-z'], ])); $this->app->make(ExecutionData::class)->setRequest($request); $tracker = $this->app->make(RequestTracker::class); $tracker->terminate(); $this->assertEquals('val-x', $tracker->data()->get('request')->where('name', 'key-x')->first()['value']); $this->assertEquals('val-y', $tracker->data()->get('request')->where('name', 'key-y')->first()['value']); $this->assertEquals('val-z', $tracker->data()->get('request')->where('name', 'key-z')->first()['value']); } } ================================================ FILE: tests/Unit/Trackers/ResponseTrackerTest.php ================================================ shouldIgnoreMissing(); $response->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $this->app->make(ExecutionData::class)->setResponse($response); $tracker = $this->app->make(ResponseTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_response_data() { $response = Mockery::mock(ExecutionResponse::class)->shouldIgnoreMissing(); $response->shouldReceive('data')->once()->andReturn(collect([ ['name' => 'key-x', 'value' => 'val-x'], ['name' => 'key-y', 'value' => 'val-y'], ['name' => 'key-z', 'value' => 'val-z'], ])); $this->app->make(ExecutionData::class)->setResponse($response); $tracker = $this->app->make(ResponseTracker::class); $tracker->terminate(); $this->assertEquals('val-x', $tracker->data()->get('response')->where('name', 'key-x')->first()['value']); $this->assertEquals('val-y', $tracker->data()->get('response')->where('name', 'key-y')->first()['value']); $this->assertEquals('val-z', $tracker->data()->get('response')->where('name', 'key-z')->first()['value']); } } ================================================ FILE: tests/Unit/Trackers/RouteTrackerTest.php ================================================ shouldIgnoreMissing(); $route->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $this->app->make(ExecutionData::class)->setRoute($route); $tracker = $this->app->make(RouteTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_route_data() { $route = Mockery::mock(ExecutionRoute::class)->shouldIgnoreMissing(); $route->shouldReceive('data')->once()->andReturn(collect([ ['name' => 'key-x', 'value' => 'val-x'], ['name' => 'key-y', 'value' => 'val-y'], ['name' => 'key-z', 'value' => 'val-z'], ])); $this->app->make(ExecutionData::class)->setRoute($route); $tracker = $this->app->make(RouteTracker::class); $tracker->terminate(); $this->assertEquals('val-x', $tracker->data()->get('route')->where('name', 'key-x')->first()['value']); $this->assertEquals('val-y', $tracker->data()->get('route')->where('name', 'key-y')->first()['value']); $this->assertEquals('val-z', $tracker->data()->get('route')->where('name', 'key-z')->first()['value']); } } ================================================ FILE: tests/Unit/Trackers/ServerTrackerTest.php ================================================ shouldIgnoreMissing(); $server->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $this->app->make(ExecutionData::class)->setServer($server); $tracker = $this->app->make(ServerTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_server_data() { $server = Mockery::mock(ExecutionServer::class)->shouldIgnoreMissing(); $server->shouldReceive('data')->once()->andReturn(collect([ ['name' => 'key-x', 'value' => 'val-x'], ['name' => 'key-y', 'value' => 'val-y'], ['name' => 'key-z', 'value' => 'val-z'], ])); $this->app->make(ExecutionData::class)->setServer($server); $tracker = $this->app->make(ServerTracker::class); $tracker->terminate(); $this->assertEquals('val-x', $tracker->data()->get('server')->where('name', 'key-x')->first()['value']); $this->assertEquals('val-y', $tracker->data()->get('server')->where('name', 'key-y')->first()['value']); $this->assertEquals('val-z', $tracker->data()->get('server')->where('name', 'key-z')->first()['value']); } } ================================================ FILE: tests/Unit/Trackers/ServiceProvidersTrackerTest.php ================================================ app) extends ServiceProvider { public function register() {} }; $this->app->register($provider); $tracker = $this->app->make(ServiceProvidersTracker::class); $tracker->terminate(); $serviceProviders = $tracker->data()->get('service_providers'); $this->assertNotNull($serviceProviders); $this->assertTrue($serviceProviders->contains(get_class($provider))); $this->assertCount(count($serviceProviders), $this->app->getLoadedProviders()); $this->assertSame(0, $serviceProviders->keys()[0]); } } ================================================ FILE: tests/Unit/Trackers/SessionTrackerTest.php ================================================ shouldIgnoreMissing(); $session->shouldReceive('meta')->once()->andReturn(collect([ 'key-a' => 'val-a', 'key-b' => 'val-b', 'key-c' => 'val-c', ])); $this->app->make(ExecutionData::class)->setSession($session); $tracker = $this->app->make(SessionTracker::class); $tracker->terminate(); $this->assertEquals('val-a', $tracker->meta()->get('key-a')); $this->assertEquals('val-b', $tracker->meta()->get('key-b')); $this->assertEquals('val-c', $tracker->meta()->get('key-c')); } /** @test */ function has_session_data() { $session = Mockery::mock(ExecutionSession::class)->shouldIgnoreMissing(); $session->shouldReceive('data')->once()->andReturn(collect([ ['name' => 'key-x', 'value' => 'val-x'], ['name' => 'key-y', 'value' => 'val-y'], ['name' => 'key-z', 'value' => 'val-z'], ])); $this->app->make(ExecutionData::class)->setSession($session); $tracker = $this->app->make(SessionTracker::class); $tracker->terminate(); $this->assertEquals('val-x', $tracker->data()->get('session')->where('name', 'key-x')->first()['value']); $this->assertEquals('val-y', $tracker->data()->get('session')->where('name', 'key-y')->first()['value']); $this->assertEquals('val-z', $tracker->data()->get('session')->where('name', 'key-z')->first()['value']); } } ================================================ FILE: tests/Unit/Trackers/ViewsTrackerTest.php ================================================ app['view']->addNamespace('tests', __DIR__ . '/../../Support/Fixtures'); } /** @test */ function has_views() { $tracker = $this->app->make(ViewsTracker::class); view('tests::dummy-view-a')->render(); view('tests::dummy-view-b')->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertNotNull($views); $this->assertCount(2, $views); } /** @test */ function has_view_name() { $tracker = $this->app->make(ViewsTracker::class); view('tests::dummy-view-a')->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertEquals('tests::dummy-view-a', $views->first()['name']); } /** @test */ function has_view_path() { $tracker = $this->app->make(ViewsTracker::class); view('tests::dummy-view-a')->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertEquals(__DIR__ . '/../../Support/Fixtures/dummy-view-a.blade.php', $views->first()['path']); } /** @test */ function has_view_data() { $this->app->make('config')->set('profiler.data.views', true); $tracker = $this->app->make(ViewsTracker::class); $user = ['name' => 'Joe']; view('tests::dummy-view-a', compact('user'))->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertEquals(['name' => 'Joe'], $views->first()['data']['user']); $this->assertArrayNotHasKey('params', $views->first()); } /** @test */ function has_not_data_of_views_if_data_tracking_is_disabled_in_config() { $tracker = $this->app->make(ViewsTracker::class); $user = ['name' => 'Joe']; view('tests::dummy-view-a', compact('user'))->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertArrayNotHasKey('data', $views->first()); } /** @test */ function has_view_params_if_data_tracking_is_disabled_in_config() { $tracker = $this->app->make(ViewsTracker::class); $name = 'Joe'; $visits = 125; $price = 5.89; $active = true; $address = null; $related = $this->user(['email' => 'a@example.com']); $roles = collect(['publisher', 'viewer']); $tags = ['a']; $comments = []; view('tests::dummy-view-a', compact( 'name', 'visits', 'price', 'active', 'address', 'related', 'roles', 'tags', 'comments' ))->render(); $tracker->terminate(); $views = $tracker->data()->get('views'); $this->assertArrayNotHasKey('data', $views->first()); $this->assertEquals([ 'name' => 'string', 'visits' => 'integer', 'price' => 'double', 'active' => 'boolean', 'address' => 'NULL', 'related' => $this->userClass(), 'roles' => 'Illuminate\Support\Collection: 2 item(s)', 'tags' => 'array: 1 item(s)', 'comments' => 'array: 0 item(s)', ], $views->first()['params']); } /** @test */ function can_reset_views() { $tracker = $this->app->make(ViewsTracker::class); view('tests::dummy-view-a')->render(); view('tests::dummy-view-a')->render(); view('tests::dummy-view-a')->render(); profiler_reset(); view('tests::dummy-view-a')->render(); $tracker->terminate(); $this->assertCount(1, $tracker->data()->get('views')); } } ================================================ FILE: tests/bootstrap/phpunit.php ================================================ dir() . '/vendor/autoload.php'; if (! file_exists($frameworkAutoloadFile)) { shell_exec('composer create-project --no-dev ' . $framework->composerPackage() . ' ./frameworks/' . $framework->dir()); } return $frameworkAutoloadFile; } /** * @param \JKocik\Laravel\Profiler\Tests\Support\Framework $framework * @return void */ function bootstrapFrameworkEnv(\JKocik\Laravel\Profiler\Tests\Support\Framework $framework): void { $frameworkPath = __DIR__ . '/../../frameworks/' . $framework->dir(); if (! file_exists($frameworkPath . '/.env')) { copy($frameworkPath . '/.env.example', $frameworkPath . '/.env'); } }