Skip to content

Commit e0f611a

Browse files
committed
test: Filters pipeline does not have memory leak and its performance is OK-ish
1 parent 96ea3b4 commit e0f611a

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737
"require-dev": {
3838
"nunomaduro/phpinsights": "^2.11",
39+
"petrknap/profiler": "^2.2",
3940
"petrknap/shorts": "^3.0",
4041
"phpstan/phpstan": "^1.12",
4142
"squizlabs/php_codesniffer": "^3.7",

tests/FilterTest.php

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44

55
namespace PetrKnap\ExternalFilter;
66

7+
use PetrKnap\Profiler\ProfileInterface;
8+
use PetrKnap\Profiler\Profiler;
9+
use PetrKnap\Profiler\ProfilerInterface;
710
use PHPUnit\Framework\Attributes\DataProvider;
11+
use PHPUnit\Framework\Attributes\Depends;
12+
use PHPUnit\Framework\ExpectationFailedException;
813
use PHPUnit\Framework\TestCase;
914
use stdClass;
15+
use Symfony\Component\Process\Process;
1016

1117
final class FilterTest extends TestCase
1218
{
@@ -71,15 +77,54 @@ public static function dataWritesToStreamsAndReturnsExpectedValue(): array
7177
];
7278
}
7379

74-
public function testBuildsAndExecutesPipeline(): void
80+
public function testBuildsAndExecutesPipeline(): ProfileInterface
7581
{
76-
$pipeline = (new Filter('gzip'))->pipe(new Filter('base64'))->pipe(new Filter('base64', ['--decode']));
77-
$filter = new Filter('gzip', ['--decompress']);
82+
$reference = Process::fromShellCommandline(
83+
"php | base64 --decode | wc --bytes",
84+
);
85+
$pipeline = (new Filter('php'))
86+
->pipe(new Filter('base64', ['--decode']))
87+
->pipe(new Filter('wc', ['--bytes']));
7888

79-
self::assertSame(
80-
'test',
81-
(new Filter('cat'))->pipe($pipeline)->pipe($filter)->filter('test'),
89+
$input = '<?php for ($i = 0; $i < 16; $i++) echo base64_encode(random_bytes(512 * 1024)) . PHP_EOL;';
90+
$output = (16 * 512 * 1024) . PHP_EOL;
91+
92+
return (new Profiler())->profile(static fn (ProfilerInterface $profiler) => self::assertSame([
93+
'reference' => $output,
94+
'pipeline' => $output,
95+
], [
96+
'reference' => $profiler->profile(static fn (): string => $reference->setInput($input)->mustRun()->getOutput())->getOutput(),
97+
'pipeline' => $profiler->profile(static fn (): string => $pipeline->filter($input))->getOutput(),
98+
]));
99+
}
100+
101+
#[Depends('testBuildsAndExecutesPipeline')]
102+
public function testPipelineDoesNotHaveMemoryLeak(ProfileInterface $profile): void
103+
{
104+
[$referenceProfile, $pipelineProfile] = $profile->getChildren();
105+
106+
self::assertLessThanOrEqual(
107+
$referenceProfile->getMemoryUsageChange() * 1.05, # allow 5% overhead
108+
$pipelineProfile->getMemoryUsageChange(),
82109
);
110+
111+
if ($referenceProfile->getMemoryUsageChange() !== 0) {
112+
self::markTestIncomplete('Memory leak detected in reference.');
113+
}
114+
}
115+
116+
#[Depends('testBuildsAndExecutesPipeline')]
117+
public function testPipelinePerformanceIsOk(ProfileInterface $profile): void
118+
{
119+
[$referenceProfile, $pipelineProfile] = $profile->getChildren();
120+
try { # @todo fix performance and remove try / catch
121+
self::assertLessThanOrEqual(
122+
$referenceProfile->getDuration() * 1.05, # allow 5% overhead
123+
$pipelineProfile->getDuration(),
124+
);
125+
} catch (ExpectationFailedException $expectationFailed) {
126+
self::markTestIncomplete($expectationFailed->getMessage());
127+
}
83128
}
84129

85130
#[DataProvider('dataThrows')]

0 commit comments

Comments
 (0)