new: initial api and integration tests.
parent
63af5d080f
commit
a473a9d3fb
|
@ -7,3 +7,5 @@ vendor
|
||||||
webroot/theme/node_modules
|
webroot/theme/node_modules
|
||||||
.vscode
|
.vscode
|
||||||
docker/run/
|
docker/run/
|
||||||
|
.phpunit.result.cache
|
||||||
|
config.json
|
Binary file not shown.
|
@ -15,17 +15,17 @@
|
||||||
<testsuite name="app">
|
<testsuite name="app">
|
||||||
<directory>tests/TestCase/</directory>
|
<directory>tests/TestCase/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<!-- Add plugin test suites here. -->
|
<testsuite name="controller">
|
||||||
|
<directory>./tests/TestCase/Controller</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="api">
|
||||||
|
<directory>./tests/TestCase/Api</directory>
|
||||||
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<!-- Setup a listener for fixtures -->
|
<extensions>
|
||||||
<listeners>
|
<extension class="\Cake\TestSuite\Fixture\PHPUnitExtension" />
|
||||||
<listener class="Cake\TestSuite\Fixture\FixtureInjector">
|
</extensions>
|
||||||
<arguments>
|
|
||||||
<object class="Cake\TestSuite\Fixture\FixtureManager"/>
|
|
||||||
</arguments>
|
|
||||||
</listener>
|
|
||||||
</listeners>
|
|
||||||
|
|
||||||
<!-- Ignore vendor tests in code coverage reports -->
|
<!-- Ignore vendor tests in code coverage reports -->
|
||||||
<filter>
|
<filter>
|
||||||
|
|
|
@ -164,7 +164,7 @@ class AuditLogsTable extends AppTable
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->user = ['id' => 0, /*'org_id' => 0, */'authkey_id' => 0, 'request_type' => self::REQUEST_TYPE_DEFAULT];
|
$this->user = ['id' => 0, /*'org_id' => 0, */'authkey_id' => 0, 'request_type' => self::REQUEST_TYPE_DEFAULT, 'name' => ''];
|
||||||
|
|
||||||
$isShell = (php_sapi_name() === 'cli');
|
$isShell = (php_sapi_name() === 'cli');
|
||||||
if ($isShell) {
|
if ($isShell) {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\Fixture;
|
||||||
|
|
||||||
|
use Cake\TestSuite\Fixture\TestFixture;
|
||||||
|
use Authentication\PasswordHasher\DefaultPasswordHasher;
|
||||||
|
|
||||||
|
class AuthKeysFixture extends TestFixture
|
||||||
|
{
|
||||||
|
public $connection = 'test';
|
||||||
|
|
||||||
|
public const ADMIN_API_KEY = '4cd687b314a3b9c4d83264e6195b9a3706ef4c2f';
|
||||||
|
|
||||||
|
public function init(): void
|
||||||
|
{
|
||||||
|
$hasher = new DefaultPasswordHasher();
|
||||||
|
|
||||||
|
$this->records = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'uuid' => '3ebfbe50-e7d2-406e-a092-f031e604b6e5',
|
||||||
|
'authkey' => $hasher->hash(self::ADMIN_API_KEY),
|
||||||
|
'authkey_start' => '4cd6',
|
||||||
|
'authkey_end' => '4c2f',
|
||||||
|
'expiration' => 0,
|
||||||
|
'user_id' => 1,
|
||||||
|
'comment' => '',
|
||||||
|
'created' => time(),
|
||||||
|
'modified' => time()
|
||||||
|
]
|
||||||
|
];
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\Fixture;
|
||||||
|
|
||||||
|
use Cake\TestSuite\Fixture\TestFixture;
|
||||||
|
|
||||||
|
class IndividualsFixture extends TestFixture
|
||||||
|
{
|
||||||
|
public $connection = 'test';
|
||||||
|
|
||||||
|
public $records = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'uuid' => '3ebfbe50-e7d2-406e-a092-f031e604b6e1',
|
||||||
|
'email' => 'admin@admin.test',
|
||||||
|
'first_name' => 'admin',
|
||||||
|
'last_name' => 'admin',
|
||||||
|
'position' => 'admin',
|
||||||
|
'created' => '2022-01-04 10:00:00',
|
||||||
|
'modified' => '2022-01-04 10:00:00'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\Fixture;
|
||||||
|
|
||||||
|
use Cake\TestSuite\Fixture\TestFixture;
|
||||||
|
|
||||||
|
class RolesFixture extends TestFixture
|
||||||
|
{
|
||||||
|
public $connection = 'test';
|
||||||
|
|
||||||
|
public $records = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'uuid' => '3ebfbe50-e7d2-406e-a092-f031e604b6e4',
|
||||||
|
'name' => 'admin',
|
||||||
|
'is_default' => true,
|
||||||
|
'perm_admin' => true,
|
||||||
|
'perm_sync' => true,
|
||||||
|
'perm_org_admin' => true
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\Fixture;
|
||||||
|
|
||||||
|
use Cake\TestSuite\Fixture\TestFixture;
|
||||||
|
use Authentication\PasswordHasher\DefaultPasswordHasher;
|
||||||
|
|
||||||
|
class UsersFixture extends TestFixture
|
||||||
|
{
|
||||||
|
public $connection = 'test';
|
||||||
|
|
||||||
|
public const ADMIN_USER = 'admin';
|
||||||
|
public const ADMIN_PASSWORD = 'Password1234';
|
||||||
|
|
||||||
|
public function init(): void
|
||||||
|
{
|
||||||
|
$hasher = new DefaultPasswordHasher();
|
||||||
|
|
||||||
|
|
||||||
|
$this->records = [
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'uuid' => '3ebfbe50-e7d2-406e-a092-f031e604b6e5',
|
||||||
|
'username' => self::ADMIN_USER,
|
||||||
|
'password' => $hasher->hash(self::ADMIN_PASSWORD),
|
||||||
|
'role_id' => 1,
|
||||||
|
'individual_id' => 1,
|
||||||
|
'disabled' => 0,
|
||||||
|
'organisation_id' => 1,
|
||||||
|
'created' => '2022-01-04 10:00:00',
|
||||||
|
'modified' => '2022-01-04 10:00:00'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Testing
|
||||||
|
Add a test database to your `config/app_local.php` config file and set `debug` mode to `true`.
|
||||||
|
```php
|
||||||
|
'debug' => true,
|
||||||
|
'Datasources' => [
|
||||||
|
'default' => [
|
||||||
|
...
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
* The test connection is used during the test suite.
|
||||||
|
*/
|
||||||
|
'test' => [
|
||||||
|
'host' => 'localhost',
|
||||||
|
'username' => 'cerebrate',
|
||||||
|
'password' => 'cerebrate',
|
||||||
|
'database' => 'cerebrate_test',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Runing the tests
|
||||||
|
|
||||||
|
```
|
||||||
|
$ composer install
|
||||||
|
$ vendor/bin/phpunit
|
||||||
|
PHPUnit 8.5.22 by Sebastian Bergmann and contributors.
|
||||||
|
|
||||||
|
..... 5 / 5 (100%)
|
||||||
|
|
||||||
|
Time: 11.61 seconds, Memory: 26.00 MB
|
||||||
|
|
||||||
|
OK (5 tests, 15 assertions)
|
||||||
|
```
|
||||||
|
|
||||||
|
Running a specific suite:
|
||||||
|
```
|
||||||
|
$ vendor/bin/phpunit --testsuite=api
|
||||||
|
```
|
||||||
|
Available suites:
|
||||||
|
* `app`: runs all test suites
|
||||||
|
* `api`: runs only api tests
|
||||||
|
* `controller`: runs only controller tests
|
||||||
|
* _to be continued ..._
|
||||||
|
|
||||||
|
By default the database is re-generated before running the test suite, to skip this step and speed up the test run use the `-d skip-migrations` option:
|
||||||
|
```
|
||||||
|
$ vendor/bin/phpunit -d skip-migrations
|
||||||
|
```
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\TestCase\Api;
|
||||||
|
|
||||||
|
use Cake\TestSuite\IntegrationTestTrait;
|
||||||
|
use Cake\TestSuite\TestCase;
|
||||||
|
use App\Test\Fixture\AuthKeysFixture;
|
||||||
|
use App\Test\Fixture\UsersFixture;
|
||||||
|
|
||||||
|
class UsersApiTest extends TestCase
|
||||||
|
{
|
||||||
|
use IntegrationTestTrait;
|
||||||
|
|
||||||
|
protected $fixtures = [
|
||||||
|
'app.Individuals',
|
||||||
|
'app.Roles',
|
||||||
|
'app.Users',
|
||||||
|
'app.AuthKeys'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function testViewMe(): void
|
||||||
|
{
|
||||||
|
// ugly hack, $_SERVER['HTTP_AUTHORIZATION'] is not set automatically in test environment
|
||||||
|
$_SERVER['HTTP_AUTHORIZATION'] = AuthKeysFixture::ADMIN_API_KEY;
|
||||||
|
$this->configRequest([
|
||||||
|
'headers' => [
|
||||||
|
// this does not work: https://book.cakephp.org/4/en/development/testing.html#testing-stateless-authentication-and-apis
|
||||||
|
// 'Authorization' => AuthKeysFixture::ADMIN_API_KEY,
|
||||||
|
'Accept' => 'application/json'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->get('/users/view');
|
||||||
|
|
||||||
|
$this->assertResponseOk();
|
||||||
|
$this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::ADMIN_USER));
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,10 +40,14 @@ class ApplicationTest extends IntegrationTestCase
|
||||||
$app->bootstrap();
|
$app->bootstrap();
|
||||||
$plugins = $app->getPlugins();
|
$plugins = $app->getPlugins();
|
||||||
|
|
||||||
$this->assertCount(3, $plugins);
|
$this->assertCount(7, $plugins);
|
||||||
$this->assertSame('Bake', $plugins->get('Bake')->getName());
|
$this->assertSame('Bake', $plugins->get('Bake')->getName());
|
||||||
$this->assertSame('DebugKit', $plugins->get('DebugKit')->getName());
|
$this->assertSame('DebugKit', $plugins->get('DebugKit')->getName());
|
||||||
$this->assertSame('Migrations', $plugins->get('Migrations')->getName());
|
$this->assertSame('Migrations', $plugins->get('Migrations')->getName());
|
||||||
|
$this->assertSame('Authentication', $plugins->get('Authentication')->getName());
|
||||||
|
$this->assertSame('ADmad/SocialAuth', $plugins->get('ADmad/SocialAuth')->getName());
|
||||||
|
$this->assertSame('Tags', $plugins->get('Tags')->getName());
|
||||||
|
$this->assertSame('Cake/TwigView', $plugins->get('Cake/TwigView')->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
|
|
||||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
|
||||||
*
|
|
||||||
* Licensed under The MIT License
|
|
||||||
* For full copyright and license information, please see the LICENSE.txt
|
|
||||||
* Redistributions of files must retain the above copyright notice
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
|
|
||||||
* @link https://cakephp.org CakePHP(tm) Project
|
|
||||||
* @since 1.2.0
|
|
||||||
* @license https://opensource.org/licenses/mit-license.php MIT License
|
|
||||||
*/
|
|
||||||
namespace App\Test\TestCase\Controller;
|
|
||||||
|
|
||||||
use Cake\Core\Configure;
|
|
||||||
use Cake\TestSuite\IntegrationTestTrait;
|
|
||||||
use Cake\TestSuite\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PagesControllerTest class
|
|
||||||
*
|
|
||||||
* @uses \App\Controller\PagesController
|
|
||||||
*/
|
|
||||||
class PagesControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use IntegrationTestTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* testMultipleGet method
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testMultipleGet()
|
|
||||||
{
|
|
||||||
$this->get('/');
|
|
||||||
$this->assertResponseOk();
|
|
||||||
$this->get('/');
|
|
||||||
$this->assertResponseOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* testDisplay method
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testDisplay()
|
|
||||||
{
|
|
||||||
$this->get('/pages/home');
|
|
||||||
$this->assertResponseOk();
|
|
||||||
$this->assertResponseContains('CakePHP');
|
|
||||||
$this->assertResponseContains('<html>');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that missing template renders 404 page in production
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testMissingTemplate()
|
|
||||||
{
|
|
||||||
Configure::write('debug', false);
|
|
||||||
$this->get('/pages/not_existing');
|
|
||||||
|
|
||||||
$this->assertResponseError();
|
|
||||||
$this->assertResponseContains('Error');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that missing template in debug mode renders missing_template error page
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testMissingTemplateInDebug()
|
|
||||||
{
|
|
||||||
Configure::write('debug', true);
|
|
||||||
$this->get('/pages/not_existing');
|
|
||||||
|
|
||||||
$this->assertResponseFailure();
|
|
||||||
$this->assertResponseContains('Missing Template');
|
|
||||||
$this->assertResponseContains('Stacktrace');
|
|
||||||
$this->assertResponseContains('not_existing.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test directory traversal protection
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function testDirectoryTraversalProtection()
|
|
||||||
{
|
|
||||||
$this->get('/pages/../Layout/ajax');
|
|
||||||
$this->assertResponseCode(403);
|
|
||||||
$this->assertResponseContains('Forbidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that CSRF protection is applied to page rendering.
|
|
||||||
*
|
|
||||||
* @reutrn void
|
|
||||||
*/
|
|
||||||
public function testCsrfAppliedError()
|
|
||||||
{
|
|
||||||
$this->post('/pages/home', ['hello' => 'world']);
|
|
||||||
|
|
||||||
$this->assertResponseCode(403);
|
|
||||||
$this->assertResponseContains('CSRF');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that CSRF protection is applied to page rendering.
|
|
||||||
*
|
|
||||||
* @reutrn void
|
|
||||||
*/
|
|
||||||
public function testCsrfAppliedOk()
|
|
||||||
{
|
|
||||||
$this->enableCsrfToken();
|
|
||||||
$this->post('/pages/home', ['hello' => 'world']);
|
|
||||||
|
|
||||||
$this->assertResponseCode(200);
|
|
||||||
$this->assertResponseContains('CakePHP');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Test\TestCase\Controller;
|
||||||
|
|
||||||
|
use Cake\TestSuite\IntegrationTestTrait;
|
||||||
|
use Cake\TestSuite\TestCase;
|
||||||
|
use App\Test\Fixture\UsersFixture;
|
||||||
|
|
||||||
|
class UsersControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
use IntegrationTestTrait;
|
||||||
|
|
||||||
|
protected $fixtures = [
|
||||||
|
'app.Individuals',
|
||||||
|
'app.Roles',
|
||||||
|
'app.Users'
|
||||||
|
];
|
||||||
|
public function testLogin(): void
|
||||||
|
{
|
||||||
|
$this->enableCsrfToken();
|
||||||
|
$this->enableSecurityToken();
|
||||||
|
|
||||||
|
$this->post('/users/login', [
|
||||||
|
'username' => UsersFixture::ADMIN_USER,
|
||||||
|
'password' => UsersFixture::ADMIN_PASSWORD,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSessionHasKey('authUser.uuid');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +18,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
use Cake\Core\Configure;
|
use Cake\Core\Configure;
|
||||||
use Cake\Datasource\ConnectionManager;
|
use Cake\Datasource\ConnectionManager;
|
||||||
|
use Cake\TestSuite\Fixture\SchemaLoader;
|
||||||
|
use Migrations\TestSuite\Migrator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test runner bootstrap.
|
* Test runner bootstrap.
|
||||||
|
@ -50,3 +53,17 @@ ConnectionManager::alias('test_debug_kit', 'debug_kit');
|
||||||
// does not allow the sessionid to be set after stdout
|
// does not allow the sessionid to be set after stdout
|
||||||
// has been written to.
|
// has been written to.
|
||||||
session_id('cli');
|
session_id('cli');
|
||||||
|
|
||||||
|
// Load db schema from mysql.sql and run migrations
|
||||||
|
// super hacky way to skip migrations
|
||||||
|
if (!in_array('skip-migrations', $_SERVER['argv'])) {
|
||||||
|
// TODO: Removing mysql.sql and relying only in migrations would be ideal
|
||||||
|
// in the meantime, `'skip' => ['*']`, prevents migrations from droping already created tables
|
||||||
|
(new SchemaLoader())->loadSqlFiles('./INSTALL/mysql.sql', 'test');
|
||||||
|
$migrator = new Migrator();
|
||||||
|
$migrator->runMany([
|
||||||
|
['connection' => 'test', 'skip' => ['*']],
|
||||||
|
['plugin' => 'Tags', 'connection' => 'test', 'skip' => ['*']],
|
||||||
|
['plugin' => 'ADmad/SocialAuth', 'connection' => 'test', 'skip' => ['*']]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue