Skip to content

Commit 22c8173

Browse files
committed
add functional tests
1 parent 48ab997 commit 22c8173

36 files changed

+3599
-24
lines changed

.docker/test/Dockerfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
FROM php:7.4-cli-bullseye
2+
3+
RUN apt-get update -q \
4+
&& apt-get install -y -q --no-install-recommends \
5+
git unzip libssl-dev libcurl4-openssl-dev libzip-dev \
6+
&& docker-php-ext-install pdo pdo_mysql \
7+
&& docker-php-ext-configure curl \
8+
&& docker-php-ext-install curl \
9+
&& rm -rf /var/lib/apt/lists/*
10+
11+
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
12+
13+
WORKDIR /app

.github/workflows/tests_phpunit.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ on:
77
branches: [ master ]
88

99
jobs:
10+
# ---------------------------------------------------------------------------
11+
# Unit tests — no database required
12+
# ---------------------------------------------------------------------------
1013
unit:
1114
name: Unit tests (PHP ${{ matrix.php }})
1215
runs-on: ubuntu-latest
@@ -31,4 +34,25 @@ jobs:
3134

3235
- name: Run unit tests
3336
working-directory: api
34-
run: vendor/bin/phpunit --configuration phpunit.xml
37+
run: vendor/bin/phpunit --configuration phpunit.xml --testsuite Unit
38+
39+
# ---------------------------------------------------------------------------
40+
# Functional tests — Apache/PHP 7.4 + MySQL 8.0 via Docker Compose
41+
# ---------------------------------------------------------------------------
42+
functional:
43+
name: Functional tests
44+
runs-on: ubuntu-latest
45+
needs: unit
46+
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- name: Build test images
51+
run: docker compose -f docker-compose.test.yml build
52+
53+
- name: Run functional tests
54+
run: docker compose -f docker-compose.test.yml run --rm phpunit
55+
56+
- name: Tear down
57+
if: always()
58+
run: docker compose -f docker-compose.test.yml down -v

api/src/core/Tool.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ public static function endWithJson($_payload, $code = 200) {
4646

4747
$payload = self::getPayload($_payload);
4848
$app->response->headers->set('Content-Type', 'application/json');
49-
$app->halt($code, json_encode($payload));
49+
// If the payload is a PaginatedCollection, getPayload() already called
50+
// setStatus() on $app->response (e.g. 206 for partial range, 400 for
51+
// out-of-range start). Respect that status instead of always using 200.
52+
$effectiveCode = ($_payload instanceof \API\Core\PaginatedCollection)
53+
? $app->response->getStatus()
54+
: $code;
55+
$app->halt($effectiveCode, json_encode($payload));
5056
}
5157

5258
/**
@@ -105,7 +111,7 @@ public static function endWithRSS($_payload, $feed_title = '', $code = 200) {
105111
break;
106112
}
107113
}
108-
if (empty($description)) {
114+
if (empty($description) && count($plugin['descriptions']) > 0) {
109115
$description = $plugin['descriptions'][0]['long_description'];
110116
}
111117

@@ -160,7 +166,7 @@ public static function makeEndpoint($callable) {
160166
try {
161167
call_user_func_array($callable, $args);
162168
}
163-
catch (\Exception $e) {
169+
catch (\Throwable $e) {
164170
global $app;
165171
if (!preg_match('/^API\\\\Exception/', get_class($e))) {
166172
switch (get_class($e)) {
@@ -316,7 +322,8 @@ public static function getRequestLang() {
316322
public static $config = null;
317323
public static function getConfig() {
318324
if (!self::$config) {
319-
require dirname(__FILE__) . '/../../config.php';
325+
$configFile = getenv('APP_CONFIG_FILE') ?: dirname(__FILE__) . '/../../config.php';
326+
require $configFile;
320327
self::$config = $config;
321328
}
322329
return self::$config;

api/src/endpoints/App.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
throw new InvalidField('name');
6969
} else if (App::where('user_id', '=', $user_id)
7070
->where('name', '=', $body->name)->first() != null) {
71-
throw new UnavailableName('app', $name);
71+
throw new UnavailableName('app', $body->name);
7272
}
7373
else {
7474
$app->name = $body->name;

api/src/endpoints/Author.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
->withAverageNote()
7575
->descWithLang(Tool::getRequestLang())
7676
->whereAuthor($author->id)
77+
->where('active', '=', 1)
7778
)
7879
);
7980
});

api/src/endpoints/Message.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
use \API\Exception\MissingField;
2323
use \API\Exception\InvalidRecaptcha;
2424

25-
require dirname(__FILE__) . '/../../config.php';
26-
2725
$send = Tool::makeEndpoint(function() use($app) {
2826
OAuthHelper::needsScopes(['message']);
2927

@@ -32,7 +30,7 @@
3230
$fields = ['firstname', 'lastname', 'email', 'subject', 'message'];
3331

3432
$recaptcha = new ReCaptcha(Tool::getConfig()['recaptcha_secret']);
35-
$resp = $recaptcha->verify($body->recaptcha_response);
33+
$resp = $recaptcha->verify($body->recaptcha_response ?? null);
3634
if (!$resp->isSuccess()) {
3735
throw new InvalidRecaptcha();
3836
}

api/src/endpoints/Plugin.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
if (isset($body->xml_url)) {
147147
// We check if the URL is a correct URI
148148
if (!filter_var($body->xml_url, FILTER_VALIDATE_URL)) {
149-
throw new InvalidField;
149+
throw new InvalidField('xml_url');
150150
}
151151

152152
// We check if we can fetch the file via HTTP
@@ -530,7 +530,7 @@
530530
$body = Tool::getBody();
531531

532532
$recaptcha = new ReCaptcha(Tool::getConfig()['recaptcha_secret']);
533-
$resp = $recaptcha->verify($body->recaptcha_response);
533+
$resp = $recaptcha->verify($body->recaptcha_response ?? null);
534534
if (!$resp->isSuccess()) {
535535
throw new InvalidRecaptcha;
536536
}

api/src/endpoints/User.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
use API\Exception\InvalidCredentials;
3535
use API\Exception\InvalidXML;
3636
use API\Exception\WrongPasswordResetToken;
37+
use API\Exception\AccountNotFound;
38+
use API\Exception\ResourceNotFound;
3739

3840
use League\OAuth2\Server\Util\SecureKey;
3941
use API\OAuthServer\AuthorizationServer;
@@ -471,7 +473,7 @@
471473
$user->setPassword($body->password);
472474
$user->save();
473475
// Deleting the ResetPasswordToken objects for this user
474-
$user->passwordResetTokens()->truncate();
476+
$user->passwordResetTokens()->delete();
475477
$app->halt(200);
476478
});
477479

api/src/endpoints/Version.php

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
11
<?php
2-
3-
use \Illuminate\Database\Capsule\Manager as DB;
42
use \API\Core\Tool;
53
use \API\Model\Plugin;
6-
74
use \API\OAuthServer\OAuthHelper;
8-
95
$version_plugins = Tool::makeEndpoint(function($version) {
106
OAuthHelper::needsScopes(['version', 'plugins']);
11-
127
$plugins = Tool::paginateCollection(Plugin::short()
13-
->with('authors', 'versions', 'descriptions')
14-
->withAverageNote()
15-
->descWithLang(Tool::getRequestLang())
16-
->withGlpiVersion($version));
8+
->with('authors', 'versions', 'descriptions')
9+
->withAverageNote()
10+
->descWithLang(Tool::getRequestLang())
11+
->withGlpiVersion($version));
1712
Tool::endWithJson($plugins);
1813
});
19-
20-
$app->get('/version/:version/plugin', $version_plugins);
21-
$app->options('/version/:version/plugin', function() {});
14+
$app->get("/version/:version/plugin", $version_plugins);
15+
$app->options("/version/:version/plugin", function() {});

api/src/oauthserver/AuthorizationServer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public function __construct() {
5353
return false;
5454
} else {
5555
$user = $user->first();
56+
if (!$user->active) {
57+
return false;
58+
}
5659
if ($user->assertPasswordIs($password)) {
5760
return $user->id;
5861
} else {

0 commit comments

Comments
 (0)