Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 6a65323

Browse files
fcabralpachecoOcramius
authored andcommitted
Add test to check memory usage behavior on SapiStreamEmitter::emit() call
1 parent 40dd3a2 commit 6a65323

File tree

1 file changed

+115
-2
lines changed

1 file changed

+115
-2
lines changed

test/Response/SapiStreamEmitterTest.php

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ public function testEmitBody($seekable, $contents, $maxBufferLength, $expectedRe
8181
$stream->getSize()->willReturn(strlen($contents));
8282
$stream->isSeekable()->willReturn($seekable);
8383
$stream->isReadable()->willReturn(true);
84+
$stream->__toString()->willReturn($contents);
85+
$stream->getContents()->willReturn($contents);
8486
$stream->rewind()->willReturn(true);
8587

8688
$stream->eof()->will(function () use (&$contents, &$position) {
@@ -104,6 +106,109 @@ public function testEmitBody($seekable, $contents, $maxBufferLength, $expectedRe
104106
$this->assertEquals($contents, ob_get_clean());
105107
}
106108

109+
public function emitMemoryUsageProvider()
110+
{
111+
return [
112+
[true, 512, 1000, 20, null],
113+
[true, 8192, 1000, 20, null],
114+
[false, 512, 1000, 20, null],
115+
[false, 8192, 1000, 20, null],
116+
[true, 512, 1000, 20, [25, 75]],
117+
[true, 8192, 1000, 20, [25, 75]],
118+
[true, 512, 1000, 20, [250, 750]],
119+
[true, 8192, 1000, 20, [250, 750]],
120+
[false, 512, 1000, 20, [25, 75]],
121+
[false, 8192, 1000, 20, [25, 75]],
122+
[false, 512, 1000, 20, [250, 750]],
123+
[false, 8192, 1000, 20, [250, 750]],
124+
];
125+
}
126+
127+
/**
128+
* @dataProvider emitMemoryUsageProvider
129+
*/
130+
public function testEmitMemoryUsage($seekable, $maxBufferLength, $sizeBlocks, $maxAllowedBlocks, $rangeBlocks)
131+
{
132+
$sizeBytes = $maxBufferLength * $sizeBlocks;
133+
$maxAllowedMemoryUsage = $maxBufferLength * $maxAllowedBlocks;
134+
$peakBufferLength = 0;
135+
$peakMemoryUsage = 0;
136+
137+
if ($rangeBlocks) {
138+
$first = $maxBufferLength * $rangeBlocks[0];
139+
$last = $maxBufferLength * $rangeBlocks[1];
140+
$position = $first;
141+
} else {
142+
$position = 0;
143+
}
144+
145+
$closureFullContents = function () use (&$sizeBytes) {
146+
return str_repeat('0', $sizeBytes);
147+
};
148+
149+
$stream = $this->prophesize('Psr\Http\Message\StreamInterface');
150+
$stream->getSize()->willReturn($sizeBytes);
151+
$stream->isSeekable()->willReturn($seekable);
152+
$stream->isReadable()->willReturn(true);
153+
$stream->__toString()->will($closureFullContents);
154+
$stream->getContents()->willReturn($closureFullContents);
155+
$stream->rewind()->willReturn(true);
156+
157+
$stream->seek(Argument::type('integer'), Argument::any())->will(function ($args) use (&$position) {
158+
$position = $args[0];
159+
return true;
160+
});
161+
162+
$stream->eof()->will(function () use (&$sizeBytes, &$position) {
163+
return ($position >= $sizeBytes);
164+
});
165+
166+
$stream->read(Argument::type('integer'))->will(function ($args) use (&$position, &$peakBufferLength) {
167+
if ($args[0] > $peakBufferLength) {
168+
$peakBufferLength = $args[0];
169+
}
170+
171+
$position += $args[0];
172+
return str_repeat('0', $args[0]);
173+
});
174+
175+
$response = (new Response())
176+
->withStatus(200)
177+
->withBody($stream->reveal());
178+
179+
180+
if ($rangeBlocks) {
181+
$response->withHeader('Content-Range', "bytes $first-$last/*");
182+
}
183+
184+
ob_start(function ($output) {
185+
return "";
186+
}, $maxBufferLength);
187+
188+
$closureTrackMemoryUsage = function () use (&$peakMemoryUsage) {
189+
$memoryUsage = memory_get_usage();
190+
191+
if ($memoryUsage > $peakMemoryUsage) {
192+
$peakMemoryUsage = $memoryUsage;
193+
}
194+
};
195+
196+
register_tick_function($closureTrackMemoryUsage);
197+
198+
declare (ticks = 1) {
199+
$this->emitter->emit($response, $maxBufferLength);
200+
}
201+
202+
unregister_tick_function($closureTrackMemoryUsage);
203+
204+
ob_end_flush();
205+
206+
$localMemoryUsage = memory_get_usage();
207+
208+
$this->assertLessThanOrEqual($maxBufferLength, $peakBufferLength);
209+
$this->assertLessThanOrEqual($maxAllowedMemoryUsage, ($peakMemoryUsage - $localMemoryUsage));
210+
}
211+
107212
public function emitBodyRangeProvider()
108213
{
109214
return [
@@ -127,7 +232,11 @@ public function testEmitBodyRange($seekable, $contents, $range, $maxBufferLength
127232
$stream->getSize()->willReturn(strlen($contents));
128233
$stream->isSeekable()->willReturn($seekable);
129234
$stream->isReadable()->willReturn(true);
130-
$stream->seek(Argument::type('integer'))->will(function ($args) use (&$position) {
235+
$stream->__toString()->willReturn($contents);
236+
$stream->getContents()->willReturn($contents);
237+
$stream->rewind()->willReturn(true);
238+
239+
$stream->seek(Argument::type('integer'), Argument::any())->will(function ($args) use (&$position) {
131240
$position = $args[0];
132241
return true;
133242
});
@@ -136,6 +245,10 @@ public function testEmitBodyRange($seekable, $contents, $range, $maxBufferLength
136245
return ! isset($contents[$position]);
137246
});
138247

248+
$stream->tell()->will(function () use (&$position) {
249+
return $position;
250+
});
251+
139252
$stream->read(Argument::type('integer'))->will(function ($args) use (&$contents, &$position) {
140253
$data = substr($contents, $position, $args[0]);
141254
$position += strlen($data);
@@ -149,7 +262,7 @@ public function testEmitBodyRange($seekable, $contents, $range, $maxBufferLength
149262

150263
ob_start();
151264
$this->emitter->emit($response, $maxBufferLength);
152-
$stream->seek(Argument::type('integer'))->shouldBeCalledTimes($seekable ? 1 : 0);
265+
$stream->seek(Argument::type('integer'), Argument::any())->shouldBeCalledTimes($seekable ? 1 : 0);
153266
$stream->read(Argument::type('integer'))->shouldBeCalledTimes($expectedReads);
154267
$this->assertEquals(substr($contents, $first, $last - $first + 1), ob_get_clean());
155268
}

0 commit comments

Comments
 (0)