diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..fc59992 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,65 @@ +name: Test + +on: + push: + branches: [master] + pull_request: + +jobs: + phpunit: + runs-on: ubuntu-latest + + services: + mariadb: + image: mariadb:10.11 + env: + MARIADB_ROOT_PASSWORD: root + MARIADB_DATABASE: dms-calendar + MARIADB_USER: calendar + MARIADB_PASSWORD: calendar + ports: + - 3306:3306 + options: >- + --health-cmd="healthcheck.sh --connect --innodb_initialized" + --health-interval=5s + --health-timeout=5s + --health-retries=20 + + env: + DB_HOST: 127.0.0.1 + DB_USERNAME: calendar + DB_PASSWORD: calendar + DB_DATABASE: dms-calendar + + steps: + - uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: mbstring, intl, pdo_mysql + tools: composer:v2 + coverage: none + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-php74-${{ hashFiles('composer.lock') }} + restore-keys: ${{ runner.os }}-php74- + + - name: Install Composer dependencies + run: composer install --no-interaction --prefer-dist --no-progress + + - name: Configure application + run: ln -s app.default.php config/app.php + + - name: Create test database + run: | + mysql -h 127.0.0.1 -uroot -proot -e "CREATE DATABASE \`dms-calendar-test\`;" + mysql -h 127.0.0.1 -uroot -proot -e "GRANT ALL PRIVILEGES ON \`dms-calendar-test\`.* TO 'calendar'@'%';" + mysql -h 127.0.0.1 -uroot -proot -e "FLUSH PRIVILEGES;" + + - name: Run PHPUnit + run: vendor/bin/phpunit --no-coverage diff --git a/docs/README.md b/docs/README.md index d143059..9a3bad2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -45,3 +45,21 @@ More details on the rest can be found at [CakePHP](https://book.cakephp.org/) - **Warning:** check [composer.json](../composer.json) to ensure you're looking at docs for the right version of CakePHP. + +## Tests + +Tests live alongside the code in [src/](../src/), not under `tests/TestCase/`. [phpunit.xml.dist](../phpunit.xml.dist) is configured to discover anything matching `*Test.php` in `./src`. Run the suite under Docker: + +``` +docker compose exec -w /var/www app vendor/bin/phpunit --no-coverage +``` + +### Test datasource + +[tests/bootstrap.php](../tests/bootstrap.php) registers a dedicated `test` connection by reading the `default` config from [config/app.default.php](../config/app.default.php) and appending `-test` to the database name. Fixtures `TRUNCATE` the tables they manage, so the suite is careful never to run against your dev database — only against the derived `-test` schema on the same host. + +**Production guardrail:** the bootstrap refuses to start if the resolved `default` host isn't on a small allowlist (`localhost`, `127.0.0.1`, `::1`, `db` — the docker-compose service name in [docker-compose.yml](../docker-compose.yml)). This stops `vendor/bin/phpunit` from doing any damage if `DB_HOST` is misconfigured to point at the prod RDS instance. If you legitimately need to run tests against another host, edit the allowlist in `tests/bootstrap.php`. + +### CI + +[.github/workflows/test.yml](../.github/workflows/test.yml) runs the full PHPUnit suite on every push and pull request against a MariaDB 10.11 service container. CI uses `DB_HOST=127.0.0.1`, which is on the allowlist above. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6e9430d..3f610d0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,7 +14,7 @@ - ./tests/TestCase + ./src diff --git a/src/Controller/CommitteesControllerTest.php b/src/Controller/CommitteesControllerTest.php index 1c3102a..088927f 100644 --- a/src/Controller/CommitteesControllerTest.php +++ b/src/Controller/CommitteesControllerTest.php @@ -17,7 +17,7 @@ class CommitteesControllerTest extends IntegrationTestCase */ public $fixtures = [ 'app.committees', - 'app.honorarias' + 'app.honoraria' ]; /** diff --git a/src/Controller/ContactsControllerTest.php b/src/Controller/ContactsControllerTest.php index c0a360d..770d5f5 100644 --- a/src/Controller/ContactsControllerTest.php +++ b/src/Controller/ContactsControllerTest.php @@ -19,7 +19,7 @@ class ContactsControllerTest extends IntegrationTestCase 'app.contacts', 'app.w9s', 'app.events', - 'app.honorarias' + 'app.honoraria' ]; /** diff --git a/src/Controller/EventsControllerTest.php b/src/Controller/EventsControllerTest.php index 5116245..1dc20f7 100644 --- a/src/Controller/EventsControllerTest.php +++ b/src/Controller/EventsControllerTest.php @@ -20,7 +20,7 @@ class EventsControllerTest extends IntegrationTestCase 'app.rooms', 'app.contacts', 'app.prerequisites', - 'app.honorarias', + 'app.honoraria', 'app.categories', 'app.tools', 'app.files', diff --git a/src/Controller/HonorariaControllerTest.php b/src/Controller/HonorariaControllerTest.php index ccf488f..bb8e659 100644 --- a/src/Controller/HonorariaControllerTest.php +++ b/src/Controller/HonorariaControllerTest.php @@ -16,7 +16,7 @@ class HonorariaControllerTest extends IntegrationTestCase * @var array */ public $fixtures = [ - 'app.honorarias', + 'app.honoraria', 'app.events', 'app.committees' ]; diff --git a/src/Model/Table/EventsTableTest.php b/src/Model/Table/EventsTableTest.php index b40b22e..35ef3f0 100644 --- a/src/Model/Table/EventsTableTest.php +++ b/src/Model/Table/EventsTableTest.php @@ -28,7 +28,7 @@ class EventsTableTest extends TestCase 'app.rooms', 'app.contacts', 'app.prerequisites', - 'app.honorarias', + 'app.honoraria', 'app.categories', 'app.tools', 'app.files', diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0ca191e..a4eeb21 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,3 +10,23 @@ require dirname(__DIR__) . '/config/bootstrap.php'; $_SERVER['PHP_SELF'] = '/'; + +// Register a dedicated 'test' datasource that mirrors the default +// connection but points at a separate database. Fixtures truncate +// tables, so we never want them touching the dev database. +$defaultConfig = \Cake\Datasource\ConnectionManager::getConfig('default'); + +// Guardrail: refuse to run tests against any non-local DB host. Fixtures +// TRUNCATE tables, so a misconfigured DATABASE_URL pointing at prod could +// wipe a 'dms-calendar-test' schema living on the prod RDS instance. +$host = $defaultConfig['host'] ?? 'localhost'; +$allowedHosts = ['localhost', '127.0.0.1', '::1', 'db']; +if (!in_array($host, $allowedHosts, true)) { + fwrite(STDERR, "REFUSING to run tests: 'default' connection host '{$host}' " + . "is not in the local allowlist (" . implode(', ', $allowedHosts) . ").\n" + . "If this is intentional, edit tests/bootstrap.php.\n"); + exit(1); +} + +$defaultConfig['database'] = ($defaultConfig['database'] ?? 'dms-calendar') . '-test'; +\Cake\Datasource\ConnectionManager::setConfig('test', $defaultConfig);