Skip to content

Commit eb0742e

Browse files
Merge branch '13.1'
* 13.1: Closes #6599
2 parents 845b55b + 451a35b commit eb0742e

14 files changed

Lines changed: 416 additions & 18 deletions
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Logging\TeamCity;
11+
12+
use PHPUnit\Event\InvalidArgumentException;
13+
use PHPUnit\Event\Test\PreparationErrored;
14+
use PHPUnit\Event\Test\PreparationErroredSubscriber;
15+
16+
/**
17+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
18+
*
19+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
20+
*/
21+
final readonly class TestPreparationErroredSubscriber extends Subscriber implements PreparationErroredSubscriber
22+
{
23+
/**
24+
* @throws InvalidArgumentException
25+
*/
26+
public function notify(PreparationErrored $event): void
27+
{
28+
$this->logger()->testPreparationErrored();
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Logging\TeamCity;
11+
12+
use PHPUnit\Event\InvalidArgumentException;
13+
use PHPUnit\Event\Test\PreparationFailed;
14+
use PHPUnit\Event\Test\PreparationFailedSubscriber;
15+
16+
/**
17+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
18+
*
19+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
20+
*/
21+
final readonly class TestPreparationFailedSubscriber extends Subscriber implements PreparationFailedSubscriber
22+
{
23+
/**
24+
* @throws InvalidArgumentException
25+
*/
26+
public function notify(PreparationFailed $event): void
27+
{
28+
$this->logger()->testPreparationFailed();
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Logging\TeamCity;
11+
12+
use PHPUnit\Event\InvalidArgumentException;
13+
use PHPUnit\Event\Test\PreparationStarted;
14+
use PHPUnit\Event\Test\PreparationStartedSubscriber;
15+
16+
/**
17+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
18+
*
19+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
20+
*/
21+
final readonly class TestPreparationStartedSubscriber extends Subscriber implements PreparationStartedSubscriber
22+
{
23+
/**
24+
* @throws InvalidArgumentException
25+
*/
26+
public function notify(PreparationStarted $event): void
27+
{
28+
$this->logger()->testPreparationStarted($event);
29+
}
30+
}

src/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
{
2222
public function notify(Prepared $event): void
2323
{
24-
$this->logger()->testPrepared($event);
24+
$this->logger()->testPrepared();
2525
}
2626
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\Logging\TeamCity;
11+
12+
use PHPUnit\Event\InvalidArgumentException;
13+
use PHPUnit\Event\Test\BeforeFirstTestMethodFailed;
14+
use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber;
15+
16+
/**
17+
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
18+
*
19+
* @internal This class is not covered by the backward compatibility promise for PHPUnit
20+
*/
21+
final readonly class TestSuiteBeforeFirstTestMethodFailedSubscriber extends Subscriber implements BeforeFirstTestMethodFailedSubscriber
22+
{
23+
/**
24+
* @throws InvalidArgumentException
25+
*/
26+
public function notify(BeforeFirstTestMethodFailed $event): void
27+
{
28+
$this->logger()->beforeFirstTestMethodFailed($event);
29+
}
30+
}

src/Logging/TeamCity/TeamCityLogger.php

Lines changed: 131 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
use PHPUnit\Event\InvalidArgumentException;
2525
use PHPUnit\Event\Telemetry\HRTime;
2626
use PHPUnit\Event\Test\BeforeFirstTestMethodErrored;
27+
use PHPUnit\Event\Test\BeforeFirstTestMethodFailed;
2728
use PHPUnit\Event\Test\ConsideredRisky;
2829
use PHPUnit\Event\Test\Errored;
2930
use PHPUnit\Event\Test\Failed;
3031
use PHPUnit\Event\Test\Finished;
3132
use PHPUnit\Event\Test\MarkedIncomplete;
32-
use PHPUnit\Event\Test\Prepared;
33+
use PHPUnit\Event\Test\PreparationStarted;
3334
use PHPUnit\Event\Test\Skipped;
3435
use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished;
3536
use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped;
@@ -50,6 +51,9 @@ final class TeamCityLogger
5051
private bool $isSummaryTestCountPrinted = false;
5152
private ?HRTime $time = null;
5253
private ?int $flowId = null;
54+
private bool $testStartedEmitted = false;
55+
private bool $prepared = false;
56+
private bool $preparationFailed = false;
5357

5458
public function __construct(Printer $printer, Facade $facade)
5559
{
@@ -112,7 +116,7 @@ public function testSuiteFinished(TestSuiteFinished $event): void
112116
$this->writeMessage('testSuiteFinished', $parameters);
113117
}
114118

115-
public function testPrepared(Prepared $event): void
119+
public function testPreparationStarted(PreparationStarted $event): void
116120
{
117121
$test = $event->test();
118122

@@ -133,7 +137,25 @@ public function testPrepared(Prepared $event): void
133137

134138
$this->writeMessage('testStarted', $parameters);
135139

136-
$this->time = $event->telemetryInfo()->time();
140+
$this->time = $event->telemetryInfo()->time();
141+
$this->testStartedEmitted = true;
142+
$this->prepared = false;
143+
$this->preparationFailed = false;
144+
}
145+
146+
public function testPreparationErrored(): void
147+
{
148+
$this->preparationFailed = true;
149+
}
150+
151+
public function testPreparationFailed(): void
152+
{
153+
$this->preparationFailed = true;
154+
}
155+
156+
public function testPrepared(): void
157+
{
158+
$this->prepared = true;
137159
}
138160

139161
/**
@@ -156,6 +178,8 @@ public function testMarkedIncomplete(MarkedIncomplete $event): void
156178
'duration' => $this->duration($event),
157179
],
158180
);
181+
182+
$this->writeTestFinishedIfPreparationDidNotComplete($event);
159183
}
160184

161185
/**
@@ -175,6 +199,8 @@ public function testSkipped(Skipped $event): void
175199
$parameters['duration'] = $this->duration($event);
176200

177201
$this->writeMessage('testIgnored', $parameters);
202+
203+
$this->writeTestFinishedIfPreparationDidNotComplete($event);
178204
}
179205

180206
/**
@@ -202,19 +228,23 @@ public function testSuiteSkipped(TestSuiteSkipped $event): void
202228
*/
203229
public function beforeFirstTestMethodErrored(BeforeFirstTestMethodErrored $event): void
204230
{
205-
if ($this->time === null) {
206-
$this->time = $event->telemetryInfo()->time();
207-
}
208-
209-
$parameters = [
210-
'name' => $event->testClassName(),
211-
'message' => $this->message($event->throwable()),
212-
'details' => $this->details($event->throwable()),
213-
'duration' => $this->duration($event),
214-
];
231+
$this->writeBeforeFirstTestMethodHookFailure(
232+
$event,
233+
$event->testClassName(),
234+
$event->throwable(),
235+
);
236+
}
215237

216-
$this->writeMessage('testFailed', $parameters);
217-
$this->writeMessage('testSuiteFinished', $parameters);
238+
/**
239+
* @throws InvalidArgumentException
240+
*/
241+
public function beforeFirstTestMethodFailed(BeforeFirstTestMethodFailed $event): void
242+
{
243+
$this->writeBeforeFirstTestMethodHookFailure(
244+
$event,
245+
$event->testClassName(),
246+
$event->throwable(),
247+
);
218248
}
219249

220250
/**
@@ -235,6 +265,8 @@ public function testErrored(Errored $event): void
235265
'duration' => $this->duration($event),
236266
],
237267
);
268+
269+
$this->writeTestFinishedIfPreparationDidNotComplete($event);
238270
}
239271

240272
/**
@@ -262,6 +294,8 @@ public function testFailed(Failed $event): void
262294
}
263295

264296
$this->writeMessage('testFailed', $parameters);
297+
298+
$this->writeTestFinishedIfPreparationDidNotComplete($event);
265299
}
266300

267301
/**
@@ -291,6 +325,10 @@ public function testConsideredRisky(ConsideredRisky $event): void
291325
*/
292326
public function testFinished(Finished $event): void
293327
{
328+
if (!$this->testStartedEmitted) {
329+
return;
330+
}
331+
294332
$this->writeMessage(
295333
'testFinished',
296334
[
@@ -299,7 +337,10 @@ public function testFinished(Finished $event): void
299337
],
300338
);
301339

302-
$this->time = null;
340+
$this->time = null;
341+
$this->testStartedEmitted = false;
342+
$this->prepared = false;
343+
$this->preparationFailed = false;
303344
}
304345

305346
public function flush(): void
@@ -312,6 +353,9 @@ private function registerSubscribers(Facade $facade): void
312353
$facade->registerSubscribers(
313354
new TestSuiteStartedSubscriber($this),
314355
new TestSuiteFinishedSubscriber($this),
356+
new TestPreparationStartedSubscriber($this),
357+
new TestPreparationErroredSubscriber($this),
358+
new TestPreparationFailedSubscriber($this),
315359
new TestPreparedSubscriber($this),
316360
new TestFinishedSubscriber($this),
317361
new TestErroredSubscriber($this),
@@ -322,7 +366,78 @@ private function registerSubscribers(Facade $facade): void
322366
new TestConsideredRiskySubscriber($this),
323367
new TestRunnerExecutionFinishedSubscriber($this),
324368
new TestSuiteBeforeFirstTestMethodErroredSubscriber($this),
369+
new TestSuiteBeforeFirstTestMethodFailedSubscriber($this),
370+
);
371+
}
372+
373+
/**
374+
* @throws InvalidArgumentException
375+
*/
376+
private function writeBeforeFirstTestMethodHookFailure(Event $event, string $name, Throwable $throwable): void
377+
{
378+
if ($this->time === null) {
379+
$this->time = $event->telemetryInfo()->time();
380+
}
381+
382+
$this->writeMessage(
383+
'testStarted',
384+
[
385+
'name' => $name,
386+
],
387+
);
388+
389+
$parameters = [
390+
'name' => $name,
391+
'message' => $this->message($throwable),
392+
'details' => $this->details($throwable),
393+
'duration' => $this->duration($event),
394+
];
395+
396+
$this->writeMessage('testFailed', $parameters);
397+
398+
$this->writeMessage(
399+
'testFinished',
400+
[
401+
'name' => $name,
402+
'duration' => $this->duration($event),
403+
],
325404
);
405+
406+
$this->writeMessage(
407+
'testSuiteFinished',
408+
[
409+
'name' => $name,
410+
],
411+
);
412+
413+
$this->time = null;
414+
}
415+
416+
/**
417+
* @throws InvalidArgumentException
418+
*/
419+
private function writeTestFinishedIfPreparationDidNotComplete(Errored|Failed|MarkedIncomplete|Skipped $event): void
420+
{
421+
if (!$this->testStartedEmitted) {
422+
return;
423+
}
424+
425+
if ($this->prepared && !$this->preparationFailed) {
426+
return;
427+
}
428+
429+
$this->writeMessage(
430+
'testFinished',
431+
[
432+
'name' => $event->test()->name(),
433+
'duration' => $this->duration($event),
434+
],
435+
);
436+
437+
$this->time = null;
438+
$this->testStartedEmitted = false;
439+
$this->prepared = false;
440+
$this->preparationFailed = false;
326441
}
327442

328443
private function setFlowId(): void

tests/end-to-end/logging/teamcity/log-teamcity.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ require_once __DIR__ . '/../../../bootstrap.php';
4343
##teamcity[testStarted name='testIncompleteWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncompleteWithMessage' flowId='%d']
4444
##teamcity[testIgnored name='testIncompleteWithMessage' message='incomplete with custom message' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d']
4545
##teamcity[testFinished name='testIncompleteWithMessage' duration='%d' flowId='%d']
46+
##teamcity[testStarted name='testSkippedByMetadata' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkippedByMetadata' flowId='%d']
4647
##teamcity[testIgnored name='testSkippedByMetadata' message='PHP > 9000.0.0 is required.' duration='%d' flowId='%d']
48+
##teamcity[testFinished name='testSkippedByMetadata' duration='%d' flowId='%d']
4749
##teamcity[testStarted name='testSkippedWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkippedWithMessage' flowId='%d']
4850
##teamcity[testIgnored name='testSkippedWithMessage' message='skipped with custom message' duration='%d' flowId='%d']
4951
##teamcity[testFinished name='testSkippedWithMessage' duration='%d' flowId='%d']

0 commit comments

Comments
 (0)