Merge pull request #80 from righel/add-integration-tests

Add integration tests
pull/85/head
Andras Iklody 2022-01-19 16:25:19 +01:00 committed by GitHub
commit 80cd93da40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 7110 additions and 586 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ vendor
webroot/theme/node_modules
.vscode
docker/run/
.phpunit.result.cache
config.json
phpunit.xml

View File

@ -74,12 +74,6 @@ sudo mysql -e "GRANT ALL PRIVILEGES ON cerebrate.* to cerebrate@localhost;"
sudo mysql -e "FLUSH PRIVILEGES;"
```
Load the default table structure into the database
```bash
sudo mysql -u cerebrate -p cerebrate < /var/www/cerebrate/INSTALL/mysql.sql
```
create your local configuration and set the db credentials
```bash

View File

@ -1,408 +0,0 @@
-- MySQL dump 10.16 Distrib 10.1.44-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: cerebrate
-- ------------------------------------------------------
-- Server version 10.1.44-MariaDB-0ubuntu0.18.04.1
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `alignment_tags`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `alignment_tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`alignment_id` int(10) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `alignment_id` (`alignment_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `alignment_tags_ibfk_1` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`),
CONSTRAINT `alignment_tags_ibfk_10` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_11` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`),
CONSTRAINT `alignment_tags_ibfk_12` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_3` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`),
CONSTRAINT `alignment_tags_ibfk_4` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_5` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`),
CONSTRAINT `alignment_tags_ibfk_6` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_7` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`),
CONSTRAINT `alignment_tags_ibfk_8` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
CONSTRAINT `alignment_tags_ibfk_9` FOREIGN KEY (`alignment_id`) REFERENCES `alignments` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `alignments`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `alignments` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`individual_id` int(10) unsigned NOT NULL,
`organisation_id` int(10) unsigned NOT NULL,
`type` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT 'member',
PRIMARY KEY (`id`),
KEY `individual_id` (`individual_id`),
KEY `organisation_id` (`organisation_id`),
CONSTRAINT `alignments_ibfk_1` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`),
CONSTRAINT `alignments_ibfk_2` FOREIGN KEY (`organisation_id`) REFERENCES `organisations` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `auth_keys`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `auth_keys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
`authkey` varchar(72) CHARACTER SET ascii DEFAULT NULL,
`authkey_start` varchar(4) CHARACTER SET ascii DEFAULT NULL,
`authkey_end` varchar(4) CHARACTER SET ascii DEFAULT NULL,
`created` int(10) unsigned NOT NULL,
`expiration` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`comment` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`id`),
KEY `authkey_start` (`authkey_start`),
KEY `authkey_end` (`authkey_end`),
KEY `created` (`created`),
KEY `expiration` (`expiration`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `broods`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `broods` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`url` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`description` text COLLATE utf8mb4_unicode_ci,
`organisation_id` int(10) unsigned NOT NULL,
`trusted` tinyint(1) DEFAULT NULL,
`pull` tinyint(1) DEFAULT NULL,
`skip_proxy` tinyint(1) DEFAULT NULL,
`authkey` varchar(40) CHARACTER SET ascii DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `name` (`name`),
KEY `url` (`url`),
KEY `authkey` (`authkey`),
KEY `organisation_id` (`organisation_id`),
FOREIGN KEY (`organisation_id`) REFERENCES `organisations` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `encryption_keys`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `encryption_keys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`type` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`encryption_key` text COLLATE utf8mb4_unicode_ci,
`revoked` tinyint(1) DEFAULT NULL,
`expires` int(10) unsigned DEFAULT NULL,
`owner_id` int(10) unsigned DEFAULT NULL,
`owner_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `type` (`type`),
KEY `expires` (`expires`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `individual_encryption_keys`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `individual_encryption_keys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`individual_id` int(10) unsigned NOT NULL,
`encryption_key_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `individual_id` (`individual_id`),
KEY `encryption_key_id` (`encryption_key_id`),
CONSTRAINT `individual_encryption_keys_ibfk_1` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`),
CONSTRAINT `individual_encryption_keys_ibfk_2` FOREIGN KEY (`encryption_key_id`) REFERENCES `encryption_keys` (`id`),
CONSTRAINT `individual_encryption_keys_ibfk_3` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`),
CONSTRAINT `individual_encryption_keys_ibfk_4` FOREIGN KEY (`encryption_key_id`) REFERENCES `encryption_keys` (`id`),
CONSTRAINT `individual_encryption_keys_ibfk_5` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`),
CONSTRAINT `individual_encryption_keys_ibfk_6` FOREIGN KEY (`encryption_key_id`) REFERENCES `encryption_keys` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `individuals`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `individuals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`email` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`first_name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`last_name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`position` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `email` (`email`),
KEY `first_name` (`first_name`),
KEY `last_name` (`last_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `local_tools`
--
CREATE TABLE IF NOT EXISTS `local_tools` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`connector` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`settings` text COLLATE utf8mb4_unicode_ci,
`exposed` tinyint(1) NOT NULL,
`description` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `connector` (`connector`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `organisation_encryption_keys`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `organisation_encryption_keys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`organisation_id` int(10) unsigned NOT NULL,
`encryption_key_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `organisation_id` (`organisation_id`),
KEY `encryption_key_id` (`encryption_key_id`),
CONSTRAINT `organisation_encryption_keys_ibfk_1` FOREIGN KEY (`organisation_id`) REFERENCES `organisations` (`id`),
CONSTRAINT `organisation_encryption_keys_ibfk_2` FOREIGN KEY (`encryption_key_id`) REFERENCES `encryption_keys` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `organisations`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `organisations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`url` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`nationality` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`sector` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`type` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`contacts` text COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `name` (`name`),
KEY `url` (`url`),
KEY `nationality` (`nationality`),
KEY `sector` (`sector`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `roles`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`is_default` tinyint(1) DEFAULT NULL,
`perm_admin` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `tags`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE IF NOT EXISTS `tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`description` text COLLATE utf8mb4_unicode_ci,
`colour` varchar(6) CHARACTER SET ascii NOT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`username` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`role_id` int(11) unsigned NOT NULL,
`individual_id` int(11) unsigned NOT NULL,
`disabled` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `role_id` (`role_id`),
KEY `individual_id` (`individual_id`),
CONSTRAINT `users_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`),
CONSTRAINT `users_ibfk_2` FOREIGN KEY (`individual_id`) REFERENCES `individuals` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
CREATE TABLE IF NOT EXISTS `sharing_groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`releasability` text DEFAULT NULL,
`description` text DEFAULT NULL,
`organisation_id` int(10) unsigned NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`active` tinyint(1) DEFAULT '1',
`local` tinyint(1) DEFAULT '1',
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `user_id` (`user_id`),
KEY `organisation_id` (`organisation_id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `sgo` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sharing_group_id` int(10) unsigned NOT NULL,
`organisation_id` int(10) unsigned NOT NULL,
`deleted` tinyint(1) DEFAULT 0,
PRIMARY KEY (`id`),
KEY `sharing_group_id` (`sharing_group_id`),
KEY `organisation_id` (`organisation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `meta_fields` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`scope` varchar(191) NOT NULL,
`parent_id` int(10) unsigned NOT NULL,
`field` varchar(191) NOT NULL,
`value` varchar(191) NOT NULL,
`uuid` varchar(40) CHARACTER SET ascii DEFAULT NULL,
`meta_template_id` int(10) unsigned NOT NULL,
`meta_template_field_id` int(10) unsigned NOT NULL,
`is_default` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `scope` (`scope`),
KEY `uuid` (`uuid`),
KEY `parent_id` (`parent_id`),
KEY `field` (`field`),
KEY `value` (`value`),
KEY `meta_template_id` (`meta_template_id`),
KEY `meta_template_field_id` (`meta_template_field_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `meta_templates` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`scope` varchar(191) NOT NULL,
`name` varchar(191) NOT NULL,
`namespace` varchar(191) NOT NULL,
`description` text,
`version` varchar(191) NOT NULL,
`uuid` varchar(40) CHARACTER SET ascii,
`source` varchar(191),
`enabled` tinyint(1) DEFAULT 0,
`is_default` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `scope` (`scope`),
KEY `source` (`source`),
KEY `name` (`name`),
KEY `namespace` (`namespace`),
KEY `version` (`version`),
KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `meta_template_fields` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`field` varchar(191) NOT NULL,
`type` varchar(191) NOT NULL,
`meta_template_id` int(10) unsigned NOT NULL,
`regex` text,
`multiple` tinyint(1) DEFAULT 0,
`enabled` tinyint(1) DEFAULT 0,
PRIMARY KEY (`id`),
CONSTRAINT `meta_template_id` FOREIGN KEY (`meta_template_id`) REFERENCES `meta_templates` (`id`),
KEY `field` (`field`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `audit_logs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created` datetime NOT NULL,
`user_id` int(10) unsigned DEFAULT NULL,
`authkey_id` int(10) unsigned DEFAULT NULL,
`request_ip` varbinary(16) DEFAULT NULL,
`request_type` tinyint NOT NULL,
`request_id` varchar(191) DEFAULT NULL,
`request_action` varchar(20) NOT NULL,
`model` varchar(80) NOT NULL,
`model_id` int(10) unsigned DEFAULT NULL,
`model_title` text DEFAULT NULL,
`change` blob,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `request_ip` (`request_ip`),
KEY `model` (`model`),
KEY `request_action` (`request_action`),
KEY `model_id` (`model_id`),
KEY `created` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-06-22 14:30:02

View File

@ -19,9 +19,12 @@
"cakephp/bake": "^2.0.3",
"cakephp/cakephp-codesniffer": "~4.0.0",
"cakephp/debug_kit": "^4.0",
"fzaninotto/faker": "^1.9",
"josegonzalez/dotenv": "^3.2",
"league/openapi-psr7-validator": "^0.16.4",
"phpunit/phpunit": "^8.5",
"psy/psysh": "@stable"
"psy/psysh": "@stable",
"wiremock-php/wiremock-php": "^2.32"
},
"suggest": {
"markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.",
@ -44,7 +47,6 @@
"scripts": {
"post-install-cmd": "App\\Console\\Installer::postInstall",
"post-create-project-cmd": "App\\Console\\Installer::postInstall",
"post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump",
"check": [
"@test",
"@cs-check"
@ -52,11 +54,15 @@
"cs-check": "phpcs --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
"cs-fix": "phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
"stan": "phpstan analyse src/",
"test": "phpunit --colors=always"
"test": [
"sh ./tests/Helper/wiremock/start.sh",
"phpunit",
"sh ./tests/Helper/wiremock/stop.sh"
]
},
"prefer-stable": true,
"config": {
"sort-packages": true
},
"minimum-stability": "dev"
}
}

File diff suppressed because it is too large Load Diff

1
debian/install vendored
View File

@ -7,4 +7,3 @@ webroot /usr/share/php-cerebrate
config /usr/share/php-cerebrate
debian/cerebrate.local.conf /etc/apache2/sites-available/
debian/config.php /etc/cerebrate/
INSTALL/mysql.sql => /usr/share/dbconfig-common/data/php-cerebrate/install/mysql

View File

@ -1,20 +1,3 @@
# Database init
For the `docker-compose` setup to work you must initialize database with
what is in `../INSTALL/mysql.sql`
```
mkdir -p run/dbinit/
cp ../INSTALL/mysql.sql run/dbinit/
```
The MariaDB container has a volume mounted as follow
`- ./run/dbinit:/docker-entrypoint-initdb.d/:ro`
So that on startup the container will source files in this directory to seed
the database. Once it's done the container will run normally and Cerebrate will
be able to roll its database migration scripts
# Actual data and volumes
The actual database will be located in `./run/database` exposed with the

View File

@ -5,7 +5,6 @@ services:
restart: always
volumes:
- ./run/database:/var/lib/mysql
- ./run/dbinit:/docker-entrypoint-initdb.d/:ro
environment:
MARIADB_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: "cerebrate"

View File

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="tests/bootstrap.php"
>
<phpunit colors="true" processIsolation="false" stopOnFailure="false" bootstrap="tests/bootstrap.php">
<php>
<ini name="memory_limit" value="-1"/>
<ini name="apc.enable_cli" value="1"/>
<ini name="memory_limit" value="-1" />
<ini name="apc.enable_cli" value="1" />
<env name="WIREMOCK_HOST" value="localhost" />
<env name="WIREMOCK_PORT" value="8080" />
<env name="OPENAPI_SPEC" value="webroot/docs/openapi.yaml" />
<env name="SKIP_DB_MIGRATIONS" value="0" />
</php>
<!-- Add any additional test suites you want to run here -->
@ -15,17 +14,17 @@
<testsuite name="app">
<directory>tests/TestCase/</directory>
</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>
<!-- Setup a listener for fixtures -->
<listeners>
<listener class="Cake\TestSuite\Fixture\FixtureInjector">
<arguments>
<object class="Cake\TestSuite\Fixture\FixtureManager"/>
</arguments>
</listener>
</listeners>
<extensions>
<extension class="\Cake\TestSuite\Fixture\PHPUnitExtension" />
</extensions>
<!-- Ignore vendor tests in code coverage reports -->
<filter>
@ -37,4 +36,4 @@
</exclude>
</whitelist>
</filter>
</phpunit>
</phpunit>

View File

@ -0,0 +1,19 @@
<?php
namespace App\Controller;
use App\Controller\AppController;
class ApiController extends AppController
{
/**
* Controller action for displaying built-in Redoc UI
*
* @return \Cake\Http\Response|null|void Renders view
*/
public function index()
{
$url = '/docs/openapi.yaml';
$this->set('url', $url);
}
}

View File

@ -194,6 +194,9 @@ class ACLComponent extends Component
'getBookmarks' => ['*'],
'saveBookmark' => ['*'],
'deleteBookmark' => ['*']
],
'Api' => [
'index' => ['*']
]
);

View File

@ -45,7 +45,12 @@ class Sidemenu {
'label' => __('Broods'),
'icon' => $this->iconTable['Broods'],
'url' => '/broods/index',
]
],
'API' => [
'label' => __('API'),
'icon' => $this->iconTable['API'],
'url' => '/api/index',
],
],
__('Administration') => [
'Roles' => [

View File

@ -34,6 +34,7 @@ class NavigationComponent extends Component
'LocalTools' => 'tools',
'Instance' => 'server',
'Tags' => 'tags',
'API' => 'code',
];
public function initialize(array $config): void

View File

@ -4,6 +4,7 @@ namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Core\Configure;
use Cake\Http\Exception\MethodNotAllowedException;
class ParamHandlerComponent extends Component
{
@ -47,7 +48,7 @@ class ParamHandlerComponent extends Component
return $this->isRest;
}
if ($this->request->is('json')) {
if (!empty($this->request->input()) && empty($this->request->input('json_decode'))) {
if (!empty((string)$this->request->getBody()) && empty($this->request->getParsedBody())) {
throw new MethodNotAllowedException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.');
}
$this->isRest = true;

View File

@ -163,8 +163,8 @@ class AuditLogsTable extends AppTable
if ($this->user !== null) {
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');
if ($isShell) {

2
templates/Api/index.php Normal file
View File

@ -0,0 +1,2 @@
<redoc spec-url='<?php echo $url ?>'></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>

View File

@ -0,0 +1,85 @@
<?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_ID = 1;
public const ADMIN_API_KEY = 'd033e22ae348aeb5660fc2140aec35850c4da997';
public const SYNC_API_ID = 2;
public const SYNC_API_KEY = '6b387ced110858dcbcda36edb044dc18f91a0894';
public const ORG_ADMIN_API_ID = 3;
public const ORG_ADMIN_API_KEY = '1c4685d281d478dbcebd494158024bc3539004d0';
public const REGULAR_USER_API_ID = 4;
public const REGULAR_USER_API_KEY = '12dea96fec20593566ab75692c9949596833adc9';
public function init(): void
{
$hasher = new DefaultPasswordHasher();
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::ADMIN_API_ID,
'uuid' => $faker->uuid(),
'authkey' => $hasher->hash(self::ADMIN_API_KEY),
'authkey_start' => substr(self::ADMIN_API_KEY, 0, 4),
'authkey_end' => substr(self::ADMIN_API_KEY, -4),
'expiration' => 0,
'user_id' => UsersFixture::USER_ADMIN_ID,
'comment' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::SYNC_API_ID,
'uuid' => $faker->uuid(),
'authkey' => $hasher->hash(self::SYNC_API_KEY),
'authkey_start' => substr(self::SYNC_API_KEY, 0, 4),
'authkey_end' => substr(self::SYNC_API_KEY, -4),
'expiration' => 0,
'user_id' => UsersFixture::USER_SYNC_ID,
'comment' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::ORG_ADMIN_API_ID,
'uuid' => $faker->uuid(),
'authkey' => $hasher->hash(self::ORG_ADMIN_API_KEY),
'authkey_start' => substr(self::ORG_ADMIN_API_KEY, 0, 4),
'authkey_end' => substr(self::ORG_ADMIN_API_KEY, -4),
'expiration' => 0,
'user_id' => UsersFixture::USER_ORG_ADMIN_ID,
'comment' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::REGULAR_USER_API_ID,
'uuid' => $faker->uuid(),
'authkey' => $hasher->hash(self::REGULAR_USER_API_KEY),
'authkey_start' => substr(self::REGULAR_USER_API_KEY, 0, 4),
'authkey_end' => substr(self::REGULAR_USER_API_KEY, -4),
'expiration' => 0,
'user_id' => UsersFixture::USER_REGULAR_USER_ID,
'comment' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class BroodsFixture extends TestFixture
{
public $connection = 'test';
public const BROOD_A_ID = 1;
public const BROOD_A_API_KEY = '6dcd4ce23d88e2ee9568ba546c007c63d9131c1b';
public const BROOD_B_ID = 2;
public const BROOD_B_API_KEY = 'ae4f281df5a5d0ff3cad6371f76d5c29b6d953ec';
public const BROOD_WIREMOCK_ID = 3;
public const BROOD_WIREMOCK_API_KEY = 'bfc63c07f74fa18b52d3cced97072cad00e51346';
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::BROOD_A_ID,
'uuid' => $faker->uuid(),
'name' => 'Brood A',
'url' => $faker->url,
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'trusted' => true,
'pull' => true,
'skip_proxy' => true,
'authkey' => self::BROOD_A_API_KEY,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::BROOD_B_ID,
'uuid' => $faker->uuid(),
'name' => 'Brood A',
'url' => $faker->url,
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_B_ID,
'trusted' => true,
'pull' => true,
'skip_proxy' => true,
'authkey' => self::BROOD_B_API_KEY,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::BROOD_WIREMOCK_ID,
'uuid' => $faker->uuid(),
'name' => 'wiremock',
'url' => 'http://localhost:8080',
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_B_ID,
'trusted' => true,
'pull' => true,
'skip_proxy' => true,
'authkey' => self::BROOD_WIREMOCK_API_KEY,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\Http\Exception\NotImplementedException;
use Cake\TestSuite\Fixture\TestFixture;
class EncryptionKeysFixture extends TestFixture
{
public $connection = 'test';
public const ENCRYPTION_KEY_ORG_A_ID = 1;
public const ENCRYPTION_KEY_ORG_B_ID = 2;
public const TYPE_PGP = 'pgp';
public const TYPE_SMIME = 'smime';
public const KEY_TYPE_EDCH = 'EDCH';
public const KEY_TYPE_RSA = 'RSA';
public const KEY_TYPE_SMIME = 'S/MIME';
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::ENCRYPTION_KEY_ORG_A_ID,
'uuid' => $faker->uuid(),
'type' => self::TYPE_PGP,
'encryption_key' => $this->getPublicKey(self::KEY_TYPE_EDCH),
'revoked' => false,
'expires' => null,
'owner_id' => OrganisationsFixture::ORGANISATION_A_ID,
'owner_model' => 'Organisation',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::ENCRYPTION_KEY_ORG_B_ID,
'uuid' => $faker->uuid(),
'type' => self::TYPE_PGP,
'encryption_key' => $this->getPublicKey(self::KEY_TYPE_EDCH),
'revoked' => false,
'expires' => null,
'owner_id' => OrganisationsFixture::ORGANISATION_B_ID,
'owner_model' => 'Organisation',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
];
parent::init();
}
public static function getPublicKey(string $type): string
{
switch ($type) {
case self::KEY_TYPE_EDCH:
return <<<EOD
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP v1.0.0
xm8EYeaEmhMFK4EEACIDAwTS1DNpEsyLo6ynsxJhe1J1k75OYGjkiYgj+4157e06
m8uNX9TRI3XKAKUs2ecG6Iv6beXpvLHcBu/GqwYnpLigpABkhLbUob5spIg+OqNA
l0U75pLyshmQ8DOWupjq2ZTNG2Zvb2JhciA8Zm9vYmFyQGV4YW1wbGUuY29tPsKP
BBMTCgAXBQJh5oSaAhsvAwsJBwMVCggCHgECF4AACgkQfYJ4NsWgZlqadgF6Apv0
S3JrJgmUejRVaMBoAlGlME6OibfAo/faYyOhO/tb0Kw8MYfrF27D+N3/TR8BAX0e
KhJvhcoHZlcb6E+xUvAT9zYyCpX6g1s2rU9qeLJEbWeEiz7/e1diYgQ2TuuJTr/O
UgRh5oSaEwgqhkjOPQMBBwIDBHTGkUJ9McCAGMB9/jhzJJ9arYLIdMUwHbxf68K3
yQaiQf2F0BUciz37I2pFPBV17CJzsHdoIG4rhrU4PI+srzvCwCcEGBMKAA8FAmHm
hJoFCQ8JnAACGy4AagkQfYJ4NsWgZlpfIAQZEwoABgUCYeaEmgAKCRC+TAWGbVzh
xvHIAP9C6iogC55FEE8XuQ2g6dPyIyou940sLQIYKdFpG2CTnwEAvosKiPEC+bwC
b75QibMSCGlYPOIO5WW9OqJyT4I59bwH4QF+KRv6b3wOoFz8/ptDyIbFpNSoBrDT
9D35Gk9oVSZg9FDeQunGRt2qkvfDxBMecPWXAYDlNTFtdBUWeXeMLJlEr5YyC3SA
RIbej4EnbpXmhdODjKLv1p5tAOw/lgEfQKzBEwbOUgRh5oSaEwgqhkjOPQMBBwID
BO9vsx/0+act9x1hNk0LHxE/PELjL2Abn/JBjAIvGgTmiZc5Vkb2XrUYAoOhKI4G
ab9UTnlGznER74SWWLELUt7CwCcEGBMKAA8FAmHmhJoFCQ8JnAACGy4AagkQfYJ4
NsWgZlpfIAQZEwoABgUCYeaEmgAKCRC5+NJ8Prn4UPSRAQCH7Ek29Z9ivuvIaj6n
2AYdgHZHBEYAg5uwSBchPRXBHwD/QxRRAyKnwdmTLJzaB7M82bHLRU5WXbEgqucv
9HuQpkiv6wGA2NVSulEz7VxxKIcaU8xQRrStIBXqMvNo/13kdlq2YWQ6EZnG7EU7
ExIU8Y2OkuFWAX9gLoJCjxfMuH5u27nNkztxL4SgORfCxWRg6VaVAFXX21dlQwIf
XUzE5dzw+nOspVE=
=WnCK
-----END PGP PUBLIC KEY BLOCK-----
EOD;
default:
throw new NotImplementedException('Unknown key type');
}
}
private static function getPrivateKey(string $type): string
{
switch ($type) {
case self::KEY_TYPE_EDCH:
return <<<EOD
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP v1.0.0
xcASBGHmhJoTBSuBBAAiAwME0tQzaRLMi6Osp7MSYXtSdZO+TmBo5ImII/uNee3t
OpvLjV/U0SN1ygClLNnnBuiL+m3l6byx3AbvxqsGJ6S4oKQAZIS21KG+bKSIPjqj
QJdFO+aS8rIZkPAzlrqY6tmU/gkDCCcuNcl1iEuoYIjwDlg5yqzxdXu9Q7V+WvBf
OflkWwIGYLjrqcDWNZqz9v4alO8/uKPZoRyYmQx3yBxjgrNs4bjibFxc43oTlHtD
JA7m+Ba4cWyMVFJ96TPXAvI5fAJszRtmb29iYXIgPGZvb2JhckBleGFtcGxlLmNv
bT7CjwQTEwoAFwUCYeaEmgIbLwMLCQcDFQoIAh4BAheAAAoJEH2CeDbFoGZamnYB
egKb9EtyayYJlHo0VWjAaAJRpTBOjom3wKP32mMjoTv7W9CsPDGH6xduw/jd/00f
AQF9HioSb4XKB2ZXG+hPsVLwE/c2MgqV+oNbNq1PaniyRG1nhIs+/3tXYmIENk7r
iU6/x6UEYeaEmhMIKoZIzj0DAQcCAwR0xpFCfTHAgBjAff44cySfWq2CyHTFMB28
X+vCt8kGokH9hdAVHIs9+yNqRTwVdewic7B3aCBuK4a1ODyPrK87/gkDCCiGr5A8
Yq+pYCpNvctmdVC3wwN+LNpiXHtkYWD37TdpwrdR0h8H/PSZFdHgkyK3tqmxPApC
S3+s+cBzza5mTPqaq/7Cc6ck40juXNBIC8rCwCcEGBMKAA8FAmHmhJoFCQ8JnAAC
Gy4AagkQfYJ4NsWgZlpfIAQZEwoABgUCYeaEmgAKCRC+TAWGbVzhxvHIAP9C6iog
C55FEE8XuQ2g6dPyIyou940sLQIYKdFpG2CTnwEAvosKiPEC+bwCb75QibMSCGlY
POIO5WW9OqJyT4I59bwH4QF+KRv6b3wOoFz8/ptDyIbFpNSoBrDT9D35Gk9oVSZg
9FDeQunGRt2qkvfDxBMecPWXAYDlNTFtdBUWeXeMLJlEr5YyC3SARIbej4EnbpXm
hdODjKLv1p5tAOw/lgEfQKzBEwbHpQRh5oSaEwgqhkjOPQMBBwIDBO9vsx/0+act
9x1hNk0LHxE/PELjL2Abn/JBjAIvGgTmiZc5Vkb2XrUYAoOhKI4Gab9UTnlGznER
74SWWLELUt7+CQMI0o+tsXn5S31gHyPTI5yRG0I7dZg4OrU+tCu11AYzC4y3aO0M
E2tixY7BDHIgtiWkeDWo8j4f8zYhBL9x/M3mpinZ6vQEhOdED+8shBmPNMLAJwQY
EwoADwUCYeaEmgUJDwmcAAIbLgBqCRB9gng2xaBmWl8gBBkTCgAGBQJh5oSaAAoJ
ELn40nw+ufhQ9JEBAIfsSTb1n2K+68hqPqfYBh2AdkcERgCDm7BIFyE9FcEfAP9D
FFEDIqfB2ZMsnNoHszzZsctFTlZdsSCq5y/0e5CmSK/rAYDY1VK6UTPtXHEohxpT
zFBGtK0gFeoy82j/XeR2WrZhZDoRmcbsRTsTEhTxjY6S4VYBf2AugkKPF8y4fm7b
uc2TO3EvhKA5F8LFZGDpVpUAVdfbV2VDAh9dTMTl3PD6c6ylUQ==
=96JC
-----END PGP PRIVATE KEY BLOCK-----
EOD;
default:
throw new NotImplementedException('Unknown key type');
}
}
}

View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class InboxFixture extends TestFixture
{
public $connection = 'test';
public $table = 'inbox';
public const INBOX_USER_REGISTRATION_ID = 1;
public const INBOX_INCOMING_CONNECTION_REQUEST_ID = 2;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::INBOX_USER_REGISTRATION_ID,
'uuid' => $faker->uuid(),
'scope' => 'User',
'action' => 'Registration',
'title' => 'User account creation requested for foo@bar.com',
'origin' => '::1',
'comment' => null,
'description' => 'Handle user account for this cerebrate instance',
'user_id' => UsersFixture::USER_ADMIN_ID,
'data' => [
'email' => 'foo@bar.com',
'password' => '$2y$10$dr5C0MWgBx1723yyws0HPudTqHz4k8wJ1PQ1ApVkNuH64LuZAr\/ve',
],
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INBOX_INCOMING_CONNECTION_REQUEST_ID,
'uuid' => $faker->uuid(),
'scope' => 'LocalTool',
'action' => 'IncomingConnectionRequest',
'title' => 'Request for MISP Inter-connection',
'origin' => 'http://127.0.0.1',
'comment' => null,
'description' => 'Handle Phase I of inter-connection when another cerebrate instance performs the request.',
'user_id' => UsersFixture::USER_ORG_ADMIN_ID,
'data' => [
'connectorName' => 'MispConnector',
'cerebrateURL' => 'http://127.0.0.1',
'local_tool_id' => 1,
'remote_tool_id' => 1,
],
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
];
parent::init();
}
}

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class IndividualsFixture extends TestFixture
{
public $connection = 'test';
public const INDIVIDUAL_ADMIN_ID = 1;
public const INDIVIDUAL_SYNC_ID = 2;
public const INDIVIDUAL_ORG_ADMIN_ID = 3;
public const INDIVIDUAL_REGULAR_USER_ID = 4;
public const INDIVIDUAL_A_ID = 5;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::INDIVIDUAL_ADMIN_ID,
'uuid' => $faker->uuid(),
'email' => $faker->email(),
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'position' => 'admin',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INDIVIDUAL_SYNC_ID,
'uuid' => $faker->uuid(),
'email' => $faker->email(),
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'position' => 'sync',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INDIVIDUAL_ORG_ADMIN_ID,
'uuid' => $faker->uuid(),
'email' => $faker->email(),
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'position' => 'org_admin',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INDIVIDUAL_REGULAR_USER_ID,
'uuid' => $faker->uuid(),
'email' => $faker->email(),
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'position' => 'user',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INDIVIDUAL_A_ID,
'uuid' => $faker->uuid(),
'email' => $faker->email(),
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'position' => 'user',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class OrganisationsFixture extends TestFixture
{
public $connection = 'test';
public const ORGANISATION_A_ID = 1;
public const ORGANISATION_B_ID = 2;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::ORGANISATION_A_ID,
'uuid' => $faker->uuid(),
'name' => 'Organisation A',
'url' => $faker->url,
'nationality' => $faker->countryCode,
'sector' => 'IT',
'type' => '',
'contacts' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::ORGANISATION_B_ID,
'uuid' => $faker->uuid(),
'name' => 'Organisation B',
'url' => $faker->url,
'nationality' => $faker->countryCode,
'sector' => 'IT',
'type' => '',
'contacts' => '',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class RolesFixture extends TestFixture
{
public $connection = 'test';
public const ROLE_ADMIN_ID = 1;
public const ROLE_SYNC_ID = 2;
public const ROLE_ORG_ADMIN_ID = 3;
public const ROLE_REGULAR_USER_ID = 4;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::ROLE_ADMIN_ID,
'uuid' => $faker->uuid(),
'name' => 'admin',
'is_default' => false,
'perm_admin' => true,
'perm_sync' => false,
'perm_org_admin' => false
],
[
'id' => self::ROLE_SYNC_ID,
'uuid' => $faker->uuid(),
'name' => 'sync',
'is_default' => false,
'perm_admin' => false,
'perm_sync' => true,
'perm_org_admin' => false
],
[
'id' => self::ROLE_ORG_ADMIN_ID,
'uuid' => $faker->uuid(),
'name' => 'org_admin',
'is_default' => false,
'perm_admin' => false,
'perm_sync' => false,
'perm_org_admin' => true
],
[
'id' => self::ROLE_REGULAR_USER_ID,
'uuid' => $faker->uuid(),
'name' => 'user',
'is_default' => true,
'perm_admin' => false,
'perm_sync' => false,
'perm_org_admin' => false
]
];
parent::init();
}
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class SharingGroupsFixture extends TestFixture
{
public $connection = 'test';
public const SHARING_GROUP_A_ID = 1;
public const SHARING_GROUP_B_ID = 2;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::SHARING_GROUP_A_ID,
'uuid' => $faker->uuid(),
'name' => 'Sharing Group A',
'releasability' => 'Sharing Group A releasability',
'description' => 'Sharing Group A description',
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'user_id' => UsersFixture::USER_ADMIN_ID,
'active' => true,
'local' => true,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::SHARING_GROUP_B_ID,
'uuid' => $faker->uuid(),
'name' => 'Sharing Group B',
'releasability' => 'Sharing Group B releasability',
'description' => 'Sharing Group B description',
'organisation_id' => OrganisationsFixture::ORGANISATION_B_ID,
'user_id' => UsersFixture::USER_ADMIN_ID,
'active' => true,
'local' => true,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
];
parent::init();
}
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class TagsTaggedsFixture extends TestFixture
{
public $connection = 'test';
public $table = 'tags_tagged';
public const TAG_RED_ID = 1;
public const TAG_GREEN_ID = 2;
public const TAG_BLUE_ID = 3;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'tag_id' => TagsTagsFixture::TAG_ORG_A_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_A_ID,
'fk_model' => 'Organisations',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'tag_id' => TagsTagsFixture::TAG_ORG_B_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_B_ID,
'fk_model' => 'Organisations',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
];
parent::init();
}
}

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class TagsTagsFixture extends TestFixture
{
public $connection = 'test';
public const TAG_RED_ID = 1;
public const TAG_GREEN_ID = 2;
public const TAG_BLUE_ID = 3;
public const TAG_ORG_A_ID = 4;
public const TAG_ORG_B_ID = 5;
public function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::TAG_RED_ID,
'name' => 'red',
'namespace' => null,
'predicate' => null,
'value' => null,
'colour' => 'FF0000',
'counter' => 0,
'text_colour' => 'red',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::TAG_GREEN_ID,
'name' => 'green',
'namespace' => null,
'predicate' => null,
'value' => null,
'colour' => '00FF00',
'counter' => 0,
'text_colour' => 'green',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::TAG_BLUE_ID,
'name' => 'blue',
'namespace' => null,
'predicate' => null,
'value' => null,
'colour' => '0000FF',
'counter' => 0,
'text_colour' => 'blue',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::TAG_ORG_A_ID,
'name' => 'org-a',
'namespace' => null,
'predicate' => null,
'value' => null,
'colour' => '000000',
'counter' => 0,
'text_colour' => 'black',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::TAG_ORG_B_ID,
'name' => 'org-b',
'namespace' => null,
'predicate' => null,
'value' => null,
'colour' => '000000',
'counter' => 0,
'text_colour' => 'black',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,92 @@
<?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';
// Admin user
public const USER_ADMIN_ID = 1;
public const USER_ADMIN_USERNAME = 'admin';
public const USER_ADMIN_PASSWORD = 'AdminPassword';
// Sync user
public const USER_SYNC_ID = 2;
public const USER_SYNC_USERNAME = 'sync';
public const USER_SYNC_PASSWORD = 'SyncPassword';
// Org Admin user
public const USER_ORG_ADMIN_ID = 3;
public const USER_ORG_ADMIN_USERNAME = 'org_admin';
public const USER_ORG_ADMIN_PASSWORD = 'OrgAdminPassword';
// Regular User user
public const USER_REGULAR_USER_ID = 4;
public const USER_REGULAR_USER_USERNAME = 'user';
public const USER_REGULAR_USER_PASSWORD = 'UserPassword';
public function init(): void
{
$hasher = new DefaultPasswordHasher();
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::USER_ADMIN_ID,
'uuid' => $faker->uuid(),
'username' => self::USER_ADMIN_USERNAME,
'password' => $hasher->hash(self::USER_ADMIN_PASSWORD),
'role_id' => RolesFixture::ROLE_ADMIN_ID,
'individual_id' => IndividualsFixture::INDIVIDUAL_ADMIN_ID,
'disabled' => 0,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::USER_SYNC_ID,
'uuid' => $faker->uuid(),
'username' => self::USER_SYNC_USERNAME,
'password' => $hasher->hash(self::USER_SYNC_PASSWORD),
'role_id' => RolesFixture::ROLE_SYNC_ID,
'individual_id' => IndividualsFixture::INDIVIDUAL_SYNC_ID,
'disabled' => 0,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::USER_ORG_ADMIN_ID,
'uuid' => $faker->uuid(),
'username' => self::USER_ORG_ADMIN_USERNAME,
'password' => $hasher->hash(self::USER_ORG_ADMIN_PASSWORD),
'role_id' => RolesFixture::ROLE_ORG_ADMIN_ID,
'individual_id' => IndividualsFixture::INDIVIDUAL_ORG_ADMIN_ID,
'disabled' => 0,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::USER_REGULAR_USER_ID,
'uuid' => $faker->uuid(),
'username' => self::USER_REGULAR_USER_USERNAME,
'password' => $hasher->hash(self::USER_REGULAR_USER_PASSWORD),
'role_id' => RolesFixture::ROLE_REGULAR_USER_ID,
'individual_id' => IndividualsFixture::INDIVIDUAL_REGULAR_USER_ID,
'disabled' => 0,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
}
}

View File

@ -0,0 +1,294 @@
<?php
declare(strict_types=1);
namespace App\Test\Helper;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\Core\Configure;
use Cake\Http\ServerRequestFactory;
use Cake\Http\ServerRequest;
use Cake\Http\Exception\NotImplementedException;
use \League\OpenAPIValidation\PSR7\ValidatorBuilder;
use \League\OpenAPIValidation\PSR7\RequestValidator;
use \League\OpenAPIValidation\PSR7\ResponseValidator;
use \League\OpenAPIValidation\PSR7\OperationAddress;
/**
* Trait ApiTestTrait
*
* @package App\Test\TestCase\Helper
*/
trait ApiTestTrait
{
use IntegrationTestTrait {
IntegrationTestTrait::_buildRequest as _buildRequestOriginal;
IntegrationTestTrait::_sendRequest as _sendRequestOriginal;
}
/** @var string */
protected $_authToken = '';
/** @var ValidatorBuilder */
private $_validator;
/** @var RequestValidator */
private $_requestValidator;
/** @var ResponseValidator */
private $_responseValidator;
/** @var ServerRequest */
protected $_psrRequest;
/* @var boolean */
protected $_skipOpenApiValidations = false;
public function setUp(): void
{
parent::setUp();
$this->initializeOpenApiValidator();
}
public function setAuthToken(string $authToken): void
{
$this->_authToken = $authToken;
// somehow this is not set automatically in test environment
$_SERVER['HTTP_AUTHORIZATION'] = $authToken;
$this->configRequest([
'headers' => [
'Accept' => 'application/json',
'Authorization' => $this->_authToken,
'Content-Type' => 'application/json'
]
]);
}
/**
* Skip OpenAPI validations.
*
* @return void
*/
public function skipOpenApiValidations(): void
{
$this->_skipOpenApiValidations = true;
}
public function assertResponseContainsArray(array $expected): void
{
$responseArray = json_decode((string)$this->_response->getBody(), true);
throw new NotImplementedException('TODO: see codeception seeResponseContainsJson()');
}
/**
* Load OpenAPI specification validator
*
* @return void
*/
public function initializeOpenApiValidator(): void
{
if (!$this->_skipOpenApiValidations) {
$this->_validator = Configure::read('App.OpenAPIValidator');
if ($this->_validator === null) {
throw new \Exception('OpenAPI validator is not configured');
}
}
}
/**
* Validates the API request against the OpenAPI spec
*
* @return void
*/
public function assertRequestMatchesOpenApiSpec(): void
{
$this->_validator->getRequestValidator()->validate($this->_psrRequest);
}
/**
* Validates the API response against the OpenAPI spec
*
* @param string $path The path to the API endpoint
* @param string $method The HTTP method used to call the endpoint
* @return void
*/
public function assertResponseMatchesOpenApiSpec(string $endpoint, string $method = 'get'): void
{
$address = new OperationAddress($endpoint, $method);
$this->_validator->getResponseValidator()->validate($address, $this->_response);
}
/**
* Validates a record exists in the database
*
* @param string $table The table name
* @param array $conditions The conditions to check
* @return void
* @throws \Exception
* @throws \Cake\Datasource\Exception\RecordNotFoundException
*
* @see https://book.cakephp.org/4/en/orm-query-builder.html
*/
public function assertDbRecordExists(string $table, array $conditions): void
{
$record = $this->getTableLocator()->get($table)->find()->where($conditions)->first();
if (!$record) {
throw new \PHPUnit\Framework\AssertionFailedError("Record not found in table '$table' with conditions: " . json_encode($conditions));
}
$this->assertNotEmpty($record);
}
/**
* Validates a record do not exists in the database
*
* @param string $table The table name
* @param array $conditions The conditions to check
* @return void
* @throws \Exception
* @throws \Cake\Datasource\Exception\RecordNotFoundException
*
* @see https://book.cakephp.org/4/en/orm-query-builder.html
*/
public function assertDbRecordNotExists(string $table, array $conditions): void
{
$record = $this->getTableLocator()->get($table)->find()->where($conditions)->first();
if ($record) {
throw new \PHPUnit\Framework\AssertionFailedError("Record found in table '$table' with conditions: " . json_encode($conditions));
}
$this->assertEmpty($record);
}
/**
* Parses the response body and returns the decoded JSON
*
* @return array
* @throws \Exception
*/
public function getJsonResponseAsArray(): array
{
if ($this->_response->getHeaders()['Content-Type'][0] !== 'application/json') {
throw new \Exception('The response is not a JSON response');
}
return json_decode((string)$this->_response->getBody(), true);
}
/**
* Gets a database records as an array
*
* @param string $table The table name
* @param array $conditions The conditions to check
* @return array
* @throws \Cake\Datasource\Exception\RecordNotFoundException
*/
public function getRecordFromDb(string $table, array $conditions): array
{
return $this->getTableLocator()->get($table)->find()->where($conditions)->first()->toArray();
}
/**
* This method intercepts IntegrationTestTrait::_buildRequest()
* in the quest to get a PSR-7 request object and saves it for
* later inspection, also validates it against the OpenAPI spec.
* @see \Cake\TestSuite\IntegrationTestTrait::_buildRequest()
*
* @param string $url The URL
* @param string $method The HTTP method
* @param array|string $data The request data.
* @return array The request context
*/
protected function _buildRequest(string $url, $method, $data = []): array
{
$spec = $this->_buildRequestOriginal($url, $method, $data);
$this->_psrRequest = $this->_createPsr7RequestFromSpec($spec);
// Validate request against OpenAPI spec
if (!$this->_skipOpenApiValidations) {
try {
$this->assertRequestMatchesOpenApiSpec();
} catch (\Exception $exception) {
$this->fail($exception->getMessage());
}
} else {
$this->addWarning(
sprintf(
'OpenAPI spec validations skipped for request [%s]%s.',
$this->_psrRequest->getMethod(),
$this->_psrRequest->getPath()
)
);
}
return $spec;
}
/**
* This method intercepts IntegrationTestTrait::_buildRequest()
* and validates the response against the OpenAPI spec.
*
* @see \Cake\TestSuite\IntegrationTestTrait::_sendRequest()
*
* @param array|string $url The URL
* @param string $method The HTTP method
* @param array|string $data The request data.
* @return void
* @throws \PHPUnit\Exception|\Throwable
*/
protected function _sendRequest($url, $method, $data = []): void
{
// Adding Content-Type: application/json $this->configRequest() prevents this from happening somehow
if (in_array($method, ['POST', 'PATCH', 'PUT']) && $this->_request['headers']['Content-Type'] === 'application/json') {
$data = json_encode($data);
}
$this->_sendRequestOriginal($url, $method, $data);
// Validate response against OpenAPI spec
if (!$this->_skipOpenApiValidations) {
$this->assertResponseMatchesOpenApiSpec(
$this->_psrRequest->getPath(),
strtolower($this->_psrRequest->getMethod())
);
} else {
$this->addWarning(
sprintf(
'OpenAPI spec validations skipped for response of [%s]%s.',
$this->_psrRequest->getMethod(),
$this->_psrRequest->getPath()
)
);
}
}
/**
* Create a PSR-7 request from the request spec.
* @see \Cake\TestSuite\MiddlewareDispatcher::_createRequest()
*
* @param array<string, mixed> $spec The request spec.
* @return \Cake\Http\ServerRequest
*/
private function _createPsr7RequestFromSpec(array $spec): ServerRequest
{
if (isset($spec['input'])) {
$spec['post'] = [];
$spec['environment']['CAKEPHP_INPUT'] = $spec['input'];
}
$environment = array_merge(
array_merge($_SERVER, ['REQUEST_URI' => $spec['url']]),
$spec['environment']
);
if (strpos($environment['PHP_SELF'], 'phpunit') !== false) {
$environment['PHP_SELF'] = '/';
}
return ServerRequestFactory::fromGlobals(
$environment,
$spec['query'],
$spec['post'],
$spec['cookies'],
$spec['files']
);
}
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Test\Helper;
use \WireMock\Client\WireMock;
use Exception;
trait WireMockTestTrait
{
/** @var WireMock */
private $wiremock;
/** @var array<mixed> */
private $config = [
'hostname' => 'localhost',
'port' => 8080
];
public function initializeWireMock(): void
{
$this->wiremock = WireMock::create(
$_ENV['WIREMOCK_HOST'] ?? $this->config['hostname'],
$_ENV['WIREMOCK_PORT'] ?? $this->config['port']
);
if (!$this->wiremock->isAlive()) {
throw new Exception('Failed to connect to WireMock server.');
}
$this->clearWireMockStubs();
}
public function clearWireMockStubs(): void
{
$this->wiremock->resetToDefault();
}
public function getWireMock(): WireMock
{
return $this->wiremock;
}
public function getWireMockBaseUrl(): string
{
return sprintf('http://%s:%s', $this->config['hostname'], $this->config['port']);
}
}

View File

@ -0,0 +1,38 @@
#!/bin/bash
# Adapted from @rowanhill wiremock start.sh script
# https://github.com/rowanhill/wiremock-php/blob/master/wiremock/start.sh
cd ./tmp/
instance=1
port=8080
if [ $# -gt 0 ]; then
instance=$1
port=$2
fi
pidFile=wiremock.$instance.pid
logFile=wiremock.$instance.log
# Ensure WireMock isn't already running
if [ -e $pidFile ]; then
echo WireMock is already started: see process `cat $pidFile` 1>&2
exit 0
fi
# Download the wiremock jar if we need it
if ! [ -e wiremock-standalone.jar ]; then
echo WireMock standalone JAR missing. Downloading.
curl https://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-jre8-standalone/2.32.0/wiremock-jre8-standalone-2.32.0.jar -o wiremock-standalone.jar
status=$?
if [ ${status} -ne 0 ]; then
echo curl could not download WireMock JAR 1>&2
exit ${status}
fi
fi
# Start WireMock in standalone mode (in a background process) and save its output to a log
java -jar wiremock-standalone.jar --port $port --root-dir $instance --disable-banner &> $logFile 2>&1 &
pgrep -f wiremock-standalone.jar > $pidFile
echo WireMock $instance started on port $port

View File

@ -0,0 +1,23 @@
#!/bin/bash
# Adapted from @rowanhill wiremock stop.sh script
# https://github.com/rowanhill/wiremock-php/blob/master/wiremock/stop.sh
cd ./tmp/
instance=1
if [ $# -gt 0 ]; then
instance=$1
fi
pidFile=wiremock.$instance.pid
if [ -e $pidFile ]; then
kill -9 `cat $pidFile`
rm $pidFile
else
echo WireMock is not started 2>&1
exit 1
fi
echo WireMock $instance stopped

123
tests/README.md Normal file
View File

@ -0,0 +1,123 @@
# Testing
1. Add a `cerebrate_test` database to the database:
```mysql
CREATE DATABASE cerebrate_test;
GRANT ALL PRIVILEGES ON cerebrate_test.* to cerebrate@localhost;
FLUSH PRIVILEGES;
QUIT;
```
2. Add a the 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
$ composer test
> sh ./tests/Helper/wiremock/start.sh
WireMock 1 started on port 8080
> phpunit
[ * ] Running DB migrations, it may take some time ...
The WireMock server is started .....
port: 8080
enable-browser-proxying: false
disable-banner: true
no-request-journal: false
verbose: false
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 --testdox
```
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 set the following env variable in `phpunit.xml`:
```xml
<php>
...
<env name="SKIP_DB_MIGRATIONS" value="1" />
</php>
```
## Extras
### WireMock
Some integration tests perform calls to external APIs, we use WireMock to mock the response of these API calls.
To download and run WireMock run the following script in a separate terminal:
```
sh ./tests/Helper/wiremock/start.sh
```
You can also run WireMock with docker, check the official docs: http://wiremock.org/docs/docker/
> NOTE: When running the tests with `composer test` WireMock is automatically started and stoped after the tests finish.
The default `hostname` and `port` for WireMock are set in `phpunit.xml` as environment variables:
```xml
<php>
...
<env name="WIREMOCK_HOST" value="localhost" />
<env name="WIREMOCK_PORT" value="8080" />
</php>
```
### Coverage
HTML:
```
$ vendor/bin/phpunit --coverage-html tmp/coverage
```
XML:
```
$ vendor/bin/phpunit --verbose --coverage-clover=coverage.xml
```
### OpenAPI validation
API tests can assert the API response matches the OpenAPI specification, after the request add this line:
```php
$this->assertResponseMatchesOpenApiSpec(self::ENDPOINT);
```
The default OpenAPI spec path is set in `phpunit.xml` as a environment variablea:
```xml
<php>
...
<env name="OPENAPI_SPEC" value="webroot/docs/openapi.yaml" />
</php>
```
### Debugging tests
```
$ export XDEBUG_CONFIG="idekey=IDEKEY"
$ phpunit
```

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
class AddAuthKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/authKeys/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testAddAdminAuthKey(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'authkey' => $faker->sha1,
'expiration' => 0,
'user_id' => UsersFixture::USER_ADMIN_ID,
'comment' => $faker->text
]
);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"uuid": "%s"', $uuid));
$this->assertDbRecordExists('AuthKeys', ['uuid' => $uuid]);
}
public function testAddAdminAuthKeyNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'authkey' => $faker->sha1,
'expiration' => 0,
'user_id' => UsersFixture::USER_ADMIN_ID,
'comment' => $faker->text
]
);
$this->assertResponseCode(404);
$this->addWarning('Should return 405 Method Not Allowed instead of 404 Not Found');
$this->assertDbRecordNotExists('AuthKeys', ['uuid' => $uuid]);
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteAuthKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/authKeys/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
];
public function testDeleteAdminAuthKey(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, AuthKeysFixture::ADMIN_API_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('AuthKeys', ['id' => AuthKeysFixture::ADMIN_API_ID]);
}
public function testDeleteOrgAdminAuthKeyNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, AuthKeysFixture::ORG_ADMIN_API_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('AuthKeys', ['id' => AuthKeysFixture::ORG_ADMIN_API_ID]);
}
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class IndexAuthKeysApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/authKeys/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexAuthKeys(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', AuthKeysFixture::ADMIN_API_ID));
}
public function testIndexDoesNotShowAdminAuthKeysAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseNotContains(sprintf('"id": %d', AuthKeysFixture::REGULAR_USER_API_KEY));
}
}

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class AddBroodApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/broods/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testAddBrood(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'name' => 'Brood A',
'url' => $faker->url,
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'trusted' => true,
'pull' => true,
'skip_proxy' => true,
'authkey' => $faker->sha1,
]
);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"uuid": "%s"', $uuid));
$this->assertDbRecordExists('Broods', ['uuid' => $uuid]);
}
public function testAddBroodNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'name' => 'Brood A',
'url' => $faker->url,
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'trusted' => true,
'pull' => true,
'skip_proxy' => true,
'authkey' => $faker->sha1,
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Broods', ['uuid' => $uuid]);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\BroodsFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteBroodApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/broods/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testDeleteBrood(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_A_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('Broods', ['id' => BroodsFixture::BROOD_A_ID]);
}
public function testDeleteBroodNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_A_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('Broods', ['id' => BroodsFixture::BROOD_A_ID]);
}
}

View File

@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\BroodsFixture;
use App\Test\Helper\ApiTestTrait;
class EditBroodApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/broods/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testEditBrood(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_A_ID);
$this->put(
$url,
[
'name' => 'Test Brood 4321',
]
);
$this->assertResponseOk();
$this->assertDbRecordExists(
'Broods',
[
'id' => BroodsFixture::BROOD_A_ID,
'name' => 'Test Brood 4321',
]
);
}
public function testEditBroodNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_B_ID);
$this->put(
$url,
[
'name' => 'Test Brood 1234'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists(
'Broods',
[
'id' => BroodsFixture::BROOD_B_ID,
'name' => 'Test Brood 1234'
]
);
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\BroodsFixture;
use App\Test\Helper\ApiTestTrait;
class IndexBroodsApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testIndexBroods(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', BroodsFixture::BROOD_A_ID));
}
}

View File

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\BroodsFixture;
use App\Test\Helper\ApiTestTrait;
use App\Test\Helper\WireMockTestTrait;
use \WireMock\Client\WireMock;
class TestBroodConnectionApiTest extends TestCase
{
use ApiTestTrait;
use WireMockTestTrait;
protected const ENDPOINT = '/broods/testConnection';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testTestBroodConnection(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->initializeWireMock();
$this->mockCerebrateStatusResponse();
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_WIREMOCK_ID);
$this->get($url);
$this->getWireMock()->verify(
WireMock::getRequestedFor(WireMock::urlEqualTo('/instance/status.json'))
->withHeader('Content-Type', WireMock::equalTo('application/json'))
->withHeader('Authorization', WireMock::equalTo(BroodsFixture::BROOD_WIREMOCK_API_KEY))
);
$this->assertResponseOk();
$this->assertResponseContains('"user": "wiremock"');
}
private function mockCerebrateStatusResponse(): \WireMock\Stubbing\StubMapping
{
return $this->getWireMock()->stubFor(
WireMock::get(WireMock::urlEqualTo('/instance/status.json'))
->willReturn(WireMock::aResponse()
->withHeader('Content-Type', 'application/json')
->withBody((string)json_encode([
"version" => "0.1",
"application" => "Cerebrate",
"user" => [
"id" => 1,
"username" => "wiremock",
"role" => [
"id" => 1
]
]
])))
);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\BroodsFixture;
use App\Test\Helper\ApiTestTrait;
class ViewBroodApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/broods/view';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Broods'
];
public function testViewBroodGroupById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_A_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', BroodsFixture::BROOD_A_ID));
}
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\EncryptionKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
class AddEncryptionKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/encryptionKeys/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.EncryptionKeys'
];
public function testAddUserEncryptionKey(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'type' => EncryptionKeysFixture::TYPE_PGP,
'encryption_key' => EncryptionKeysFixture::getPublicKey(EncryptionKeysFixture::KEY_TYPE_EDCH),
'revoked' => false,
'expires' => null,
'owner_id' => UsersFixture::USER_ADMIN_ID,
'owner_model' => 'User'
]
);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"uuid": "%s"', $uuid));
$this->assertDbRecordExists('EncryptionKeys', ['uuid' => $uuid]);
}
public function testAddAdminUserEncryptionKeyNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'type' => EncryptionKeysFixture::TYPE_PGP,
'encryption_key' => EncryptionKeysFixture::getPublicKey(EncryptionKeysFixture::KEY_TYPE_EDCH),
'revoked' => false,
'expires' => null,
'owner_id' => UsersFixture::USER_ADMIN_ID,
'owner_model' => 'User'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('EncryptionKeys', ['uuid' => $uuid]);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\EncryptionKeysFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteEncryptionKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/encryptionKeys/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.EncryptionKeys'
];
public function testDeleteEncryptionKey(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('EncryptionKeys', ['id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID]);
}
public function testDeleteEncryptionKeyNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('EncryptionKeys', ['id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID]);
}
}

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\EncryptionKeysFixture;
use App\Test\Helper\ApiTestTrait;
class EditEncryptionKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/encryptionKeys/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.EncryptionKeys'
];
public function testRevokeEncryptionKey(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID);
$this->put(
$url,
[
'revoked' => true,
]
);
$this->assertResponseOk();
$this->assertDbRecordExists(
'EncryptionKeys',
[
'id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID,
'revoked' => true,
]
);
}
public function testRevokeAdminEncryptionKeyNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID);
$this->put(
$url,
[
'revoked' => true
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists(
'EncryptionKeys',
[
'id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID,
'revoked' => true
]
);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\EncryptionKeysFixture;
use App\Test\Helper\ApiTestTrait;
class IndexEncryptionKeysApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/encryptionKeys/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.EncryptionKeys'
];
public function testIndexEncryptionKeys(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID));
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\EncryptionKeysFixture;
use App\Test\Helper\ApiTestTrait;
class ViewEncryptionKeyApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/encryptionKeys/view';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.EncryptionKeys'
];
public function testViewEncryptionKeyById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID));
}
}

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class CreateInboxEntryApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/inbox/createEntry';
protected $fixtures = [
'app.Inbox',
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testAddUserRegistrationInbox(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
// to avoid $this->request->clientIp() to return null
$_SERVER['REMOTE_ADDR'] = '::1';
$url = sprintf("%s/%s/%s", self::ENDPOINT, 'User', 'Registration');
$this->post(
$url,
[
'email' => 'john@example.com',
'password' => 'Password12345!'
]
);
$this->assertResponseOk();
$this->assertResponseContains('"email": "john@example.com"');
$this->assertDbRecordExists(
'Inbox',
[
'id' => 3, // hacky, but `data` is json string cannot verify the value because of the hashed password
'scope' => 'User',
'action' => 'Registration',
]
);
}
public function testAddUserRegistrationInboxNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf("%s/%s/%s", self::ENDPOINT, 'User', 'Registration');
$this->post(
$url,
[
'email' => 'john@example.com',
'password' => 'Password12345!'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Inbox', ['id' => 3]);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\InboxFixture;
use App\Test\Helper\ApiTestTrait;
class IndexInboxApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/inbox/index';
protected $fixtures = [
'app.Inbox',
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexInbox(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', InboxFixture::INBOX_USER_REGISTRATION_ID));
$this->assertResponseContains(sprintf('"id": %d', InboxFixture::INBOX_INCOMING_CONNECTION_REQUEST_ID));
}
}

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class AddIndividualApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/individuals/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testAddIndividual(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->post(
self::ENDPOINT,
[
'email' => 'john@example.com',
'first_name' => 'John',
'last_name' => 'Doe',
'position' => 'Security Analyst'
]
);
$this->assertResponseOk();
$this->assertResponseContains('"email": "john@example.com"');
$this->assertDbRecordExists('Individuals', ['email' => 'john@example.com']);
}
// public function testAddUserNotAllowedAsRegularUser(): void
// {
// $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
// $this->post(
// self::ENDPOINT,
// [
// 'email' => 'john@example.com',
// 'first_name' => 'John',
// 'last_name' => 'Doe',
// 'position' => 'Security Analyst'
// ]
// );
// $this->assertResponseCode(405);
// $this->assertDbRecordNotExists('Individuals', ['email' => 'john@example.com']);
// }
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\IndividualsFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteIndividualApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/individuals/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testDeleteIndividual(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, IndividualsFixture::INDIVIDUAL_A_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('Individuals', ['id' => IndividualsFixture::INDIVIDUAL_A_ID]);
}
public function testDeleteIndividualNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, IndividualsFixture::INDIVIDUAL_ADMIN_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('Individuals', ['id' => IndividualsFixture::INDIVIDUAL_ADMIN_ID]);
}
}

View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\IndividualsFixture;
use App\Test\Helper\ApiTestTrait;
class EditIndividualApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/individuals/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testEditIndividualAsAdmin(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, IndividualsFixture::INDIVIDUAL_REGULAR_USER_ID);
$this->put(
$url,
[
'email' => 'foo@bar.com',
]
);
$this->assertResponseOk();
$this->assertDbRecordExists('Individuals', [
'id' => IndividualsFixture::INDIVIDUAL_REGULAR_USER_ID,
'email' => 'foo@bar.com'
]);
}
public function testEditAnyIndividualNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, IndividualsFixture::INDIVIDUAL_ADMIN_ID);
$this->put(
$url,
[
'email' => 'foo@bar.com',
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Individuals', [
'id' => IndividualsFixture::INDIVIDUAL_ADMIN_ID,
'email' => 'foo@bar.com'
]);
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\IndividualsFixture;
use App\Test\Helper\ApiTestTrait;
class IndexIndividualsApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/individuals/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexIndividuals(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', IndividualsFixture::INDIVIDUAL_ADMIN_ID));
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\IndividualsFixture;
use App\Test\Helper\ApiTestTrait;
class ViewIndividualApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/individuals/view';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testViewIndividualById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, IndividualsFixture::INDIVIDUAL_ADMIN_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', IndividualsFixture::INDIVIDUAL_ADMIN_ID));
}
}

View File

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class AddOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testAddOrganisation(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'name' => 'Test Organisation',
'description' => $faker->text,
'uuid' => $uuid,
'url' => 'http://example.com',
'nationality' => 'US',
'sector' => 'sector',
'type' => 'type',
]
);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"uuid": "%s"', $uuid));
$this->assertDbRecordExists('Organisations', ['uuid' => $uuid]);
}
public function testAddOrganisationNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'name' => 'Test Organisation',
'description' => $faker->text,
'uuid' => $uuid,
'url' => 'http://example.com',
'nationality' => 'US',
'sector' => 'sector',
'type' => 'type',
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Organisations', ['uuid' => $uuid]);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testDeleteOrganisation(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_B_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('Organisations', ['id' => OrganisationsFixture::ORGANISATION_B_ID]);
}
public function testDeleteOrganisationNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_B_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('Organisations', ['id' => OrganisationsFixture::ORGANISATION_B_ID]);
}
}

View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Helper\ApiTestTrait;
class EditOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testEditOrganisation(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->put(
$url,
[
'name' => 'Test Organisation 4321',
]
);
$this->assertResponseOk();
$this->assertDbRecordExists(
'Organisations',
[
'id' => OrganisationsFixture::ORGANISATION_A_ID,
'name' => 'Test Organisation 4321',
]
);
}
public function testEditOrganisationNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_B_ID);
$this->put(
$url,
[
'name' => 'Test Organisation 1234'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists(
'Organisations',
[
'id' => OrganisationsFixture::ORGANISATION_B_ID,
'name' => 'Test Organisation 1234'
]
);
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Helper\ApiTestTrait;
class IndexOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexOrganisations(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', OrganisationsFixture::ORGANISATION_A_ID));
$this->assertResponseContains(sprintf('"id": %d', OrganisationsFixture::ORGANISATION_B_ID));
}
}

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\TagsTagsFixture;
use App\Test\Helper\ApiTestTrait;
class TagOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/tag';
protected $fixtures = [
'app.TagsTags',
'app.Organisations',
'app.TagsTaggeds',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testTagOrganisation(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->post(
$url,
[
'tag_list' => "[\"red\"]"
]
);
$this->assertResponseOk();
$this->assertDbRecordExists(
'TagsTagged',
[
'tag_id' => TagsTagsFixture::TAG_RED_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_A_ID,
'fk_model' => 'Organisations'
]
);
}
public function testTagOrganisationNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->post(
$url,
[
'tag_list' => "[\"green\"]"
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists(
'TagsTagged',
[
'tag_id' => TagsTagsFixture::TAG_GREEN_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_A_ID,
'fk_model' => 'Organisations'
]
);
}
}

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\TagsTagsFixture;
use App\Test\Helper\ApiTestTrait;
class UntagOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/untag';
protected $fixtures = [
'app.TagsTags',
'app.Organisations',
'app.TagsTaggeds',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testUntagOrganisation(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->post(
$url,
[
'tag_list' => "[\"org-a\"]"
]
);
$this->assertResponseOk();
$this->assertDbRecordNotExists(
'TagsTagged',
[
'tag_id' => TagsTagsFixture::TAG_ORG_A_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_A_ID,
'fk_model' => 'Organisations'
]
);
}
public function testUntagOrganisationNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->post(
$url,
[
'tag_list' => "[\"org-a\"]"
]
);
$this->assertResponseCode(405);
$this->assertDbRecordExists(
'TagsTagged',
[
'tag_id' => TagsTagsFixture::TAG_ORG_A_ID,
'fk_id' => OrganisationsFixture::ORGANISATION_A_ID,
'fk_model' => 'Organisations'
]
);
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Helper\ApiTestTrait;
class ViewOrganisationApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/organisations/view';
protected $fixtures = [
'app.TagsTags',
'app.Organisations',
'app.TagsTaggeds',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testViewOrganisationById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, OrganisationsFixture::ORGANISATION_A_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains('"name": "Organisation A"');
}
}

View File

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class AddSharingGroupApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/sharingGroups/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.SharingGroups'
];
public function testAddSharingGroup(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'name' => 'Test Sharing Group',
'releasability' => 'Test Sharing Group releasability',
'description' => 'Test Sharing Group description',
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'user_id' => UsersFixture::USER_ADMIN_ID,
'active' => true,
'local' => true
]
);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"uuid": "%s"', $uuid));
$this->assertDbRecordExists('SharingGroups', ['uuid' => $uuid]);
}
public function testAddSharingGroupNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$faker = \Faker\Factory::create();
$uuid = $faker->uuid;
$this->post(
self::ENDPOINT,
[
'uuid' => $uuid,
'name' => 'Test Sharing Group',
'releasability' => 'Sharing Group A',
'description' => 'Sharing Group A description',
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'user_id' => UsersFixture::USER_ADMIN_ID,
'active' => true,
'local' => true
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('SharingGroups', ['uuid' => $uuid]);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\SharingGroupsFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteSharingGroupApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/sharingGroups/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.SharingGroups'
];
public function testDeleteSharingGroup(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, SharingGroupsFixture::SHARING_GROUP_A_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('SharingGroups', ['id' => SharingGroupsFixture::SHARING_GROUP_A_ID]);
}
public function testDeleteSharingGroupNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, SharingGroupsFixture::SHARING_GROUP_A_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('SharingGroups', ['id' => SharingGroupsFixture::SHARING_GROUP_A_ID]);
}
}

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\SharingGroupsFixture;
use App\Test\Helper\ApiTestTrait;
class EditSharingGroupApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/sharingGroups/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.SharingGroups'
];
public function testEditSharingGroup(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, SharingGroupsFixture::SHARING_GROUP_A_ID);
$this->put(
$url,
[
'name' => 'Test Sharing Group 4321',
]
);
$this->assertResponseOk();
$this->assertDbRecordExists(
'SharingGroups',
[
'id' => SharingGroupsFixture::SHARING_GROUP_A_ID,
'name' => 'Test Sharing Group 4321',
]
);
}
public function testEditSharingGroupNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, SharingGroupsFixture::SHARING_GROUP_B_ID);
$this->put(
$url,
[
'name' => 'Test Sharing Group 1234'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists(
'SharingGroups',
[
'id' => SharingGroupsFixture::SHARING_GROUP_B_ID,
'name' => 'Test Sharing Group 1234'
]
);
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\SharingGroupsFixture;
use App\Test\Helper\ApiTestTrait;
class IndexSharingGroupsApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/sharingGroups/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.SharingGroups'
];
public function testIndexSharingGroups(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', SharingGroupsFixture::SHARING_GROUP_A_ID));
$this->assertResponseContains(sprintf('"id": %d', SharingGroupsFixture::SHARING_GROUP_B_ID));
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\SharingGroupsFixture;
use App\Test\Helper\ApiTestTrait;
class ViewSharingGroupApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/sharingGroups/view';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.SharingGroups'
];
public function testViewSharingGroupById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, SharingGroupsFixture::SHARING_GROUP_A_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"id": %d', SharingGroupsFixture::SHARING_GROUP_A_ID));
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class IndexTagsApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/tags/index';
protected $fixtures = [
'app.TagsTags',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexTags(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains('"name": "red"');
$this->assertResponseContains('"name": "green"');
$this->assertResponseContains('"name": "blue"');
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\RolesFixture;
use App\Test\Helper\ApiTestTrait;
class AddUserApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/add';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testAddUser(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->post(
self::ENDPOINT,
[
'individual_id' => UsersFixture::USER_REGULAR_USER_ID,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'role_id' => RolesFixture::ROLE_REGULAR_USER_ID,
'disabled' => false,
'username' => 'test',
'password' => 'Password123456!',
]
);
$this->assertResponseOk();
$this->assertResponseContains('"username": "test"');
$this->assertDbRecordExists('Users', ['username' => 'test']);
}
public function testAddUserNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$this->post(
self::ENDPOINT,
[
'individual_id' => UsersFixture::USER_REGULAR_USER_ID,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'role_id' => RolesFixture::ROLE_REGULAR_USER_ID,
'disabled' => false,
'username' => 'test',
'password' => 'Password123456!'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Users', ['username' => 'test']);
}
}

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
use Cake\Auth\FormAuthenticate;
use Cake\Http\ServerRequest;
use Cake\Http\Response;
use Cake\Controller\ComponentRegistry;
class ChangePasswordApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/edit';
/** @var \Cake\Auth\FormAuthenticate */
protected $auth;
/** @var \Cake\Controller\ComponentRegistry */
protected $collection;
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function setUp(): void
{
parent::setUp();
$this->initializeOpenApiValidator();
$this->collection = new ComponentRegistry();
$this->auth = new FormAuthenticate($this->collection, [
'userModel' => 'Users',
]);
}
public function testChangePasswordOwnUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$newPassword = 'Test12345678!';
$this->put(
self::ENDPOINT,
[
'password' => $newPassword,
]
);
$this->assertResponseOk();
// Test new password with form login
$request = new ServerRequest([
'url' => 'users/login',
'post' => [
'username' => UsersFixture::USER_REGULAR_USER_USERNAME,
'password' => $newPassword
],
]);
$result = $this->auth->authenticate($request, new Response());
$this->assertEquals(UsersFixture::USER_REGULAR_USER_ID, $result['id']);
$this->assertEquals(UsersFixture::USER_REGULAR_USER_USERNAME, $result['username']);
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
class DeleteUserApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/delete';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testDeleteUser(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID);
$this->delete($url);
$this->assertResponseOk();
$this->assertDbRecordNotExists('Users', ['id' => UsersFixture::USER_REGULAR_USER_ID]);
}
public function testDeleteUserNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_ORG_ADMIN_ID);
$this->delete($url);
$this->assertResponseCode(405);
$this->assertDbRecordExists('Users', ['id' => UsersFixture::USER_ORG_ADMIN_ID]);
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Fixture\RolesFixture;
use App\Test\Helper\ApiTestTrait;
class EditUserApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/edit';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testEditUser(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID);
$this->put(
$url,
[
'id' => UsersFixture::USER_REGULAR_USER_ID,
'role_id' => RolesFixture::ROLE_ORG_ADMIN_ID,
]
);
$this->assertResponseOk();
$this->assertDbRecordExists('Users', [
'id' => UsersFixture::USER_REGULAR_USER_ID,
'role_id' => RolesFixture::ROLE_ORG_ADMIN_ID
]);
}
public function testEditRoleNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$this->put(
self::ENDPOINT,
[
'role_id' => RolesFixture::ROLE_ADMIN_ID,
]
);
$this->assertResponseOk();
$this->assertDbRecordNotExists('Users', [
'id' => UsersFixture::USER_REGULAR_USER_ID,
'role_id' => RolesFixture::ROLE_ADMIN_ID
]);
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
class IndexUsersApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/index';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testIndexUsers(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_ADMIN_USERNAME));
}
}

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
use App\Test\Helper\ApiTestTrait;
class ViewUserApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/users/view';
protected $fixtures = [
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function testViewMyUser(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_ADMIN_USERNAME));
}
public function testViewUserById(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID);
$this->get($url);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"username": "%s"', UsersFixture::USER_REGULAR_USER_USERNAME));
}
}

View File

@ -40,10 +40,14 @@ class ApplicationTest extends IntegrationTestCase
$app->bootstrap();
$plugins = $app->getPlugins();
$this->assertCount(3, $plugins);
$this->assertCount(7, $plugins);
$this->assertSame('Bake', $plugins->get('Bake')->getName());
$this->assertSame('DebugKit', $plugins->get('DebugKit')->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());
}
/**

View File

@ -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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Controller\Users;
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::USER_ADMIN_USERNAME,
'password' => UsersFixture::USER_ADMIN_PASSWORD,
]);
$this->assertSessionHasKey('authUser.uuid');
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
@ -17,6 +18,11 @@ declare(strict_types=1);
use Cake\Core\Configure;
use Cake\Datasource\ConnectionManager;
use Migrations\TestSuite\Migrator;
use \League\OpenAPIValidation\PSR7\ValidatorBuilder;
use \League\OpenAPIValidation\PSR7\RequestValidator;
use \League\OpenAPIValidation\PSR7\ResponseValidator;
use \League\OpenAPIValidation\PSR7\OperationAddress;
/**
* Test runner bootstrap.
@ -50,3 +56,19 @@ ConnectionManager::alias('test_debug_kit', 'debug_kit');
// does not allow the sessionid to be set after stdout
// has been written to.
session_id('cli');
if (!$_ENV['SKIP_DB_MIGRATIONS']) {
echo "[ * ] Running DB migrations, it may take some time ...\n";
$migrator = new Migrator();
$migrator->runMany([
['connection' => 'test'],
['plugin' => 'Tags', 'connection' => 'test'],
['plugin' => 'ADmad/SocialAuth', 'connection' => 'test']
]);
} else {
echo "[ * ] Skipping DB migrations ...\n";
}
$specFile = $_ENV['OPENAPI_SPEC'] ?? APP . '../webroot/docs/openapi.yaml';
// Initialize OpenAPI spec validator
Configure::write('App.OpenAPIValidator', (new ValidatorBuilder)->fromYamlFile($specFile));

2055
webroot/docs/openapi.yaml Normal file

File diff suppressed because it is too large Load Diff