Skip to content

Commit 410be88

Browse files
committed
Add more coverage tests
1 parent 301f25d commit 410be88

File tree

2 files changed

+76
-36
lines changed

2 files changed

+76
-36
lines changed

src/Terremoth/Async/Process.php

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Process
1414
public function __construct(private int $shmopKey = 0)
1515
{
1616
if (!$this->shmopKey) {
17-
$this->shmopKey = mt_rand(0, self::MAX_INT); // communication key
17+
$this->shmopKey = mt_rand(0, self::MAX_INT);
1818
}
1919
}
2020

@@ -31,24 +31,28 @@ public function send(Closure $asyncFunction): void
3131
});
3232

3333
try {
34-
$shmopInstance = shmop_open($this->shmopKey, 'n', 0660, $length);
34+
try {
35+
$shmopInstance = $this->openShmop($this->shmopKey, 'n', 0660, $length);
36+
} catch (Exception) {
37+
$shmopInstance = false;
38+
}
3539

3640
if ($shmopInstance === false) {
37-
$existing = shmop_open($this->shmopKey, 'a', 0660, 0);
41+
$existing = $this->openShmop($this->shmopKey, 'a', 0660, 0);
3842

3943
if ($existing === false) {
4044
throw new Exception(
4145
'Could not access existing shmop instance with key: ' . $this->shmopKey
4246
);
4347
}
4448

45-
if (shmop_delete($existing) === false) {
49+
if ($this->deleteShmop($existing) === false) {
4650
throw new Exception(
4751
'Could not delete existing shmop instance with key: ' . $this->shmopKey
4852
);
4953
}
5054

51-
$shmopInstance = shmop_open($this->shmopKey, 'c', 0660, $length);
55+
$shmopInstance = $this->openShmop($this->shmopKey, 'c', 0660, $length);
5256

5357
if ($shmopInstance === false) {
5458
throw new Exception(
@@ -62,7 +66,7 @@ public function send(Closure $asyncFunction): void
6266

6367
$bytesWritten = $this->writeToShmop($shmopInstance, $serialized, 0);
6468

65-
if ((bool)$bytesWritten === false) {
69+
if ($bytesWritten === false) {
6670
throw new Exception(
6771
'shmop_write failed when writing to shared memory with key: ' . $this->shmopKey
6872
);
@@ -71,7 +75,7 @@ public function send(Closure $asyncFunction): void
7175
if ($bytesWritten !== $length) {
7276
throw new Exception(
7377
'Could not write all bytes to shared memory. Expected: '
74-
. $length . ', Written: ' . (int)$bytesWritten
78+
. $length . ', Written: ' . $bytesWritten
7579
);
7680
}
7781

@@ -83,14 +87,18 @@ public function send(Closure $asyncFunction): void
8387
$file->run();
8488
}
8589

86-
/**
87-
* @param Shmop $shmopInstance
88-
* @param string $data
89-
* @param int $offset
90-
* @return int|false
91-
*/
9290
protected function writeToShmop(Shmop $shmopInstance, string $data, int $offset): int|false
9391
{
9492
return shmop_write($shmopInstance, $data, $offset);
9593
}
94+
95+
protected function openShmop(int $key, string $mode, int $permissions, int $size): Shmop|false
96+
{
97+
return shmop_open($key, $mode, $permissions, $size);
98+
}
99+
100+
protected function deleteShmop(Shmop $shmopInstance): bool
101+
{
102+
return shmop_delete($shmopInstance);
103+
}
96104
}

tests/Terremoth/AsyncTest/ProcessTest.php

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPUnit\Framework\TestCase;
66
use Random\RandomException;
7+
use Shmop;
78
use Terremoth\Async\Process;
89
use Exception;
910
use Laravel\SerializableClosure\SerializableClosure;
@@ -26,20 +27,15 @@ protected function setUp(): void
2627
public function testConstructorGeneratesRandomKeyWhenZero(): void
2728
{
2829
$process = new Process(0);
29-
3030
$ref = new ReflectionProperty(Process::class, 'shmopKey');
31-
3231
$key = intval($ref->getValue($process));
33-
3432
$this->assertGreaterThan(0, $key);
3533
}
3634

3735
public function testConstructorKeepsProvidedKey(): void
3836
{
3937
$process = new Process(12345);
40-
4138
$reflection = new ReflectionProperty(Process::class, 'shmopKey');
42-
4339
$this->assertSame(12345, $reflection->getValue($process));
4440
}
4541

@@ -53,7 +49,7 @@ public function testSendActuallyWritesSerializedClosureToShmop(): void
5349
$process = new Process($key);
5450

5551
$closure = function (): int {
56-
return (3 * 2 + 34 | 2 ^ 1) - 1; // this is whatever, just for phpmd stops crying, the result is 42
52+
return 42;
5753
};
5854

5955
$process->send($closure);
@@ -69,10 +65,7 @@ public function testSendActuallyWritesSerializedClosureToShmop(): void
6965
$unserialized = unserialize($data);
7066
$this->assertInstanceOf(SerializableClosure::class, $unserialized);
7167

72-
$unserialized->getClosure();
73-
74-
// shmop_delete($shmop);
75-
// shmop_close($shmop); // deprecated
68+
//shmop_delete($shmop);
7669
}
7770

7871
/**
@@ -93,29 +86,68 @@ public function testSendThrowsWhenNotAllBytesAreWritten(): void
9386
->willReturn(10);
9487

9588
$this->expectException(Exception::class);
89+
$this->expectExceptionMessage('Could not write all bytes');
90+
91+
$process->send(fn() => true);
92+
}
93+
94+
public function testSendThrowsExceptionWhenWriteFailsCompletely(): void
95+
{
96+
$key = 123456;
97+
$process = $this->getMockBuilder(Process::class)
98+
->setConstructorArgs([$key])
99+
->onlyMethods(['writeToShmop'])
100+
->getMock();
101+
102+
$process->expects($this->once())
103+
->method('writeToShmop')
104+
->willReturn(false);
105+
106+
$this->expectException(Exception::class);
107+
$this->expectExceptionMessage('shmop_write failed');
96108

97-
$process->send(function () {
98-
});
109+
$process->send(fn() => true);
99110
}
100111

101112
/**
102-
* @throws RandomException
103113
* @throws Exception
104114
*/
105-
public function testSendDoesNotThrowOnSuccess(): void
115+
public function testSendHandlesShmopCollisionAndRecreation(): void
106116
{
107-
$key = ftok(__FILE__, 'c') ?: random_int(1, 1000000);
117+
$key = 987654;
108118

109-
$process = new Process($key);
119+
$process = $this->getMockBuilder(Process::class)
120+
->setConstructorArgs([$key])
121+
->onlyMethods(['openShmop', 'deleteShmop', 'writeToShmop'])
122+
->getMock();
110123

111-
$process->send(function (): int {
112-
return 42;
113-
});
124+
$process->expects($this->exactly(3))
125+
->method('openShmop')
126+
->willReturnCallback(function (int $key, string $mode) {
127+
unset($key);
128+
if ($mode === 'n') {
129+
throw new Exception('shmop already exists');
130+
}
114131

115-
$shmop = shmop_open($key, 'a', 0, 0);
116-
$this->assertNotFalse($shmop, 'Shared memory should exist after send');
132+
$tempKey = random_int(1000000, 9999999);
133+
$dummyShmop = shmop_open($tempKey, 'c', 0660, 1);
117134

118-
$size = shmop_size($shmop);
119-
$this->assertGreaterThan(0, $size, 'Shared memory should contain data');
135+
$this->assertTrue(shmop_delete($dummyShmop));
136+
137+
return $dummyShmop;
138+
});
139+
140+
$process->expects($this->once())
141+
->method('deleteShmop')
142+
->willReturn(true);
143+
144+
$process->expects($this->once())
145+
->method('writeToShmop')
146+
->willReturnCallback(function (Shmop $shmop, string $data) {
147+
unset($shmop);
148+
return mb_strlen($data);
149+
});
150+
151+
$process->send(fn() => 'test');
120152
}
121153
}

0 commit comments

Comments
 (0)