From 1479375ed3860e41b0d413f7a68c382f29ca97fb Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 10:53:09 +0100 Subject: [PATCH 1/6] feat: add fixtures + test example --- config/app.php | 5 +- phpunit.xml.dist | 13 +- tests/Fixture/ApplicationsFixture.php | 28 ++++ tests/Fixture/ObjectTypesFixture.php | 75 +++++++++++ tests/Fixture/ObjectsFixture.php | 78 +++++++++++ tests/Fixture/ProfilesFixture.php | 26 ++++ tests/Fixture/PropertiesFixture.php | 20 +++ tests/Fixture/PropertyTypesFixture.php | 171 +++++++++++++++++++++++++ tests/Fixture/RolesFixture.php | 26 ++++ tests/Fixture/RolesUsersFixture.php | 22 ++++ tests/Fixture/UsersFixture.php | 35 +++++ tests/IntegrationTestCase.php | 47 +++++++ tests/TestCase/UsersTest.php | 38 ++++++ 13 files changed, 577 insertions(+), 7 deletions(-) create mode 100644 tests/Fixture/ApplicationsFixture.php create mode 100644 tests/Fixture/ObjectTypesFixture.php create mode 100644 tests/Fixture/ObjectsFixture.php create mode 100644 tests/Fixture/ProfilesFixture.php create mode 100644 tests/Fixture/PropertiesFixture.php create mode 100644 tests/Fixture/PropertyTypesFixture.php create mode 100644 tests/Fixture/RolesFixture.php create mode 100644 tests/Fixture/RolesUsersFixture.php create mode 100644 tests/Fixture/UsersFixture.php create mode 100644 tests/IntegrationTestCase.php create mode 100644 tests/TestCase/UsersTest.php diff --git a/config/app.php b/config/app.php index b04a7c5..2871840 100644 --- a/config/app.php +++ b/config/app.php @@ -213,7 +213,10 @@ 'skipLog' => ['Cake\Network\Exception\NotFoundException', 'BEdita\API\Exception\ExpiredTokenException'], 'log' => true, 'trace' => true, - 'ignoredDeprecationPaths' => ['vendor/cakephp/cakephp/src/Log/Engine/FileLog.php'], + 'ignoredDeprecationPaths' => [ + 'vendor/cakephp/cakephp/src/Log/Engine/FileLog.php', + 'vendor/cakephp/migrations/src/Db/Table/ForeignKey.php', + ], ], /* diff --git a/phpunit.xml.dist b/phpunit.xml.dist index affe678..9b6c640 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,25 +7,26 @@ bootstrap="./tests/bootstrap.php" cacheDirectory=".phpunit.cache" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.1/phpunit.xsd" + displayDetailsOnTestsThatTriggerDeprecations="false" + displayDetailsOnTestsThatTriggerErrors="false" + displayDetailsOnTestsThatTriggerNotices="false" + displayDetailsOnTestsThatTriggerWarnings="false" + displayDetailsOnPhpunitDeprecations="false" > + - + ./tests/TestCase/ - - - - - diff --git a/tests/Fixture/ApplicationsFixture.php b/tests/Fixture/ApplicationsFixture.php new file mode 100644 index 0000000..6cad06f --- /dev/null +++ b/tests/Fixture/ApplicationsFixture.php @@ -0,0 +1,28 @@ + API_KEY, + 'client_secret' => null, + 'name' => 'my_webapp', + 'created' => '2026-01-29 07:10:57', + 'modified' => '2026-01-29 07:10:57', + 'enabled' => 1, + ], + ]; +} diff --git a/tests/Fixture/ObjectTypesFixture.php b/tests/Fixture/ObjectTypesFixture.php new file mode 100644 index 0000000..a63e6de --- /dev/null +++ b/tests/Fixture/ObjectTypesFixture.php @@ -0,0 +1,75 @@ + 'object', + 'name' => 'objects', + 'is_abstract' => true, + 'parent_id' => null, + 'tree_left' => 1, + 'tree_right' => 24, + 'description' => null, + 'plugin' => 'BEdita/Core', + 'model' => 'Objects', + 'created' => '2025-11-10 09:27:23', + 'modified' => '2025-11-10 09:27:23', + 'enabled' => true, + 'core_type' => true, + 'translation_rules' => null, + 'is_translatable' => false, + ], + // 2 + [ + 'singular' => 'user', + 'name' => 'users', + 'is_abstract' => false, + 'parent_id' => 1, + 'tree_left' => 6, + 'tree_right' => 7, + 'description' => null, + 'plugin' => 'BEdita/Core', + 'model' => 'Users', + 'created' => '2025-11-10 09:27:23', + 'modified' => '2025-11-10 09:27:23', + 'enabled' => true, + 'core_type' => true, + 'translation_rules' => null, + 'is_translatable' => false, + ], + // 3 + [ + 'singular' => 'profile', + 'name' => 'profiles', + 'is_abstract' => false, + 'parent_id' => 1, + 'tree_left' => 4, + 'tree_right' => 5, + 'description' => null, + 'associations' => ['Tags'], + 'plugin' => 'BEdita/Core', + 'model' => 'Profiles', + 'created' => '2025-11-10 09:27:23', + 'modified' => '2025-11-10 09:27:23', + 'enabled' => true, + 'core_type' => true, + 'translation_rules' => null, + 'is_translatable' => false, + ], + ]; +} diff --git a/tests/Fixture/ObjectsFixture.php b/tests/Fixture/ObjectsFixture.php new file mode 100644 index 0000000..23d5ae6 --- /dev/null +++ b/tests/Fixture/ObjectsFixture.php @@ -0,0 +1,78 @@ + 2, + 'status' => 'on', + 'uname' => 'gustavo-admin', + 'locked' => 1, + 'deleted' => 0, + 'created' => '2026-01-29 07:09:23', + 'modified' => '2026-01-29 07:09:23', + 'title' => 'Gustavo Admin', + 'lang' => 'it', + 'created_by' => 1, + 'modified_by' => 1, + ], + ]; + + /** + * @inheritDoc + */ + public function init(): void + { + parent::init(); + + // remove `objects_createdby_fk` and `objects_modifiedby_fk` constraints + // to avoid PostgreSQL error inserting first user that references itself. + // CakePHP inserting fixture disables constraints but + // when the constraints are enabled again PostgreSQL give an SQL error. + $connection = ConnectionManager::get($this->connection()); + if (!$connection->getDriver() instanceof Postgres) { + return; + } + + $constraints = $this->_schema->constraints(); + $removeConstraints = ['objects_createdby_fk', 'objects_modifiedby_fk']; + if (empty(array_intersect($constraints, $removeConstraints))) { + return; + } + + $restoreConstraints = []; + foreach ($this->_schema->constraints() as $name) { + if (in_array($name, $removeConstraints)) { + continue; + } + + $restoreConstraints[$name] = $this->_schema->getConstraint($name); + $this->_schema->dropConstraint($name); + } + + $dropConstraintSql = $this->_schema->dropConstraintSql($connection); + foreach ($dropConstraintSql as $sql) { + $connection->execute($sql); + } + + foreach ($restoreConstraints as $name => $attrs) { + $this->_schema->addConstraint($name, $attrs); + } + } +} diff --git a/tests/Fixture/ProfilesFixture.php b/tests/Fixture/ProfilesFixture.php new file mode 100644 index 0000000..586a3a8 --- /dev/null +++ b/tests/Fixture/ProfilesFixture.php @@ -0,0 +1,26 @@ + 1, + 'name' => 'Gustavo', + 'surname' => 'Admin', + 'email' => 'gustavo-admin@example.com', + ], + ]; +} diff --git a/tests/Fixture/PropertiesFixture.php b/tests/Fixture/PropertiesFixture.php new file mode 100644 index 0000000..7c2227f --- /dev/null +++ b/tests/Fixture/PropertiesFixture.php @@ -0,0 +1,20 @@ +records = [ + // 1 + [ + 'name' => 'string', + 'params' => ['type' => 'string'], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 2 + [ + 'name' => 'text', + 'params' => [ + 'type' => 'string', + 'contentMediaType' => 'text/html', + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 3 + [ + 'name' => 'status', + 'params' => [ + 'type' => 'string', + 'enum' => ['on', 'off', 'draft'], + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 4 + [ + 'name' => 'email', + 'params' => [ + 'type' => 'string', + 'format' => 'email', + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 5 + [ + 'name' => 'url', + 'params' => [ + 'type' => 'string', + 'format' => 'uri', + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 6 + [ + 'name' => 'date', + 'params' => [ + 'type' => 'string', + 'format' => 'date', + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 7 + [ + 'name' => 'datetime', + 'params' => [ + 'type' => 'string', + 'format' => 'date-time', + ], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 8 + [ + 'name' => 'number', + 'params' => ['type' => 'number'], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 9 + [ + 'name' => 'integer', + 'params' => ['type' => 'integer'], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 10 + [ + 'name' => 'boolean', + 'params' => ['type' => 'boolean'], + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 11 + [ + 'name' => 'json', + 'params' => new stdClass(), + 'created' => '2025-11-01 09:23:43', + 'modified' => '2025-11-01 09:23:43', + 'core_type' => true, + ], + // 12 + [ + 'name' => 'unused property type', + 'params' => [ + 'type' => 'object', + 'properties' => [ + 'gustavo' => ['const' => 'supporto'], + ], + 'required' => ['gustavo'], + ], + 'created' => '2025-11-02 09:23:43', + 'modified' => '2025-11-02 09:23:43', + 'core_type' => false, + ], + // 13 + [ + 'name' => 'children_order', + 'params' => [ + 'type' => 'string', + 'enum' => [ + 'position', + '-position', + 'title', + '-title', + 'created', + '-created', + 'modified', + '-modified', + 'publish_start', + '-publish_start', + ], + ], + 'created' => '2022-12-01 15:35:21', + 'modified' => '2022-12-01 15:35:21', + 'core_type' => true, + ], + ]; + + parent::init(); + } +} diff --git a/tests/Fixture/RolesFixture.php b/tests/Fixture/RolesFixture.php new file mode 100644 index 0000000..999964a --- /dev/null +++ b/tests/Fixture/RolesFixture.php @@ -0,0 +1,26 @@ + 'admin', + 'unchangeable' => 1, + 'created' => '2025-12-29 11:36:00', + 'modified' => '2025-12-29 11:36:00', + 'priority' => 0, + ], + ]; +} diff --git a/tests/Fixture/RolesUsersFixture.php b/tests/Fixture/RolesUsersFixture.php new file mode 100644 index 0000000..773ba41 --- /dev/null +++ b/tests/Fixture/RolesUsersFixture.php @@ -0,0 +1,22 @@ + 1, + 'user_id' => 1, + ], + ]; +} diff --git a/tests/Fixture/UsersFixture.php b/tests/Fixture/UsersFixture.php new file mode 100644 index 0000000..cac6cb3 --- /dev/null +++ b/tests/Fixture/UsersFixture.php @@ -0,0 +1,35 @@ +records = [ + [ + 'id' => 1, + 'username' => 'gustavo-admin', + 'password_hash' => (new LegacyPasswordHasher(['hashType' => 'md5']))->hash('supporto'), + 'blocked' => 0, + 'last_login' => null, + 'last_login_err' => null, + 'num_login_err' => 0, + 'verified' => '2026-01-29 11:36:00', + 'password_modified' => '2026-01-29 11:36:00', + ], + ]; + + parent::init(); + } +} diff --git a/tests/IntegrationTestCase.php b/tests/IntegrationTestCase.php new file mode 100644 index 0000000..ddd4014 --- /dev/null +++ b/tests/IntegrationTestCase.php @@ -0,0 +1,47 @@ + + */ + protected array $fixtures = []; + + /** + * The required fixtures for authentication. + * They are added to fixtures present in test case class + * + * @var array + */ + protected array $authFixtures = [ + 'app.Applications', + 'app.ObjectTypes', + 'app.Objects', + 'app.Profiles', + 'app.Users', + 'app.Roles', + 'app.RolesUsers', + 'app.PropertyTypes', + 'app.Properties', + ]; + + /** + * Default user used for authentication + * + * @var array + */ + protected array $defaultUser = [ + 'username' => 'gustavo-admin', + 'password' => 'supporto', + ]; +} diff --git a/tests/TestCase/UsersTest.php b/tests/TestCase/UsersTest.php new file mode 100644 index 0000000..5d40e0d --- /dev/null +++ b/tests/TestCase/UsersTest.php @@ -0,0 +1,38 @@ +configRequestHeaders('GET', $this->getUserAuthHeader(username: 'gustavo-admin', password: 'supporto')); + $this->get('/users/1'); + $this->assertResponseOk(); + } +} From 5f09acd14a9eb423285ee23e9bbce06a00640b93 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 10:58:21 +0100 Subject: [PATCH 2/6] chore fix: php stan --- phpstan.neon.dist | 1 + tests/Fixture/ApplicationsFixture.php | 4 +--- tests/Fixture/ObjectTypesFixture.php | 4 +--- tests/Fixture/ObjectsFixture.php | 4 +--- tests/Fixture/ProfilesFixture.php | 4 +--- tests/Fixture/PropertiesFixture.php | 4 +--- 6 files changed, 6 insertions(+), 15 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index cb0d17d..b1bc3e0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,3 +7,4 @@ parameters: - tests excludePaths: - src/Console/Installer.php + - tests/Fixture diff --git a/tests/Fixture/ApplicationsFixture.php b/tests/Fixture/ApplicationsFixture.php index 6cad06f..4e499f3 100644 --- a/tests/Fixture/ApplicationsFixture.php +++ b/tests/Fixture/ApplicationsFixture.php @@ -11,9 +11,7 @@ class ApplicationsFixture extends TestFixture { /** - * Records - * - * @var array + * @inheritDoc */ public array $records = [ [ diff --git a/tests/Fixture/ObjectTypesFixture.php b/tests/Fixture/ObjectTypesFixture.php index a63e6de..825a9d1 100644 --- a/tests/Fixture/ObjectTypesFixture.php +++ b/tests/Fixture/ObjectTypesFixture.php @@ -11,9 +11,7 @@ class ObjectTypesFixture extends TestFixture { /** - * Records - * - * @var array + * @inheritDoc */ public array $records = [ // 1 diff --git a/tests/Fixture/ObjectsFixture.php b/tests/Fixture/ObjectsFixture.php index 23d5ae6..4e35492 100644 --- a/tests/Fixture/ObjectsFixture.php +++ b/tests/Fixture/ObjectsFixture.php @@ -13,9 +13,7 @@ class ObjectsFixture extends TestFixture { /** - * Records - * - * @var array + * @inheritDoc */ public array $records = [ // 1 diff --git a/tests/Fixture/ProfilesFixture.php b/tests/Fixture/ProfilesFixture.php index 586a3a8..c896158 100644 --- a/tests/Fixture/ProfilesFixture.php +++ b/tests/Fixture/ProfilesFixture.php @@ -11,9 +11,7 @@ class ProfilesFixture extends TestFixture { /** - * Records - * - * @var array + * @inheritDoc */ public array $records = [ [ diff --git a/tests/Fixture/PropertiesFixture.php b/tests/Fixture/PropertiesFixture.php index 7c2227f..ff7a47b 100644 --- a/tests/Fixture/PropertiesFixture.php +++ b/tests/Fixture/PropertiesFixture.php @@ -11,9 +11,7 @@ class PropertiesFixture extends TestFixture { /** - * Records - * - * @var array + * @inheritDoc */ public array $records = [ ]; From 9be77bd6ad4bdcb54b54327084b67e1ddcb5c1cb Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 16:51:12 +0100 Subject: [PATCH 3/6] ci: debug mysql --- .github/workflows/php.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index a0e7173..61d43f8 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -93,6 +93,19 @@ jobs: - name: 'Install dependencies with Composer' run: 'composer install --prefer-dist --no-interaction' + - name: 'Wait for MySQL to be ready' + if: ${{ fromJson(matrix.db).pdo == 'mysql' }} + run: | + for i in {1..30}; do + if mysqladmin ping -h 127.0.0.1 -u"bedita" -p"bedita" --silent; then + echo "MySQL is up!" + break + fi + echo "Waiting for MySQL... ($i)" + sleep 2 + done + mysqladmin ping -h 127.0.0.1 -u"bedita" -p"bedita" --silent || (echo "MySQL did not become available in time" && exit 1) + - name: 'Run PHPUnit with coverage' run: 'vendor/bin/phpunit --coverage-clover=${{ matrix.php-version }}-${{ strategy.job-index }}-clover.xml' From e911b36a00647248f9ebb5f648dad5961b80f7d1 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 16:56:40 +0100 Subject: [PATCH 4/6] ci: debug mysql --- .github/workflows/php.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 61d43f8..8e56706 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -41,7 +41,7 @@ jobs: matrix: php-version: [8.3, 8.4] db: - - '{"vendor": "MySQL 8.4", "pdo": "mysql", "dsn": "mysql://bedita:bedita@127.0.0.1:3306/bedita", "image": "mysql:8.4", "options": "--health-cmd \"mysqladmin ping -h localhost\" --health-interval 10s --health-timeout 5s --health-retries 5"}' + - '{"vendor": "MySQL 8.0", "pdo": "mysql", "dsn": "mysql://bedita:bedita@127.0.0.1:3306/bedita", "image": "mysql:8.0", "options": "--health-cmd \"mysqladmin ping -h localhost\" --health-interval 10s --health-timeout 5s --health-retries 5"}' - '{"vendor": "SQLite", "pdo": "sqlite", "dsn": "sqlite://tmp/test.sql", "db_name": "", "image": "nginx:alpine", "options": "--health-cmd \"/bin/true\" --health-interval 1s --health-timeout 2s --health-retries 5"}' - '{"vendor": "PostgreSQL 18", "pdo": "pgsql", "dsn": "postgres://bedita:bedita@127.0.0.1:5432/bedita", "image": "postgres:18", "options": "--health-cmd \"pg_isready\" --health-interval 10s --health-timeout 5s --health-retries 5"}' env: @@ -93,19 +93,6 @@ jobs: - name: 'Install dependencies with Composer' run: 'composer install --prefer-dist --no-interaction' - - name: 'Wait for MySQL to be ready' - if: ${{ fromJson(matrix.db).pdo == 'mysql' }} - run: | - for i in {1..30}; do - if mysqladmin ping -h 127.0.0.1 -u"bedita" -p"bedita" --silent; then - echo "MySQL is up!" - break - fi - echo "Waiting for MySQL... ($i)" - sleep 2 - done - mysqladmin ping -h 127.0.0.1 -u"bedita" -p"bedita" --silent || (echo "MySQL did not become available in time" && exit 1) - - name: 'Run PHPUnit with coverage' run: 'vendor/bin/phpunit --coverage-clover=${{ matrix.php-version }}-${{ strategy.job-index }}-clover.xml' From c1f4ab5a0ec5ad47f3e2567d1f16818156dc0509 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 17:05:44 +0100 Subject: [PATCH 5/6] ci: debug mysql --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 8e56706..a0e7173 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -41,7 +41,7 @@ jobs: matrix: php-version: [8.3, 8.4] db: - - '{"vendor": "MySQL 8.0", "pdo": "mysql", "dsn": "mysql://bedita:bedita@127.0.0.1:3306/bedita", "image": "mysql:8.0", "options": "--health-cmd \"mysqladmin ping -h localhost\" --health-interval 10s --health-timeout 5s --health-retries 5"}' + - '{"vendor": "MySQL 8.4", "pdo": "mysql", "dsn": "mysql://bedita:bedita@127.0.0.1:3306/bedita", "image": "mysql:8.4", "options": "--health-cmd \"mysqladmin ping -h localhost\" --health-interval 10s --health-timeout 5s --health-retries 5"}' - '{"vendor": "SQLite", "pdo": "sqlite", "dsn": "sqlite://tmp/test.sql", "db_name": "", "image": "nginx:alpine", "options": "--health-cmd \"/bin/true\" --health-interval 1s --health-timeout 2s --health-retries 5"}' - '{"vendor": "PostgreSQL 18", "pdo": "pgsql", "dsn": "postgres://bedita:bedita@127.0.0.1:5432/bedita", "image": "postgres:18", "options": "--health-cmd \"pg_isready\" --health-interval 10s --health-timeout 5s --health-retries 5"}' env: From e8a94064b3728834efc87d99048550d199a99bc6 Mon Sep 17 00:00:00 2001 From: dante di domenico Date: Thu, 29 Jan 2026 17:18:04 +0100 Subject: [PATCH 6/6] fix: ci --- .github/workflows/php.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index a0e7173..602e7ee 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -61,6 +61,7 @@ jobs: POSTGRES_PASSWORD: 'bedita' POSTGRES_DB: 'bedita' ports: + - '3306:3306' - '5432:5432' options: '${{ fromJson(matrix.db).options }}'