remove test database when tests ends (Symfony / PHP Unit) - symfony

I am using PHPUnit (9.5) with Symfony (5.3).
For my tests, I use the default test database config from config/packages/test/doctrine.yaml :
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
So my tests use the same database as prod with the suffix '_test'.
I added some code to tests/bootstrap.php to automate database creation / reset before each test runs :
// delete database if exists, then create
passthru('php bin/console doctrine:database:drop --env=test --force --if-exists');
passthru('php bin/console doctrine:database:create --env=test');
// run migrations
passthru('php bin/console doctrine:migrations:migrate --env=test -n');
and I use dama/doctrine-test-bundle for automatic transactions for each tests.
That is working very well, but I have a question :
Is there a way to delete the database at the end of test run ? (like I did in bootstrap.php)

I understand that your bootstrap.php file is running before the test, you need a solution to launch something after your test.
First, create a command that drop the test database.
In anyway, be very careful that the code in your command stop all execution, if you aren't in an explicit test environment (because it means you are in a production environment).
Then, you can alter your composer.json file to launch the created command after your test in a chain of scripts.
Here is an exemple
"scripts": {
"test-and-remove": [
"#putenv APP_ENV=test",
"phpunit --configuration phpunit.xml",
"php bin/console app:drop-test-database"
],
Then you only have to launch your test via this new command:
composer test-and-remove

Related

In Symfony 5, the command doctrine:database:create outputs an error instead of creating a database for test environment

I'm learning Symfony 5 at Symfony 5: The Fast Track and I'm at the step 17.4 Working with a Test Database.
I can read from the beginning of this section:
... the Symfony CLI automatically exposes the DATABASE_URL
environment variable. When APP_ENV is test, like set when running
PHPUnit, it changes the database name from main to main_test so
that tests have their very own database.
Before being able to run the test, we need to “initialize” the test
database (create the database and migrate it):
$ APP_ENV=test symfony console doctrine:database:create
$ APP_ENV=test symfony console doctrine:migrations:migrate -n
My database name is guestbook, running under MySql & Apache, as specified in the .env file:
DATABASE_URL="mysql://root:#127.0.0.1:3306/guestbook?serverVersion=mariadb-10.4.19"
So, while I was expecting a database named guestbook_test to be created when I execute the command symfony console doctrine:database:create, it outputs the following error:
Could not create database `guestbook` for connection named default
An exception occurred while executing 'CREATE DATABASE `guestbook`':
SQLSTATE[HY000]: General error: 1007 Can't create database 'guestbook'; database exists
exit status 1
To make sure the environment is "test", I, first, tried these two ways:
In the .env file: APP_ENV=test
In the .env.local file: APP_ENV=test
But, I got the same error.
When I displayed the content of environment variable APP_ENV from a controller, using return new Response("APP_ENV = '" . getenv('APP_ENV') . "'");, it displays a null value: APP_ENV=''.
So, I assigned the value 'test' to APP_ENV in Real environment variables (for me, that was Windows/Paramaters/environment variables...etc). This once, the controller displays APP_ENV='test', but I get always the same error, when I execute the Doctrine command: symfony console doctrine:database:create
I don't know what I'm missing !! Please, any help?
UPDATE ON: 07 June 2021 22:05
I, even tried assigning the value test to APP_ENV in php.ini; but, when I displayed this env var using: symfony console debug:container --env-var=APP_ENV, I got:
Symfony Container Environment Variables
=======================================
// Displaying detailed environment variable usage matching APP_ENV
None of the environment variables match this name.
It's, little bit, strange since I have this env var assigned every where (in .env file, .env.local, php.ini and in a real env vars) and this command says there is no env var called APP_ENV !
What helped in my case:
create .env.local file
copy the DATABASE_URL variable with db name suffixed with _test
I also had to change db user to root, as my app db user didn't have permissions to create databases,

Symfony: Loading .env.test files

I thought this PR fixed the issue I am having - but I have this patch and it's still not working as I expected - what am I missing or mis-understanding?
https://github.com/symfony/symfony/pull/28533
I have created a .env.test with the following:
DATABASE_URL_TEST=mysql://apps:#localhost:3306/mydb_test
Then I dropped a doctrine.yaml inside the config/packages/test directory.
Symfony v4.2.3
However when I run this command from CLI:
APP_ENV=test bin/console doctrine:database:create --env=test
I am getting an error:
Environment variable not found: "DATABASE_URL_TEST".
Clearly the .env.test file is not being loaded - how do I get a specific environment configuration file to load - other than .env???
If indeed your application was a Symfony 3.x application at some point, what I would guess is that, during the upgrade process, those two lines out of the UPGRADE procedure were missed:
Then, upgrade the contents of your console script and your front
controller:
bin/console:
https://github.com/symfony/recipes/blob/master/symfony/console/3.3/bin/console
public/index.php:
https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/public/index.php
Indeed, it seems like bin/console have been changed recently to reflect the adaptation done on the DotEnv component: https://github.com/symfony/recipes/commit/3e471cbc7d359b3ab245f3b0748d698e8d29692c#diff-2af50efd729ff8e61dcbd936cf2b114b
Mind that you'll also need https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/4.2/config/bootstrap.php
I had a very similar problem. My issue was that my phpunit.xml.dist was pointing to the wrong bootstrap file:
Previously:
bootstrap="vendor/autoload.php"
Changed to:
bootstrap="tests/bootstrap.php"

Previously executed migration are not registered migrations

I'm trying to update my database with those commands
php bin/console make:migration
this return success
But when I try
php bin/console doctrine:migrations:migrate
I have this error:
WARNING! You have 5 previously executed migrations in the database >>that are not registered migrations.
>> 2018-12-17 10:42:04 (20181217104204)
>> 2018-12-17 13:19:24 (20181217131924)
>> 2018-12-17 13:40:58 (20181217134058)
>> 2018-12-18 10:41:38 (20181218104138)
>> 2018-12-18 13:15:49 (20181218131549)
Thing is, the database listed here are not in my migrations table from my database and they are not in my Migrations folder either.
How can I remove those wrong migrations ? Thanks.
This is a year old, but I've had problems a few times where I delete old migration files because they aren't relevant or whatever reason and had the same issue. I think the correct way to handle this is to delete references from the table directly.
php bin/console doctrine:query:sql "delete from migration_versions where version = '2020181217104204'";
EDIT - newer versions of Symfony are now using a "doctrine_migration_versions" table.
php bin/console doctrine:query:sql "delete from doctrine_migration_versions where version = '2020181217104204'";
Etc..
Encounterd the same probleme : I had previously copied already executed migration to the newly created migration table (due to doctrine update).
Renaming all version names as follow saved the day : 20190408092436 --> DoctrineMigrations\Version20190408092436

Symfony debug still enabled after cache:warmup --no-debug

I have Symfony 3.2.7 installed on a production server.
I issue the following commands:
bin/console cache:clear --no-warmup --no-debug --env=preview
bin/console cache:warmup --no-debug --env=preview
bin/console --version
I get the following output, showing that debug is enabled.
Symfony 3.2.7 (kernel: app, env: preview, debug: true)
What am I missing?
Nevermind.
Bad programmer on device.
The monolog.handlers.main.level value was set to debug.
Duh.
Sorry for the noise.
I've never used bin/console in a production server, but I don't think that information is reliable for your use case.
If you open the bin/console script in an editor you will see:
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod';
As you can see the $debug parameter is determined by a combination of environment variables and parameters.
Every time you call this script this value is recalculated.

How to set the environment in a Symfony2 console command

Hopefully a simple question - how does one specify which environment to use when running a console command in Symfony2. I've created a few commands, however I would like to run them in the context of my 'staging' environment when on my staging server and my 'prod' environment when on my production server (the different environments define different database connections). How do I configure and pass this information to my console command?
You have two options that will help you out. You can specify the environment that the console will run in with the --env flag, and use --no-debug to disable debug mode.
php app/console --env=staging your:console:command or php app/console --env=prod your:console:command should do what you're looking for (the console runs in the dev environment with debug on by default).
You can look at the code of the app/console file for more info.
You can also use the SYMFONY_ENV environment variable to set a default environment distinct to 'dev' (e.g. export SYMFONY_ENV=prod in ~/.bash_profile)
To answer the question #croca had, to expand on what #Francesc Rosàs posted, and as #Problematic suggested.
If you look in app/console you should see $env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
All this does is checks the input arguments passed to the console for --env or -e, checks the default value from getenv('SYMFONY_ENV'), or sets it to dev if neither are supplied.
It is then passed to $kernel = new AppKernel($env, $debug);
You could essentially either make changes directly to app/console to achieve your application's specific functionality or copy app/console to a separate file such as app/exec, then process the $env variable how you prefer to determine the desired environment.
Simple Example: app/exec
#!/usr/bin/env php
<?php
/**
* disabled debug mode,
* set environment based on requesting address being local
* otherwise the server's IP address
* be sure to perform at least chmod(750) on the file to ensure it is executable
* otherwise it must be prefixed with your php executable
*/
set_time_limit(0);
require_once __DIR__.'/bootstrap.php.cache';
require_once __DIR__.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
$input = new ArgvInput();
$env = ($_SERVER['REMOTE_ADDR'] === '127.0.0.1' || $_SERVER['REMOTE_ADDR'] === '::1' ? 'dev' :
($_SERVER['SERVER_ADDR'] === '192.168.2.1' ? 'test' : 'prod')
);
$kernel = new AppKernel($env, false);
$application = new Application($kernel);
$application->run($input);
Then call php app/exec namespace:command arguments --flags
Additionally you could process your own application instead of using the app/console AppKernel - instructions from Symfony can be found here: http://symfony.com/doc/current/components/console/introduction.html
The official documentation says:
By default, console commands run in the dev environment and you may want to change this for some commands.
So, as #Problematic suggest, you can specify the environment for your command using the flag "--env=your_env" or its shortcut "-e your_env".
I wonder whether it is possible to force the default environment for a command. I mean, without having to use the flags. Any idea?
There is another variant, not so convenient though, but works also with composer
SYMFONY_ENV=prod app/console cache:clear
Maybe you could look at the implementation of the cache:clear command. This may give you some clues on how to choose the environment from a command.
app/console help cache:clear

Resources