Skip to content

Commit 889f6d5

Browse files
committed
feat: Refactor test workflows and consolidate route definitions for FPM and Swoole servers
1 parent bff2f3c commit 889f6d5

4 files changed

Lines changed: 173 additions & 286 deletions

File tree

.github/workflows/test.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,17 @@ jobs:
1818
- name: Setup Docker
1919
run: docker compose up -d --build
2020

21-
- name: Wait for Server to be ready
22-
run: sleep 10
21+
- name: Wait for FPM server to be ready
22+
run: |
23+
echo "Waiting for FPM server..."
24+
timeout 30 bash -c 'until curl -sf http://localhost:9020/ > /dev/null 2>&1; do sleep 1; done'
25+
echo "FPM server ready"
26+
27+
- name: Wait for Swoole server to be ready
28+
run: |
29+
echo "Waiting for Swoole server..."
30+
timeout 30 bash -c 'until curl -sf http://localhost:9021/ > /dev/null 2>&1; do sleep 1; done'
31+
echo "Swoole server ready"
2332
2433
- name: Run Tests
25-
run: docker compose exec web vendor/bin/phpunit --configuration phpunit.xml
34+
run: docker compose exec web vendor/bin/phpunit --configuration phpunit.xml

tests/e2e/routes.php

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?php
2+
3+
/**
4+
* Shared route definitions for both FPM and Swoole e2e servers.
5+
* Type hints use base classes so routes work with any adapter.
6+
*/
7+
8+
use Utopia\Http\Http;
9+
use Utopia\Http\Request;
10+
use Utopia\Http\Response;
11+
use Utopia\Validator\Text;
12+
13+
Http::get('/')
14+
->inject('response')
15+
->action(function (Response $response) {
16+
$response->send('Hello World!');
17+
});
18+
19+
Http::get('/value/:value')
20+
->param('value', '', new Text(64))
21+
->inject('response')
22+
->action(function (string $value, Response $response) {
23+
$response->send($value);
24+
});
25+
26+
Http::get('/cookies')
27+
->inject('request')
28+
->inject('response')
29+
->action(function (Request $request, Response $response) {
30+
$response->send($request->getHeaders()['cookie'] ?? '');
31+
});
32+
33+
Http::get('/set-cookie')
34+
->inject('request')
35+
->inject('response')
36+
->action(function (Request $request, Response $response) {
37+
$response->addHeader('Set-Cookie', 'key1=value1');
38+
$response->addHeader('Set-Cookie', 'key2=value2');
39+
$response->send('OK');
40+
});
41+
42+
Http::get('/set-cookie-no-override')
43+
->inject('request')
44+
->inject('response')
45+
->action(function (Request $request, Response $response) {
46+
$response->addHeader('Set-Cookie', 'key1=value1', override: false);
47+
$response->addHeader('Set-Cookie', 'key2=value2', override: false);
48+
$response->send('OK');
49+
});
50+
51+
Http::get('/chunked')
52+
->inject('response')
53+
->action(function (Response $response) {
54+
foreach (['Hello ', 'World!'] as $key => $word) {
55+
$response->chunk($word, $key == 1);
56+
}
57+
});
58+
59+
Http::get('/redirect')
60+
->inject('response')
61+
->action(function (Response $response) {
62+
$response->redirect('/');
63+
});
64+
65+
Http::get('/humans.txt')
66+
->inject('response')
67+
->action(function (Response $response) {
68+
$response->noContent();
69+
});
70+
71+
Http::post('/functions/deployment')
72+
->alias('/functions/deployment/:deploymentId')
73+
->param('deploymentId', '', new Text(64, 0), '', true)
74+
->inject('response')
75+
->action(function (string $deploymentId, Response $response) {
76+
if (empty($deploymentId)) {
77+
$response->noContent();
78+
return;
79+
}
80+
81+
$response->send('ID:' . $deploymentId);
82+
});
83+
84+
Http::post('/databases/:databaseId/collections/:collectionId')
85+
->alias('/database/collections/:collectionId')
86+
->param('databaseId', '', new Text(64, 0), '', true)
87+
->param('collectionId', '', new Text(64, 0), '', true)
88+
->inject('response')
89+
->action(function (string $databaseId, string $collectionId, Response $response) {
90+
$response->send($databaseId . ';' . $collectionId);
91+
});
92+
93+
// Endpoints for early response
94+
// Meant to run twice, so init hook can know if action ran
95+
$earlyResponseAction = 'no';
96+
Http::init()
97+
->groups(['early-response'])
98+
->inject('response')
99+
->action(function (Response $response) use ($earlyResponseAction) {
100+
$response->send('Init response. Actioned before: ' . $earlyResponseAction);
101+
});
102+
103+
Http::get('/early-response')
104+
->groups(['early-response'])
105+
->inject('response')
106+
->action(function (Response $response) use (&$earlyResponseAction) {
107+
$earlyResponseAction = 'yes';
108+
$response->send('Action response');
109+
});
110+
111+
// ── Streaming endpoints ──
112+
113+
Http::get('/stream/generator')
114+
->inject('response')
115+
->action(function (Response $response) {
116+
$chunks = ['chunk1-', 'chunk2-', 'chunk3'];
117+
$totalSize = array_sum(array_map('strlen', $chunks));
118+
119+
$generator = (function () use ($chunks) {
120+
foreach ($chunks as $chunk) {
121+
yield $chunk;
122+
}
123+
})();
124+
125+
$response->stream($generator, $totalSize);
126+
});
127+
128+
Http::get('/stream/callable')
129+
->inject('response')
130+
->action(function (Response $response) {
131+
$data = str_repeat('A', 1000);
132+
133+
$response->stream(function (int $offset, int $length) use ($data) {
134+
return substr($data, $offset, $length);
135+
}, strlen($data));
136+
});
137+
138+
Http::get('/stream/generator-large')
139+
->inject('response')
140+
->action(function (Response $response) {
141+
$chunkSize = 100000; // 100KB per chunk
142+
$numChunks = 5;
143+
$totalSize = $chunkSize * $numChunks;
144+
145+
$generator = (function () use ($chunkSize, $numChunks) {
146+
for ($i = 0; $i < $numChunks; $i++) {
147+
yield str_repeat(chr(65 + $i), $chunkSize);
148+
}
149+
})();
150+
151+
$response->stream($generator, $totalSize);
152+
});

tests/e2e/server.php

Lines changed: 2 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,18 @@
11
<?php
22

3-
require_once __DIR__.'/../../vendor/autoload.php';
3+
require_once __DIR__ . '/../../vendor/autoload.php';
44

55
use Utopia\Http\Http;
66
use Utopia\Http\Adapter\FPM\Request;
77
use Utopia\Http\Adapter\FPM\Response;
8-
use Utopia\Validator\Text;
98

109
ini_set('memory_limit', '1024M');
1110
ini_set('display_errors', '1');
1211
ini_set('display_startup_errors', '1');
1312
ini_set('display_socket_timeout', '-1');
1413
error_reporting(E_ALL);
1514

16-
Http::get('/')
17-
->inject('response')
18-
->action(function (Response $response) {
19-
$response->send('Hello World!');
20-
});
21-
22-
Http::get('/value/:value')
23-
->param('value', '', new Text(64))
24-
->inject('response')
25-
->action(function (string $value, Response $response) {
26-
$response->send($value);
27-
});
28-
29-
Http::get('/cookies')
30-
->inject('request')
31-
->inject('response')
32-
->action(function (Request $request, Response $response) {
33-
$response->send($request->getHeaders()['cookie'] ?? '');
34-
});
35-
36-
Http::get('/set-cookie')
37-
->inject('request')
38-
->inject('response')
39-
->action(function (Request $request, Response $response) {
40-
$response->addHeader('Set-Cookie', 'key1=value1');
41-
$response->addHeader('Set-Cookie', 'key2=value2');
42-
$response->send('OK');
43-
});
44-
45-
Http::get('/set-cookie-no-override')
46-
->inject('request')
47-
->inject('response')
48-
->action(function (Request $request, Response $response) {
49-
$response->addHeader('Set-Cookie', 'key1=value1', override: false);
50-
$response->addHeader('Set-Cookie', 'key2=value2', override: false);
51-
$response->send('OK');
52-
});
53-
54-
Http::get('/chunked')
55-
->inject('response')
56-
->action(function (Response $response) {
57-
foreach (['Hello ', 'World!'] as $key => $word) {
58-
$response->chunk($word, $key == 1);
59-
}
60-
});
61-
62-
Http::get('/redirect')
63-
->inject('response')
64-
->action(function (Response $response) {
65-
$response->redirect('/');
66-
});
67-
68-
Http::get('/humans.txt')
69-
->inject('response')
70-
->action(function (Response $response) {
71-
$response->noContent();
72-
});
73-
74-
Http::post('/functions/deployment')
75-
->alias('/functions/deployment/:deploymentId')
76-
->param('deploymentId', '', new Text(64, 0), '', true)
77-
->inject('response')
78-
->action(function (string $deploymentId, Response $response) {
79-
if (empty($deploymentId)) {
80-
$response->noContent();
81-
return;
82-
}
83-
84-
$response->send('ID:' . $deploymentId);
85-
});
86-
87-
Http::post('/databases/:databaseId/collections/:collectionId')
88-
->alias('/database/collections/:collectionId')
89-
->param('databaseId', '', new Text(64, 0), '', true)
90-
->param('collectionId', '', new Text(64, 0), '', true)
91-
->inject('response')
92-
->action(function (string $databaseId, string $collectionId, Response $response) {
93-
$response->send($databaseId . ';' . $collectionId);
94-
});
95-
96-
// Endpoints for early response
97-
// Meant to run twice, so init hook can know if action ran
98-
$earlyResponseAction = 'no';
99-
Http::init()
100-
->groups(['early-response'])
101-
->inject('response')
102-
->action(function (Response $response) use ($earlyResponseAction) {
103-
$response->send('Init response. Actioned before: ' . $earlyResponseAction);
104-
});
105-
106-
Http::get('/early-response')
107-
->groups(['early-response'])
108-
->inject('response')
109-
->action(function (Response $response) use (&$earlyResponseAction) {
110-
$earlyResponseAction = 'yes';
111-
$response->send('Action response');
112-
});
113-
114-
// ── Streaming endpoints ──
115-
116-
Http::get('/stream/generator')
117-
->inject('response')
118-
->action(function (Response $response) {
119-
$chunks = ['chunk1-', 'chunk2-', 'chunk3'];
120-
$totalSize = array_sum(array_map('strlen', $chunks));
121-
122-
$generator = (function () use ($chunks) {
123-
foreach ($chunks as $chunk) {
124-
yield $chunk;
125-
}
126-
})();
127-
128-
$response->stream($generator, $totalSize);
129-
});
130-
131-
Http::get('/stream/callable')
132-
->inject('response')
133-
->action(function (Response $response) {
134-
$data = str_repeat('A', 1000);
135-
136-
$response->stream(function (int $offset, int $length) use ($data) {
137-
return substr($data, $offset, $length);
138-
}, strlen($data));
139-
});
140-
141-
Http::get('/stream/generator-large')
142-
->inject('response')
143-
->action(function (Response $response) {
144-
$chunkSize = 100000; // 100KB per chunk
145-
$numChunks = 5;
146-
$totalSize = $chunkSize * $numChunks;
147-
148-
$generator = (function () use ($chunkSize, $numChunks) {
149-
for ($i = 0; $i < $numChunks; $i++) {
150-
yield str_repeat(chr(65 + $i), $chunkSize);
151-
}
152-
})();
153-
154-
$response->stream($generator, $totalSize);
155-
});
15+
require_once __DIR__ . '/routes.php';
15616

15717
$request = new Request();
15818
$response = new Response();

0 commit comments

Comments
 (0)