Skip to content

Commit dad8a38

Browse files
committed
Corona: Implement TracingControllerInterface in the Request class
1 parent 845b038 commit dad8a38

File tree

2 files changed

+309
-3
lines changed

2 files changed

+309
-3
lines changed

Diff for: src/Lunr/Corona/Request.php

+48-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use BackedEnum;
1414
use Lunr\Corona\Parsers\TracingInfo\TracingInfoValue;
15+
use Lunr\Ticks\TracingControllerInterface;
1516
use Lunr\Ticks\TracingInfoInterface;
1617
use RuntimeException;
1718

@@ -34,7 +35,7 @@
3435
* @property-read string $call The call identifier, combining controller and method
3536
* @property-read string $verbosity Logging verbosity
3637
*/
37-
class Request implements TracingInfoInterface
38+
class Request implements TracingControllerInterface, TracingInfoInterface
3839
{
3940

4041
/**
@@ -104,12 +105,19 @@ class Request implements TracingInfoInterface
104105
*/
105106
private array $mock;
106107

108+
/**
109+
* Whether to generate UUIDs as hex string or real UUIDs.
110+
* @var bool
111+
*/
112+
protected readonly bool $uuidAsHexString;
113+
107114
/**
108115
* Constructor.
109116
*
110-
* @param RequestParserInterface $parser Shared instance of a Request Parser class
117+
* @param RequestParserInterface $parser Shared instance of a Request Parser class
118+
* @param bool $uuidAsHexString Whether to generate UUIDs as hex string or real UUIDs
111119
*/
112-
public function __construct($parser)
120+
public function __construct($parser, $uuidAsHexString = TRUE)
113121
{
114122
$this->parser = $parser;
115123
$this->parsers = [];
@@ -124,6 +132,8 @@ public function __construct($parser)
124132
$this->rawData = '';
125133

126134
$this->mock = [];
135+
136+
$this->uuidAsHexString = $uuidAsHexString;
127137
}
128138

129139
/**
@@ -256,6 +266,41 @@ public function registerParser(RequestValueParserInterface $parser): void
256266
$this->parsers[$parser->getRequestValueType()] = $parser;
257267
}
258268

269+
/**
270+
* Start a new child span.
271+
*
272+
* @return void
273+
*/
274+
public function startChildSpan(): void
275+
{
276+
$requestValues = [];
277+
278+
$requestValues[TracingInfoValue::ParentSpanID->value] = $this->get(TracingInfoValue::SpanID);
279+
$requestValues[TracingInfoValue::SpanID->value] = uuid_create();
280+
281+
if ($this->uuidAsHexString)
282+
{
283+
$requestValues[TracingInfoValue::SpanID->value] = str_replace('-', '', $requestValues[TracingInfoValue::SpanID->value]);
284+
}
285+
286+
if (!empty($this->mock))
287+
{
288+
$this->setMockValues($this->mock[0]);
289+
}
290+
291+
$this->addMockValues($requestValues);
292+
}
293+
294+
/**
295+
* Stop the current child span, returning to the scope of the parent.
296+
*
297+
* @return void
298+
*/
299+
public function stopChildSpan(): void
300+
{
301+
array_shift($this->mock);
302+
}
303+
259304
/**
260305
* Override request values detected from the request parser.
261306
* Replace all previous mock values.
+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
<?php
2+
3+
/**
4+
* This file contains the RequestTracingControllerTest class.
5+
*
6+
* SPDX-FileCopyrightText: Copyright 2025 Move Agency Group B.V., Zwolle, The Netherlands
7+
* SPDX-License-Identifier: MIT
8+
*/
9+
10+
namespace Lunr\Corona\Tests;
11+
12+
use Lunr\Corona\Parsers\TracingInfo\TracingInfoValue;
13+
use Lunr\Corona\Request;
14+
use Lunr\Corona\RequestParserInterface;
15+
use Lunr\Corona\RequestValueParserInterface;
16+
17+
/**
18+
* Tests for getAsEnumting request values.
19+
*
20+
* @covers Lunr\Corona\Request
21+
*/
22+
class RequestTracingControllerTest extends RequestTestCase
23+
{
24+
25+
/**
26+
* Check that startChildSpan() starts a new span.
27+
*
28+
* @covers Lunr\Corona\Request::startChildSpan
29+
*/
30+
public function testStartChildSpanWithExistingMock(): void
31+
{
32+
$parser = $this->getMockBuilder(RequestValueParserInterface::class)
33+
->getMock();
34+
35+
$parsers = [
36+
TracingInfoValue::class => $parser,
37+
];
38+
39+
$this->setReflectionPropertyValue('parsers', $parsers);
40+
41+
$mock = [
42+
[
43+
'controller' => 'test',
44+
],
45+
];
46+
47+
$this->setReflectionPropertyValue('mock', $mock);
48+
49+
$id = '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5';
50+
51+
$parser->expects($this->once())
52+
->method('get')
53+
->with(TracingInfoValue::SpanID)
54+
->willReturn($id);
55+
56+
$this->mockFunction('uuid_create', fn() => '200c5938-cbe1-4b58-ad36-022ab5c6bcc6');
57+
58+
$this->class->startChildSpan();
59+
60+
$expected = [
61+
[
62+
TracingInfoValue::ParentSpanID->value => '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5',
63+
TracingInfoValue::SpanID->value => '200c5938cbe14b58ad36022ab5c6bcc6',
64+
'controller' => 'test',
65+
],
66+
[
67+
'controller' => 'test',
68+
],
69+
];
70+
71+
$this->assertPropertyEquals('mock', $expected);
72+
73+
$this->unmockFunction('uuid_create');
74+
}
75+
76+
/**
77+
* Check that startChildSpan() starts a new span.
78+
*
79+
* @covers Lunr\Corona\Request::startChildSpan
80+
*/
81+
public function testStartChildSpan(): void
82+
{
83+
$parser = $this->getMockBuilder(RequestValueParserInterface::class)
84+
->getMock();
85+
86+
$parsers = [
87+
TracingInfoValue::class => $parser,
88+
];
89+
90+
$this->setReflectionPropertyValue('parsers', $parsers);
91+
92+
$id = '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5';
93+
94+
$parser->expects($this->once())
95+
->method('get')
96+
->with(TracingInfoValue::SpanID)
97+
->willReturn($id);
98+
99+
$this->mockFunction('uuid_create', fn() => '200c5938-cbe1-4b58-ad36-022ab5c6bcc6');
100+
101+
$this->class->startChildSpan();
102+
103+
$expected = [
104+
[
105+
TracingInfoValue::ParentSpanID->value => '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5',
106+
TracingInfoValue::SpanID->value => '200c5938cbe14b58ad36022ab5c6bcc6',
107+
],
108+
];
109+
110+
$this->assertPropertyEquals('mock', $expected);
111+
112+
$this->unmockFunction('uuid_create');
113+
}
114+
115+
/**
116+
* Check that startChildSpan() starts a new span.
117+
*
118+
* @covers Lunr\Corona\Request::startChildSpan
119+
*/
120+
public function testStartChildSpanWithRealUuidValue(): void
121+
{
122+
$parser = $this->getMockBuilder(RequestParserInterface::class)->getMock();
123+
124+
$parser->expects($this->once())
125+
->method('parse_request')
126+
->willReturn([]);
127+
128+
$parser->expects($this->once())
129+
->method('parse_post')
130+
->willReturn([]);
131+
132+
$parser->expects($this->once())
133+
->method('parse_get')
134+
->willReturn([]);
135+
136+
$parser->expects($this->once())
137+
->method('parse_cookie')
138+
->willReturn([]);
139+
140+
$parser->expects($this->once())
141+
->method('parse_server')
142+
->willReturn([]);
143+
144+
$parser->expects($this->once())
145+
->method('parse_files')
146+
->willReturn([]);
147+
148+
$parser->expects($this->once())
149+
->method('parse_command_line_arguments')
150+
->willReturn([]);
151+
152+
$class = new Request($parser, uuidAsHexString: FALSE);
153+
154+
$parser = $this->getMockBuilder(RequestValueParserInterface::class)
155+
->getMock();
156+
157+
$parsers = [
158+
TracingInfoValue::class => $parser,
159+
];
160+
161+
$this->getReflectionProperty('parsers')->setValue($class, $parsers);
162+
163+
$id = '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5';
164+
165+
$parser->expects($this->once())
166+
->method('get')
167+
->with(TracingInfoValue::SpanID)
168+
->willReturn($id);
169+
170+
$this->mockFunction('uuid_create', fn() => '200c5938-cbe1-4b58-ad36-022ab5c6bcc6');
171+
172+
$class->startChildSpan();
173+
174+
$expected = [
175+
[
176+
TracingInfoValue::ParentSpanID->value => '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5',
177+
TracingInfoValue::SpanID->value => '200c5938-cbe1-4b58-ad36-022ab5c6bcc6',
178+
],
179+
];
180+
181+
$value = $this->getReflectionProperty('mock')->getValue($class);
182+
183+
$this->assertEquals($expected, $value);
184+
185+
$this->unmockFunction('uuid_create');
186+
}
187+
188+
/**
189+
* Check that stopChildSpan() stops the current span.
190+
*
191+
* @covers Lunr\Corona\Request::stopChildSpan
192+
*/
193+
public function testStopChildSpanWithSingleMock(): void
194+
{
195+
$mock = [
196+
[
197+
TracingInfoValue::ParentSpanID->value => '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5',
198+
TracingInfoValue::SpanID->value => '200c5938cbe14b58ad36022ab5c6bcc6',
199+
'controller' => 'test',
200+
],
201+
];
202+
203+
$this->setReflectionPropertyValue('mock', $mock);
204+
205+
$this->class->stopChildSpan();
206+
207+
$expected = [];
208+
209+
$this->assertPropertyEquals('mock', $expected);
210+
}
211+
212+
/**
213+
* Check that stopChildSpan() stops the current span.
214+
*
215+
* @covers Lunr\Corona\Request::stopChildSpan
216+
*/
217+
public function testStopChildSpanWithMultipleMocks(): void
218+
{
219+
$mock = [
220+
[
221+
TracingInfoValue::ParentSpanID->value => '1bee74f0-5f21-4b7f-9fff-62e7320e9aa5',
222+
TracingInfoValue::SpanID->value => '200c5938cbe14b58ad36022ab5c6bcc6',
223+
'controller' => 'test',
224+
],
225+
[
226+
'controller' => 'test',
227+
],
228+
];
229+
230+
$this->setReflectionPropertyValue('mock', $mock);
231+
232+
$this->class->stopChildSpan();
233+
234+
$expected = [
235+
[
236+
'controller' => 'test',
237+
],
238+
];
239+
240+
$this->assertPropertyEquals('mock', $expected);
241+
}
242+
243+
/**
244+
* Check that stopChildSpan() stops the current span.
245+
*
246+
* @covers Lunr\Corona\Request::stopChildSpan
247+
*/
248+
public function testStopChildSpanWithNoMock(): void
249+
{
250+
$mock = [];
251+
252+
$this->setReflectionPropertyValue('mock', $mock);
253+
254+
$this->class->stopChildSpan();
255+
256+
$this->assertPropertyEquals('mock', $mock);
257+
}
258+
259+
}
260+
261+
?>

0 commit comments

Comments
 (0)