Skip to content

Commit b2ffda2

Browse files
authored
Merge pull request #989 from appwrite/feat-better-multipart-tests
feat: better multipart tests
2 parents 35c43c9 + a796ccc commit b2ffda2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+757
-211
lines changed

.github/workflows/tests.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,23 @@ jobs:
100100

101101
- name: Lint
102102
run: composer lint
103+
104+
specs:
105+
runs-on: ubuntu-latest
106+
107+
steps:
108+
- name: Checkout code
109+
uses: actions/checkout@v4
110+
111+
- name: Setup PHP with PECL extension
112+
uses: shivammathur/setup-php@v2
113+
with:
114+
php-version: ${{ matrix.php-version }}
115+
extensions: curl
116+
117+
- name: Install
118+
run: composer install
119+
120+
- name: Validate specs
121+
run: composer test tests/SpecsTest.php
122+

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"ext-mbstring": "*",
3232
"ext-json": "*",
3333
"twig/twig": "3.14.*",
34-
"matthiasmullie/minify": "1.3.*"
34+
"matthiasmullie/minify": "1.3.*",
35+
"utopia-php/fetch": "^0.2.1"
3536
},
3637
"require-dev": {
3738
"phpunit/phpunit": "11.*",

composer.lock

Lines changed: 58 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mock-server/app/http.php

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,18 @@
325325

326326
$chunkSize = 5 * 1024 * 1024; // 5MB
327327

328+
if ($x != 'string') {
329+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong string value: ' . $x . ', expected: string');
330+
}
331+
332+
if ($y !== 123) {
333+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong numeric value: ' . $y . ', expected: 123');
334+
}
335+
336+
if ($z[0] !== 'string in array' || \count($z) !== 1) {
337+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong array value: ' . \json_encode($z) . ', expected: ["string in array"]');
338+
}
339+
328340
if (!empty($contentRange)) {
329341
$start = $request->getContentRangeStart();
330342
$end = $request->getContentRangeEnd();
@@ -373,15 +385,16 @@
373385
$file['size'] = (\is_array($file['size'])) ? $file['size'][0] : $file['size'];
374386

375387
if ($file['name'] !== 'file.png') {
376-
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file name');
388+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file name: ' . $file['name'] . ', expected: file.png');
377389
}
378390

379391
if ($file['size'] !== 38756) {
380-
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
392+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size: ' . $file['size'] . ', expected: 38756');
381393
}
382394

383-
if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
384-
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file uploaded');
395+
$hash = \md5(\file_get_contents($file['tmp_name']));
396+
if ($hash !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
397+
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file uploaded: ' . $hash . ', expected: d80e7e6999a3eb2ae0d631a96fe135a4');
385398
}
386399
}
387400
});
@@ -410,6 +423,41 @@
410423
]);
411424
});
412425

426+
App::post('/v1/mock/tests/general/multipart-echo')
427+
->desc('Multipart echo')
428+
->groups(['mock'])
429+
->label('scope', 'public')
430+
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
431+
->label('sdk.namespace', 'general')
432+
->label('sdk.method', 'multipartEcho')
433+
->label('sdk.description', 'Echo a multipart request.')
434+
->label('sdk.response.code', Response::STATUS_CODE_OK)
435+
->label('sdk.response.type', Response::CONTENT_TYPE_MULTIPART)
436+
->label('sdk.response.model', Response::MODEL_MULTIPART)
437+
->label('sdk.mock', true)
438+
->param('body', '', new File(), 'Sample file param', false, [], true)
439+
->inject('response')
440+
->inject('request')
441+
->action(function (string $body, Response $response, Request $request) {
442+
if (empty($body)) {
443+
$file = $request->getFiles('body');
444+
445+
if (empty($file)) {
446+
$file = $request->getFiles(0);
447+
}
448+
449+
if (isset($file['tmp_name'])) {
450+
$body = \file_get_contents($file['tmp_name']);
451+
} else {
452+
$body = '';
453+
}
454+
}
455+
456+
$response->multipart([
457+
'responseBody' => $body
458+
]);
459+
});
460+
413461
App::get('/v1/mock/tests/general/redirect')
414462
->desc('Redirect')
415463
->groups(['mock'])

mock-server/docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
services:
22
mockapi:
33
container_name: mockapi
4+
ports:
5+
- 3175:80
46
build:
57
context: .
68
args:

src/SDK/Language/Ruby.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ public function getTypeName(array $parameter, array $spec = []): string
214214
self::TYPE_STRING => 'String',
215215
self::TYPE_ARRAY => 'Array',
216216
self::TYPE_OBJECT => 'Hash',
217+
self::TYPE_FILE => 'Payload',
218+
self::TYPE_PAYLOAD => 'Payload',
217219
self::TYPE_BOOLEAN => '',
218220
default => $parameter['type'],
219221
};

templates/android/library/src/main/java/io/package/Client.kt.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,14 @@ class Client @JvmOverloads constructor(
285285
)
286286
}
287287
}
288+
it.value is Payload -> {
289+
val payload = it.value as Payload
290+
if (payload.sourceType == "path") {
291+
builder.addFormDataPart(it.key, payload.filename, File(payload.path).asRequestBody())
292+
} else {
293+
builder.addFormDataPart(it.key, payload.toString())
294+
}
295+
}
288296
else -> {
289297
builder.addFormDataPart(it.key, it.value.toString())
290298
}

templates/android/library/src/main/java/io/package/models/Payload.kt.twig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class Payload private constructor() {
3939
}
4040

4141
fun toFile(path: String): File {
42+
Files.createDirectories(Paths.get(path).parent);
43+
4244
val file = File(path)
4345
file.appendBytes(toBinary())
4446
return file

templates/dart/lib/payload.dart.twig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:convert';
22
import 'src/exception.dart';
3+
import 'dart:io';
34

45
class Payload {
56
late final String? path;
@@ -44,6 +45,15 @@ class Payload {
4445
}
4546
}
4647

48+
/// Create a file from the payload
49+
void toFile(String path) {
50+
if(data == null) {
51+
throw {{spec.title | caseUcfirst}}Exception('`data` is not defined.');
52+
}
53+
final file = File(path);
54+
file.writeAsBytesSync(data!);
55+
}
56+
4757
/// Create a Payload from binary data
4858
factory Payload.fromBinary({
4959
required List<int> data,

templates/deno/src/payload.ts.twig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { basename } from "https://deno.land/[email protected]/path/mod.ts";
1+
import { basename, dirname } from "https://deno.land/[email protected]/path/mod.ts";
22

33
export class Payload {
44
private data: Uint8Array;
@@ -30,6 +30,7 @@ export class Payload {
3030
}
3131

3232
public async toFile(path: string): Promise<void> {
33+
await Deno.mkdir(dirname(path), { recursive: true });
3334
await Deno.writeFile(path, this.data);
3435
}
3536

0 commit comments

Comments
 (0)