Skip to content

Commit 8e1ef6a

Browse files
committed
Add awaitCompletion tests for nested spawn and child scopes
Cover scenarios not previously tested: - spawn() inside scope's coroutine (same scope inheritance) - child scope via Scope::inherit() with active coroutines - grandchild scope cascading completion - deeply nested spawn() chains
1 parent b08b955 commit 8e1ef6a

4 files changed

Lines changed: 228 additions & 0 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
Scope: awaitCompletion() waits for coroutines spawned inside scope's coroutines
3+
--FILE--
4+
<?php
5+
6+
use Async\Scope;
7+
use function Async\spawn;
8+
use function Async\await;
9+
use function Async\delay;
10+
use function Async\timeout;
11+
12+
echo "start\n";
13+
14+
$scope = Scope::inherit();
15+
$results = [];
16+
17+
$scope->spawn(function() use (&$results) {
18+
$results[] = 'parent_start';
19+
20+
// Nested spawn() — should go into the same scope via ZEND_ASYNC_CURRENT_SCOPE
21+
spawn(function() use (&$results) {
22+
delay(50);
23+
$results[] = 'child_1';
24+
});
25+
26+
spawn(function() use (&$results) {
27+
delay(100);
28+
$results[] = 'child_2';
29+
});
30+
31+
$results[] = 'parent_end';
32+
});
33+
34+
$external = spawn(function() use ($scope) {
35+
try {
36+
$scope->awaitCompletion(timeout(2000));
37+
echo "scope completed\n";
38+
} catch (\Async\OperationCanceledException $e) {
39+
echo "ERROR: timed out\n";
40+
}
41+
});
42+
43+
await($external);
44+
45+
echo "results: " . implode(', ', $results) . "\n";
46+
echo "finished: " . ($scope->isFinished() ? "true" : "false") . "\n";
47+
echo "end\n";
48+
49+
?>
50+
--EXPECT--
51+
start
52+
scope completed
53+
results: parent_start, parent_end, child_1, child_2
54+
finished: true
55+
end
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
Scope: awaitCompletion() waits for child scopes created via Scope::inherit()
3+
--FILE--
4+
<?php
5+
6+
use Async\Scope;
7+
use function Async\spawn;
8+
use function Async\await;
9+
use function Async\delay;
10+
use function Async\timeout;
11+
12+
echo "start\n";
13+
14+
$scope = Scope::inherit();
15+
$results = [];
16+
$childScopeRef = null;
17+
18+
$scope->spawn(function() use (&$results, &$childScopeRef) {
19+
$results[] = 'parent_start';
20+
21+
// Create child scope — inherits from ZEND_ASYNC_CURRENT_SCOPE = $scope
22+
$childScopeRef = Scope::inherit();
23+
24+
$childScopeRef->spawn(function() use (&$results) {
25+
delay(50);
26+
$results[] = 'child_scope_coroutine_1';
27+
});
28+
29+
$childScopeRef->spawn(function() use (&$results) {
30+
delay(100);
31+
$results[] = 'child_scope_coroutine_2';
32+
});
33+
34+
$results[] = 'parent_end';
35+
});
36+
37+
$external = spawn(function() use ($scope) {
38+
try {
39+
$scope->awaitCompletion(timeout(2000));
40+
echo "scope completed\n";
41+
} catch (\Async\OperationCanceledException $e) {
42+
echo "ERROR: timed out\n";
43+
}
44+
});
45+
46+
await($external);
47+
48+
echo "results: " . implode(', ', $results) . "\n";
49+
echo "parent finished: " . ($scope->isFinished() ? "true" : "false") . "\n";
50+
echo "child finished: " . ($childScopeRef->isFinished() ? "true" : "false") . "\n";
51+
echo "end\n";
52+
53+
?>
54+
--EXPECT--
55+
start
56+
scope completed
57+
results: parent_start, parent_end, child_scope_coroutine_1, child_scope_coroutine_2
58+
parent finished: true
59+
child finished: true
60+
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--TEST--
2+
Scope: awaitCompletion() waits for grandchild scopes (cascading completion)
3+
--FILE--
4+
<?php
5+
6+
use Async\Scope;
7+
use function Async\spawn;
8+
use function Async\await;
9+
use function Async\delay;
10+
use function Async\timeout;
11+
12+
echo "start\n";
13+
14+
$scope = Scope::inherit();
15+
$results = [];
16+
$childRef = null;
17+
$grandchildRef = null;
18+
19+
$scope->spawn(function() use (&$results, &$childRef, &$grandchildRef) {
20+
$results[] = 'level_0';
21+
22+
$childRef = Scope::inherit();
23+
$childRef->spawn(function() use (&$results, &$grandchildRef) {
24+
$results[] = 'level_1';
25+
26+
$grandchildRef = Scope::inherit();
27+
$grandchildRef->spawn(function() use (&$results) {
28+
delay(50);
29+
$results[] = 'level_2';
30+
});
31+
});
32+
});
33+
34+
$external = spawn(function() use ($scope) {
35+
try {
36+
$scope->awaitCompletion(timeout(2000));
37+
echo "scope completed\n";
38+
} catch (\Async\OperationCanceledException $e) {
39+
echo "ERROR: timed out\n";
40+
}
41+
});
42+
43+
await($external);
44+
45+
echo "results: " . implode(', ', $results) . "\n";
46+
echo "finished: " . ($scope->isFinished() ? "true" : "false") . "\n";
47+
echo "end\n";
48+
49+
?>
50+
--EXPECT--
51+
start
52+
scope completed
53+
results: level_0, level_1, level_2
54+
finished: true
55+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Scope: awaitCompletion() waits for deeply nested spawn() chains
3+
--FILE--
4+
<?php
5+
6+
use Async\Scope;
7+
use function Async\spawn;
8+
use function Async\await;
9+
use function Async\delay;
10+
use function Async\timeout;
11+
12+
echo "start\n";
13+
14+
$scope = Scope::inherit();
15+
$results = [];
16+
17+
// Coroutine spawns coroutine spawns coroutine — all in the same scope
18+
$scope->spawn(function() use (&$results) {
19+
$results[] = 'a';
20+
21+
spawn(function() use (&$results) {
22+
$results[] = 'b';
23+
delay(20);
24+
25+
spawn(function() use (&$results) {
26+
$results[] = 'c';
27+
delay(20);
28+
29+
spawn(function() use (&$results) {
30+
delay(20);
31+
$results[] = 'd';
32+
});
33+
});
34+
});
35+
});
36+
37+
$external = spawn(function() use ($scope) {
38+
try {
39+
$scope->awaitCompletion(timeout(2000));
40+
echo "scope completed\n";
41+
} catch (\Async\OperationCanceledException $e) {
42+
echo "ERROR: timed out\n";
43+
}
44+
});
45+
46+
await($external);
47+
48+
echo "results: " . implode(', ', $results) . "\n";
49+
echo "finished: " . ($scope->isFinished() ? "true" : "false") . "\n";
50+
echo "end\n";
51+
52+
?>
53+
--EXPECT--
54+
start
55+
scope completed
56+
results: a, b, c, d
57+
finished: true
58+
end

0 commit comments

Comments
 (0)