-
Notifications
You must be signed in to change notification settings - Fork 0
Test Octane request context provider #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
glensc
wants to merge
5
commits into
main
Choose a base branch
from
carry-OctaneWorkerProfilerManager-tests
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
27161cc
Test Octane request context provider
glensc d08ceb9
Test Octane profiler manager lifecycle
glensc 3b593ea
Test: Cover manager-driven Octane provider flow
glensc 22f87e4
Potential fix for pull request finding
glensc 57a23c0
test: assert LaravelProfilerException in Octane context tests
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| <?php | ||
|
|
||
| namespace Xhgui\Profiler\Laravel\Tests\Octane; | ||
|
|
||
| use Illuminate\Http\Request; | ||
| use Xhgui\Profiler\Laravel\Exception\LaravelProfilerException; | ||
| use Xhgui\Profiler\Laravel\Octane\OctaneRequestContextProvider; | ||
| use Xhgui\Profiler\Laravel\Octane\OctaneRequestContextState; | ||
| use Xhgui\Profiler\Laravel\Tests\TestCase; | ||
| use Xhgui\Profiler\RequestContext\RequestContextInterface; | ||
|
|
||
| final class OctaneRequestContextProviderTest extends TestCase | ||
| { | ||
| public function test_capture_returns_a_request_context_snapshot(): void | ||
| { | ||
| $request = Request::create('/profiles', 'GET', ['page' => '2'], [], [], [ | ||
| 'REQUEST_URI' => '/profiles?page=2', | ||
| 'REQUEST_METHOD' => 'GET', | ||
| 'REQUEST_TIME' => 1234, | ||
| 'REQUEST_TIME_FLOAT' => 1234.5, | ||
| ]); | ||
|
|
||
| $state = new OctaneRequestContextState; | ||
| $state->activate($request, ['APP_ENV' => 'testing']); | ||
|
|
||
| $provider = new OctaneRequestContextProvider($state); | ||
| $context = $provider->capture(); | ||
|
|
||
| $this->assertInstanceOf(RequestContextInterface::class, $context); | ||
| $this->assertSame('/profiles?page=2', $context->getUrl()); | ||
| $this->assertSame(['page' => '2'], $context->getQuery()); | ||
| $this->assertSame(['APP_ENV' => 'testing'], $context->getEnv()); | ||
| $this->assertSame(1234.5, $context->getServer()['REQUEST_TIME_FLOAT']); | ||
| $this->assertSame(1234, $context->getServer()['REQUEST_TIME']); | ||
| } | ||
|
|
||
| public function test_capture_uses_the_current_active_request_snapshot(): void | ||
| { | ||
| $state = new OctaneRequestContextState; | ||
| $provider = new OctaneRequestContextProvider($state); | ||
|
|
||
| $state->activate(Request::create('/first', 'GET', ['page' => '1'], [], [], [ | ||
| 'REQUEST_TIME' => 100, | ||
| 'REQUEST_TIME_FLOAT' => 100.0, | ||
| ]), ['APP_ENV' => 'testing']); | ||
| $firstContext = $provider->capture(); | ||
|
|
||
| $state->clear(); | ||
| $state->activate(Request::create('/second', 'GET', ['page' => '2'], [], [], [ | ||
| 'REQUEST_TIME' => 200, | ||
| 'REQUEST_TIME_FLOAT' => 200.0, | ||
| ]), ['APP_ENV' => 'testing']); | ||
| $secondContext = $provider->capture(); | ||
|
|
||
| $this->assertSame('/first?page=1', $firstContext->getUrl()); | ||
| $this->assertSame('/second?page=2', $secondContext->getUrl()); | ||
| $this->assertSame(['page' => '2'], $secondContext->getQuery()); | ||
| $this->assertSame(200.0, $secondContext->getServer()['REQUEST_TIME_FLOAT']); | ||
| } | ||
|
|
||
| public function test_capture_fails_without_an_active_request_snapshot(): void | ||
| { | ||
| $provider = new OctaneRequestContextProvider(new OctaneRequestContextState); | ||
|
|
||
| $this->expectException(LaravelProfilerException::class); | ||
| $this->expectExceptionMessage('Octane request context is not active.'); | ||
|
|
||
| $provider->capture(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| <?php | ||
|
|
||
| namespace Xhgui\Profiler\Laravel\Tests\Octane; | ||
|
|
||
| use Illuminate\Http\Request; | ||
| use Illuminate\Support\Facades\Log; | ||
| use Xhgui\Profiler\Laravel\Exception\LaravelProfilerException; | ||
| use Xhgui\Profiler\Laravel\Octane\OctaneRequestContextProvider; | ||
| use Xhgui\Profiler\Laravel\Octane\OctaneRequestContextState; | ||
| use Xhgui\Profiler\Laravel\Octane\OctaneWorkerProfilerManager; | ||
| use Xhgui\Profiler\Laravel\Tests\TestCase; | ||
| use Xhgui\Profiler\Profiler; | ||
|
|
||
| final class OctaneWorkerProfilerManagerTest extends TestCase | ||
| { | ||
| public function test_sequential_requests_reuse_the_same_profiler(): void | ||
| { | ||
| $manager = $this->newManager(); | ||
|
|
||
| $profilerA = $manager->startRequest($this->enabledConfig(), Request::create('/profiles', 'GET', ['page' => '2'])); | ||
| $manager->stopRequest(); | ||
|
|
||
| $profilerB = $manager->startRequest($this->enabledConfig(), Request::create('/health', 'GET', ['ping' => '1'])); | ||
| $manager->stopRequest(); | ||
|
|
||
| $this->assertSame($profilerA, $profilerB); | ||
| } | ||
|
|
||
| public function test_stale_running_profiler_is_stopped_and_rebuilt_before_the_next_request(): void | ||
| { | ||
| $logger = new class | ||
| { | ||
| public array $warnings = []; | ||
|
|
||
| public function warning(string $message): void | ||
| { | ||
| $this->warnings[] = $message; | ||
| } | ||
| }; | ||
|
|
||
| Log::swap($logger); | ||
|
|
||
| $firstProfilerState = $this->newProfilerState(); | ||
| $manager = $this->newManager([$firstProfilerState, $this->newProfilerState()]); | ||
|
|
||
| $profilerA = $manager->startRequest($this->enabledConfig(), Request::create('/first')); | ||
| $profilerB = $manager->startRequest($this->enabledConfig(), Request::create('/second')); | ||
|
|
||
| $this->assertNotSame($profilerA, $profilerB); | ||
| $this->assertTrue($firstProfilerState->stopped); | ||
| $this->assertSame( | ||
| ['Xhgui Octane profiler was still running at the start of a new request; rebuilding worker profiler state.'], | ||
| $logger->warnings, | ||
| ); | ||
| } | ||
|
|
||
| public function test_enable_failure_clears_the_active_request_context(): void | ||
| { | ||
| $profilerState = $this->newProfilerState([ | ||
| 'enableException' => new \RuntimeException('boom'), | ||
| ]); | ||
| $state = new OctaneRequestContextState; | ||
| $provider = new OctaneRequestContextProvider($state); | ||
| $manager = $this->newManager([$profilerState], $state, $provider); | ||
|
|
||
| try { | ||
| $manager->startRequest($this->enabledConfig(), Request::create('/broken')); | ||
| $this->fail('Expected the profiler enable failure to be rethrown.'); | ||
| } catch (\RuntimeException $exception) { | ||
| $this->assertSame('boom', $exception->getMessage()); | ||
| } | ||
|
|
||
| $this->expectException(LaravelProfilerException::class); | ||
| $this->expectExceptionMessage('Octane request context is not active.'); | ||
|
|
||
| $provider->capture(); | ||
| } | ||
|
|
||
| public function test_stale_cleanup_failures_are_logged_before_rebuild(): void | ||
| { | ||
| $logger = new class | ||
| { | ||
| public array $warnings = []; | ||
|
|
||
| public function warning(string $message): void | ||
| { | ||
| $this->warnings[] = $message; | ||
| } | ||
| }; | ||
|
|
||
| Log::swap($logger); | ||
|
|
||
| $firstProfilerState = $this->newProfilerState([ | ||
| 'disableException' => new \RuntimeException('cleanup failed'), | ||
| ]); | ||
| $manager = $this->newManager([$firstProfilerState, $this->newProfilerState()]); | ||
|
|
||
| $profilerA = $manager->startRequest($this->enabledConfig(), Request::create('/first')); | ||
| $profilerB = $manager->startRequest($this->enabledConfig(), Request::create('/second')); | ||
|
|
||
| $this->assertNotSame($profilerA, $profilerB); | ||
| $this->assertSame([ | ||
| 'Xhgui Octane profiler was still running at the start of a new request; rebuilding worker profiler state.', | ||
| 'Xhgui Octane stale profiler cleanup failed: cleanup failed', | ||
| ], $logger->warnings); | ||
| } | ||
|
|
||
| private function newManager( | ||
| array $profilerStates = [], | ||
| ?OctaneRequestContextState $state = null, | ||
| ?OctaneRequestContextProvider $provider = null, | ||
| ): OctaneWorkerProfilerManager { | ||
| $state ??= new OctaneRequestContextState; | ||
| $provider ??= new OctaneRequestContextProvider($state); | ||
|
|
||
| return new class($state, $provider, $profilerStates, $this) extends OctaneWorkerProfilerManager | ||
| { | ||
| public function __construct( | ||
| OctaneRequestContextState $state, | ||
| private OctaneRequestContextProvider $provider, | ||
| private array $profilerStates, | ||
| private OctaneWorkerProfilerManagerTest $test, | ||
| ) { | ||
| parent::__construct($state, $provider); | ||
| } | ||
|
|
||
| protected function createProfiler(array $config): Profiler | ||
| { | ||
| $profilerState = array_shift($this->profilerStates); | ||
|
|
||
| return $this->test->makeManagedProfiler($this->provider, $profilerState); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| public function makeManagedProfiler(OctaneRequestContextProvider $provider, ?object $state = null): Profiler | ||
| { | ||
| return $this->newManagedProfiler($provider, $state); | ||
| } | ||
|
|
||
| private function enabledConfig(array $overrides = []): array | ||
| { | ||
| return array_replace_recursive([ | ||
| 'enabled' => true, | ||
| 'save.handler' => Profiler::SAVER_FILE, | ||
| 'save.handler.file' => [ | ||
| 'filename' => sys_get_temp_dir().'/xhgui-manager.jsonl', | ||
| ], | ||
| ], $overrides); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 57a23c0: the Octane request-context test now expects
LaravelProfilerExceptioninstead ofRuntimeException, and related Octane manager assertion/imports were aligned to the same exception contract. No UI changes were involved (no screenshot applicable).