Skip to content

Commit 42638c5

Browse files
authored
Merge pull request #14 from Tiime-Software/successfully-tested
Introduce "not successfully tested routes"
2 parents a28afb3 + 083e9bf commit 42638c5

File tree

4 files changed

+159
-19
lines changed

4 files changed

+159
-19
lines changed

src/Command/CheckCommand.php

+30-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ protected function configure(): void
3333
->addOption('maximum-routes-to-display', 'm', InputOption::VALUE_REQUIRED, 'Maximum number of non tested routes to display', $this->maximumNumberOfNonTestedRoutesToDisplay)
3434
->addOption('routes-to-ignore', 'i', InputOption::VALUE_REQUIRED, 'A file containing routes to ignore', $this->routesToIgnoreFile)
3535
->addOption('generate-baseline', 'g', InputOption::VALUE_NONE, 'Generate the file containing the routes to be ignored')
36+
->addOption('ignore-not-successfully-tested-routes', 'S', InputOption::VALUE_NONE, 'Does not fail if a route have not been successfully tested (never returned a 1xx, 2xx or 3xx code).')
3637
;
3738
}
3839

@@ -54,6 +55,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5455

5556
$untestedRoutes = $this->routesChecker->getUntestedRoutes($routesToIgnore);
5657
$testedIgnoredRoutes = $this->routesChecker->getTestedIgnoredRoutes($routesToIgnore);
58+
$notSuccessfullyTestedRoutes = $this->routesChecker->getNotSuccessfullyTestedRoutes($routesToIgnore);
5759

5860
if (0 === $count = \count($untestedRoutes)) {
5961
if (0 < \count($testedIgnoredRoutes)) {
@@ -62,6 +64,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6264
return Command::FAILURE;
6365
}
6466

67+
if (0 < \count($notSuccessfullyTestedRoutes)) {
68+
$this->showNotSuccessfullyTestedRoutes($io, $notSuccessfullyTestedRoutes);
69+
70+
return $input->getOption('ignore-not-successfully-tested-routes') ? Command::SUCCESS : Command::FAILURE;
71+
}
72+
6573
$io->success('Congrats, all routes have been tested!');
6674

6775
return Command::SUCCESS;
@@ -76,10 +84,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7684
$io->listing(\array_slice($untestedRoutes, 0, $max));
7785

7886
if ($count > $max) {
79-
$io->writeln(sprintf('... and %d more', $count - $max));
87+
$io->writeln(\sprintf('... and %d more', $count - $max));
8088
}
8189

82-
$io->error(sprintf('Found %d non tested route%s!', $count, 1 === $count ? '' : 's'));
90+
$io->error(\sprintf('Found %d non tested route%s!', $count, 1 === $count ? '' : 's'));
91+
92+
$this->showNotSuccessfullyTestedRoutes($io, $testedIgnoredRoutes);
8393

8494
$this->showTestedIgnoredRoutesSection($io, $testedIgnoredRoutes);
8595

@@ -88,7 +98,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8898
->saveRoute(
8999
implode(\PHP_EOL, $untestedRoutes)
90100
);
91-
$io->writeln(sprintf('Results saved in %s', $routesToIgnoreFile));
101+
$io->writeln(\sprintf('Results saved in %s', $routesToIgnoreFile));
102+
}
103+
104+
if (0 < \count($notSuccessfullyTestedRoutes)) {
105+
return $input->getOption('ignore-not-successfully-tested-routes') ? Command::SUCCESS : Command::FAILURE;
92106
}
93107

94108
return Command::FAILURE;
@@ -106,4 +120,17 @@ private function showTestedIgnoredRoutesSection(SymfonyStyle $io, array $testedI
106120
$io->warning('Some ignored routes looks tested, you should remove them from baseline!');
107121
$io->listing($testedIgnoredRoutes);
108122
}
123+
124+
/**
125+
* @param string[] $notSuccessfullyTestedRoutes
126+
*/
127+
private function showNotSuccessfullyTestedRoutes(SymfonyStyle $io, array $notSuccessfullyTestedRoutes): void
128+
{
129+
if (0 === \count($notSuccessfullyTestedRoutes)) {
130+
return;
131+
}
132+
133+
$io->warning(\sprintf('Found %d routes which are not successfully tested (they never returned a 1xx, 2xx or 3xx code).', \count($notSuccessfullyTestedRoutes)));
134+
$io->listing($notSuccessfullyTestedRoutes);
135+
}
109136
}

src/RoutesChecker.php

+57-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Symfony\Component\Routing\RouterInterface;
88
use Tiime\TestedRoutesCheckerBundle\RouteStorage\RouteStorageInterface;
99

10-
final class RoutesChecker
10+
class RoutesChecker
1111
{
1212
public function __construct(
1313
private readonly RouterInterface $router,
@@ -29,21 +29,7 @@ public function getUntestedRoutes(array $routesToIgnore = []): array
2929
$routes = array_keys($this->router->getRouteCollection()->all());
3030
$untestedRoutes = array_diff($routes, $testedRoutes);
3131

32-
$filteredRoutes = [];
33-
foreach ($untestedRoutes as $untestedRoute) {
34-
if (\in_array($untestedRoute, $routesToIgnore)) {
35-
continue;
36-
}
37-
foreach ($routesToIgnore as $routeToIgnore) {
38-
if (@preg_match("#\b$routeToIgnore\b#", $untestedRoute)) {
39-
continue 2;
40-
}
41-
}
42-
43-
$filteredRoutes[] = $untestedRoute;
44-
}
45-
46-
return $filteredRoutes;
32+
return $this->filterRoutesWithRoutesToIgnore($untestedRoutes, $routesToIgnore);
4733
}
4834

4935
/**
@@ -60,6 +46,36 @@ public function getTestedIgnoredRoutes(array $routesToIgnore = []): array
6046
return array_values(array_intersect($testedRoutes, $routesToIgnore));
6147
}
6248

49+
/**
50+
* Return not successfully tested routes.
51+
*
52+
* A route is considered non fully tested when it never return a successful
53+
* code during test execution.
54+
*
55+
* - a successful code is a 1xx, 2xx or 3xx code.
56+
* - if the route have been tested several times with at least 1 successful
57+
* code: it's considered successfully tested.
58+
*
59+
* @param string[] $routesToIgnore
60+
*
61+
* @return string[]
62+
*/
63+
public function getNotSuccessfullyTestedRoutes(array $routesToIgnore = []): array
64+
{
65+
// Filter all routes wich have been successfully tested at least once.
66+
$routes = array_keys(array_filter($this->routeStorage->getRoutes(), static function (array $responseCodes): bool {
67+
foreach ($responseCodes as $responseCode) {
68+
if ($responseCode < 400) {
69+
return false;
70+
}
71+
}
72+
73+
return true;
74+
}));
75+
76+
return $this->filterRoutesWithRoutesToIgnore($routes, $routesToIgnore);
77+
}
78+
6379
/**
6480
* @return string[]
6581
*/
@@ -73,4 +89,29 @@ private function getDefaultRoutesToIgnore(): array
7389
'app.swagger',
7490
];
7591
}
92+
93+
/**
94+
* @param string[] $routes
95+
* @param string[] $routesToIgnore
96+
*
97+
* @return string[]
98+
*/
99+
private function filterRoutesWithRoutesToIgnore(array $routes, array $routesToIgnore): array
100+
{
101+
$filteredRoutes = [];
102+
foreach ($routes as $route) {
103+
if (\in_array($route, $routesToIgnore)) {
104+
continue;
105+
}
106+
foreach ($routesToIgnore as $routeToIgnore) {
107+
if (@preg_match("#\b$routeToIgnore\b#", $route)) {
108+
continue 2;
109+
}
110+
}
111+
112+
$filteredRoutes[] = $route;
113+
}
114+
115+
return $filteredRoutes;
116+
}
76117
}

tests/Command/CheckCommandTest.php

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tiime\TestedRoutesCheckerBundle\Tests\Command;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Symfony\Component\Console\Tester\CommandTester;
9+
use Tiime\TestedRoutesCheckerBundle\Command\CheckCommand;
10+
use Tiime\TestedRoutesCheckerBundle\RoutesChecker;
11+
12+
final class CheckCommandTest extends TestCase
13+
{
14+
public function testWithoutUntestedRoutes(): void
15+
{
16+
$routesChecker = $this->createMock(RoutesChecker::class);
17+
$routesChecker->expects($this->once())->method('getUntestedRoutes')->willReturn([]);
18+
$routesChecker->expects($this->once())->method('getNotSuccessfullyTestedRoutes')->willReturn([]);
19+
20+
$commandTester = new CommandTester(new CheckCommand($routesChecker, 10, __DIR__.'/ignored_routes'));
21+
22+
$commandTester->execute([]);
23+
24+
$commandTester->assertCommandIsSuccessful();
25+
26+
$output = $commandTester->getDisplay();
27+
$this->assertStringContainsString('[OK] Congrats, all routes have been tested!', $output);
28+
}
29+
30+
public function testWithUntestedRoutes(): void
31+
{
32+
$routesChecker = $this->createMock(RoutesChecker::class);
33+
$routesChecker->expects($this->once())->method('getUntestedRoutes')->willReturn(['route1', 'route2']);
34+
$routesChecker->expects($this->once())->method('getNotSuccessfullyTestedRoutes')->willReturn([]);
35+
36+
$commandTester = new CommandTester(new CheckCommand($routesChecker, 10, __DIR__.'/ignored_routes'));
37+
38+
$commandTester->execute([]);
39+
40+
$this->assertSame(1, $commandTester->getStatusCode());
41+
42+
$output = $commandTester->getDisplay();
43+
$this->assertStringContainsString('[ERROR] Found 2 non tested routes!', $output);
44+
}
45+
46+
public function testWithNotSuccessfullyTestedRoutes(): void
47+
{
48+
$routesChecker = $this->createMock(RoutesChecker::class);
49+
$routesChecker->expects($this->once())->method('getUntestedRoutes')->willReturn([]);
50+
$routesChecker->expects($this->once())->method('getNotSuccessfullyTestedRoutes')->willReturn(['route3', 'route4']);
51+
52+
$commandTester = new CommandTester(new CheckCommand($routesChecker, 10, __DIR__.'/ignored_routes'));
53+
54+
$commandTester->execute([]);
55+
56+
$this->assertSame(1, $commandTester->getStatusCode());
57+
58+
$output = $commandTester->getDisplay();
59+
$this->assertStringContainsString('[WARNING] Found 2 routes which are not successfully tested', $output);
60+
}
61+
}

tests/RoutesCheckerTest.php

+11
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,15 @@ public function testGetTestedIgnoredRoutes(): void
3434

3535
$this->assertSame(['route2'], $testedIgnoredRoutes);
3636
}
37+
38+
public function testGetNotFullyTesteRoutes(): void
39+
{
40+
$this->routeStorage->expects($this->once())
41+
->method('getRoutes')
42+
->willReturn(['route1' => [200], 'route2' => [404], 'route3' => [500]]);
43+
44+
$routes = $this->routesChecker->getNotSuccessfullyTestedRoutes(['route2', 'route4']);
45+
46+
$this->assertSame(['route3'], $routes);
47+
}
3748
}

0 commit comments

Comments
 (0)