Skip to content

Commit 4a993ec

Browse files
committed
Replace cancellation tests with Promise::race() performance test
1 parent 2f42ae9 commit 4a993ec

File tree

1 file changed

+13
-245
lines changed

1 file changed

+13
-245
lines changed

test.php

Lines changed: 13 additions & 245 deletions
Original file line numberDiff line numberDiff line change
@@ -1,258 +1,26 @@
11
<?php
22

3+
use Rcalicdan\FiberAsync\Promise\Promise;
34

4-
use Rcalicdan\FiberAsync\Api\Timer;
55

66
require_once __DIR__ . '/vendor/autoload.php';
77

8-
function logWithTimestamp(string $message): void {
9-
$timestamp = number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 4);
10-
echo "[{$timestamp}s] {$message}" . PHP_EOL;
11-
}
8+
$microtime = microtime(true);
9+
$results = run(function () {
10+
$Promise = Promise::race([
11+
'google' => http()->get('https://www.google.com')->then(fn()=>print"google wins\n"),
12+
'facebook' => http()->get('https://www.facebook.com')->then(fn()=>print"facebook wins\n"),
13+
'linkedIn' => http()->get('https://www.linkedin.com')->then(fn()=>print"linkedIn wins\n"),
14+
'instagram' => http()->get('https://www.instagram.com')->then(fn()=>print"instagram wins\n"),
15+
]);
1216

13-
$startTime = microtime(true);
14-
$_SERVER['REQUEST_TIME_FLOAT'] = $startTime;
15-
16-
logWithTimestamp("=== Testing Cancellable Streaming Promises ===\n");
17-
18-
// Test 1: Cancel a streaming request mid-way
19-
logWithTimestamp("--- Test 1: Cancel streaming request after 1 second ---");
20-
21-
$test1Result = run(function () {
22-
logWithTimestamp("Starting long-running stream (5 second delay)...");
23-
24-
$chunkCount = 0;
25-
$streamPromise = http_stream('https://httpbin.org/delay/5', [
26-
'timeout' => 10
27-
], function($chunk) use (&$chunkCount) {
28-
$chunkCount++;
29-
logWithTimestamp("Stream chunk #{$chunkCount} received: " . strlen($chunk) . " bytes");
30-
});
31-
32-
// Set up cancellation after 1 second using Timer::delay
33-
logWithTimestamp("Setting up cancellation timer for 1 second...");
34-
Timer::delay(1.0)->then(function() use ($streamPromise) {
35-
logWithTimestamp("⚠️ CANCELLING STREAM NOW!");
36-
$streamPromise->cancel();
37-
logWithTimestamp("Cancel signal sent");
38-
});
39-
40-
try {
41-
logWithTimestamp("Waiting for stream result...");
42-
$result = await($streamPromise);
43-
logWithTimestamp("❌ ERROR: Stream completed instead of being cancelled!");
44-
return ['status' => 'completed', 'chunks' => $chunkCount];
45-
} catch (Exception $e) {
46-
logWithTimestamp("✅ SUCCESS: Stream was cancelled - " . $e->getMessage());
47-
return ['status' => 'cancelled', 'chunks' => $chunkCount, 'error' => $e->getMessage()];
48-
}
49-
});
50-
51-
logWithTimestamp("Test 1 result: " . $test1Result['status']);
52-
logWithTimestamp("Chunks received before cancellation: " . $test1Result['chunks']);
53-
logWithTimestamp("Is promise cancelled: " . (method_exists($streamPromise ?? null, 'isCancelled') ? ($streamPromise->isCancelled() ? 'Yes' : 'No') : 'Unknown'));
54-
55-
echo "\n";
56-
57-
// Test 2: Cancel a download mid-way
58-
logWithTimestamp("--- Test 2: Cancel file download after 0.5 seconds ---");
59-
60-
$test2Result = run(function () {
61-
$tempFile = sys_get_temp_dir() . '/cancel_test_' . uniqid() . '.tmp';
62-
logWithTimestamp("Starting download to: " . basename($tempFile));
63-
64-
// Use a larger file for download to ensure we can cancel it
65-
$downloadPromise = http_download('https://httpbin.org/delay/3', $tempFile);
66-
67-
// Cancel after 0.5 seconds using Timer::delay
68-
logWithTimestamp("Setting up cancellation timer for 0.5 seconds...");
69-
Timer::delay(0.5)->then(function() use ($downloadPromise) {
70-
logWithTimestamp("⚠️ CANCELLING DOWNLOAD NOW!");
71-
$downloadPromise->cancel();
72-
logWithTimestamp("Download cancel signal sent");
73-
});
74-
75-
try {
76-
logWithTimestamp("Waiting for download result...");
77-
$result = await($downloadPromise);
78-
logWithTimestamp("❌ ERROR: Download completed instead of being cancelled!");
79-
80-
// Clean up file if it exists
81-
if (file_exists($result['file'])) {
82-
unlink($result['file']);
83-
}
84-
85-
return ['status' => 'completed'];
86-
} catch (Exception $e) {
87-
logWithTimestamp("✅ SUCCESS: Download was cancelled - " . $e->getMessage());
88-
89-
// Verify file was cleaned up
90-
$fileExists = file_exists($tempFile);
91-
logWithTimestamp("Partial file cleaned up: " . ($fileExists ? "❌ No" : "✅ Yes"));
92-
93-
return [
94-
'status' => 'cancelled',
95-
'file_cleaned' => !$fileExists,
96-
'error' => $e->getMessage(),
97-
'is_cancelled' => $downloadPromise->isCancelled()
98-
];
99-
}
100-
});
101-
102-
logWithTimestamp("Test 2 result: " . $test2Result['status']);
103-
if (isset($test2Result['file_cleaned'])) {
104-
logWithTimestamp("File cleanup successful: " . ($test2Result['file_cleaned'] ? "✅ Yes" : "❌ No"));
105-
logWithTimestamp("Promise cancelled status: " . ($test2Result['is_cancelled'] ? "✅ Yes" : "❌ No"));
106-
}
107-
108-
echo "\n";
109-
110-
// Test 3: Test immediate cancellation
111-
logWithTimestamp("--- Test 3: Immediate cancellation ---");
112-
113-
$test3Result = run(function () {
114-
logWithTimestamp("Creating stream promise...");
115-
116-
$streamPromise = http_stream('https://httpbin.org/delay/2', [], function($chunk) {
117-
logWithTimestamp("❌ This should not be called - chunk received: " . strlen($chunk) . " bytes");
118-
});
119-
120-
logWithTimestamp("Checking initial cancelled status: " . ($streamPromise->isCancelled() ? "Yes" : "No"));
121-
logWithTimestamp("Cancelling immediately...");
122-
$streamPromise->cancel();
123-
logWithTimestamp("Cancelled status after cancel(): " . ($streamPromise->isCancelled() ? "Yes" : "No"));
124-
125-
try {
126-
$result = await($streamPromise);
127-
logWithTimestamp("❌ ERROR: Stream completed despite immediate cancellation!");
128-
return ['status' => 'completed'];
129-
} catch (Exception $e) {
130-
logWithTimestamp("✅ SUCCESS: Immediate cancellation worked - " . $e->getMessage());
131-
return ['status' => 'cancelled', 'error' => $e->getMessage(), 'is_cancelled' => $streamPromise->isCancelled()];
132-
}
133-
});
134-
135-
logWithTimestamp("Test 3 result: " . $test3Result['status']);
136-
logWithTimestamp("Final cancelled status: " . ($test3Result['is_cancelled'] ? "✅ Yes" : "❌ No"));
137-
138-
echo "\n";
139-
140-
// Test 4: Test cancellation with multiple promises
141-
logWithTimestamp("--- Test 4: Cancel individual promises in concurrent execution ---");
142-
143-
$test4Result = run(function () {
144-
logWithTimestamp("Starting multiple streams...");
145-
146-
$stream1Chunks = 0;
147-
$stream2Chunks = 0;
148-
149-
$stream1 = http_stream('https://httpbin.org/delay/1', [], function($chunk) use (&$stream1Chunks) {
150-
$stream1Chunks++;
151-
logWithTimestamp("Stream1 chunk: " . strlen($chunk) . " bytes");
152-
});
153-
154-
$stream2 = http_stream('https://httpbin.org/delay/4', [], function($chunk) use (&$stream2Chunks) {
155-
$stream2Chunks++;
156-
logWithTimestamp("Stream2 (will be cancelled) chunk: " . strlen($chunk) . " bytes");
157-
});
158-
159-
// Cancel stream2 after 1.5 seconds
160-
Timer::delay(1.5)->then(function() use ($stream2) {
161-
logWithTimestamp("⚠️ CANCELLING STREAM2 after 1.5s!");
162-
$stream2->cancel();
163-
logWithTimestamp("Stream2 cancelled status: " . ($stream2->isCancelled() ? "Yes" : "No"));
164-
});
165-
166-
// Wait for both individually to see their results
167-
$results = [];
168-
169-
try {
170-
$results['stream1'] = await($stream1);
171-
logWithTimestamp("✅ Stream1 completed successfully");
172-
} catch (Exception $e) {
173-
logWithTimestamp("Stream1 failed: " . $e->getMessage());
174-
$results['stream1'] = null;
175-
}
176-
177-
try {
178-
$results['stream2'] = await($stream2);
179-
logWithTimestamp("❌ Stream2 completed (should have been cancelled)");
180-
} catch (Exception $e) {
181-
logWithTimestamp("✅ Stream2 was cancelled: " . $e->getMessage());
182-
$results['stream2'] = null;
183-
}
184-
185-
return [
186-
'stream1_completed' => $results['stream1'] !== null,
187-
'stream2_cancelled' => $stream2->isCancelled(),
188-
'stream1_chunks' => $stream1Chunks,
189-
'stream2_chunks' => $stream2Chunks,
190-
];
17+
return await($Promise);
19118
});
19219

193-
logWithTimestamp("Test 4 results:");
194-
logWithTimestamp("- Stream1 completed: " . ($test4Result['stream1_completed'] ? "✅ Yes" : "❌ No"));
195-
logWithTimestamp("- Stream2 cancelled: " . ($test4Result['stream2_cancelled'] ? "✅ Yes" : "❌ No"));
196-
logWithTimestamp("- Stream1 chunks: " . $test4Result['stream1_chunks']);
197-
logWithTimestamp("- Stream2 chunks: " . $test4Result['stream2_chunks']);
20+
$microtime = microtime(true) - $microtime;
21+
echo $microtime . PHP_EOL;
19822

199-
echo "\n";
20023

201-
// Test 5: Test cancel handler is called
202-
logWithTimestamp("--- Test 5: Verify cancel handler is called ---");
203-
204-
$test5Result = run(function () {
205-
$cancelHandlerCalled = false;
206-
$cleanupExecuted = false;
207-
208-
logWithTimestamp("Creating stream with custom cancel handler...");
209-
210-
$streamPromise = http_stream('https://httpbin.org/delay/3', [], function($chunk) {
211-
logWithTimestamp("Chunk received: " . strlen($chunk) . " bytes");
212-
});
213-
214-
// Add additional cancel handler to test if it's called
215-
$originalSetCancelHandler = [$streamPromise, 'setCancelHandler'];
216-
if (is_callable($originalSetCancelHandler)) {
217-
// Get the original handler first
218-
$streamPromise->setCancelHandler(function() use (&$cancelHandlerCalled, &$cleanupExecuted) {
219-
$cancelHandlerCalled = true;
220-
logWithTimestamp("🔧 Custom cancel handler called!");
221-
222-
// Simulate cleanup
223-
$cleanupExecuted = true;
224-
logWithTimestamp("🧹 Cleanup executed in cancel handler");
225-
});
226-
}
227-
228-
// Cancel after 1 second
229-
Timer::delay(1.0)->then(function() use ($streamPromise) {
230-
logWithTimestamp("⚠️ Cancelling stream to test cancel handler...");
231-
$streamPromise->cancel();
232-
});
233-
234-
try {
235-
await($streamPromise);
236-
logWithTimestamp("❌ Stream completed unexpectedly");
237-
return ['completed' => true];
238-
} catch (Exception $e) {
239-
logWithTimestamp("✅ Stream cancelled: " . $e->getMessage());
240-
241-
return [
242-
'cancelled' => true,
243-
'cancel_handler_called' => $cancelHandlerCalled,
244-
'cleanup_executed' => $cleanupExecuted,
245-
'is_cancelled' => $streamPromise->isCancelled()
246-
];
247-
}
248-
});
24+
24925

250-
if (isset($test5Result['cancelled'])) {
251-
logWithTimestamp("Test 5 results:");
252-
logWithTimestamp("- Promise cancelled: " . ($test5Result['is_cancelled'] ? "✅ Yes" : "❌ No"));
253-
logWithTimestamp("- Cancel handler called: " . ($test5Result['cancel_handler_called'] ? "✅ Yes" : "❌ No"));
254-
logWithTimestamp("- Cleanup executed: " . ($test5Result['cleanup_executed'] ? "✅ Yes" : "❌ No"));
255-
}
25626

257-
$totalTime = microtime(true) - $startTime;
258-
logWithTimestamp("\n=== All cancellation tests completed in " . number_format($totalTime, 4) . "s ===");

0 commit comments

Comments
 (0)