Using SQLite for unit testing a mysql migrations setup - mysql

I want to use SQLite for PHPunit tests. We are using the mysql driver, so we have created our migrations based on that... meaning we are using nullables for default values. MYSQL doesn't care about this. SQLite, apparently, does.
Migrations:
Schema::table('users', function ($table) {
$table->string('username', 132)->nullable();
TestCase snippet: configuring phpunit environment
$app['config']->set('database.connections.testbench', [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => ''
]
Running phpunit outputs:
Cannot add a NOT NULL column with default value NULL
I noticed there was a "STRICT" mode for mysql in the database.php configuration file that you can set to false which handles invalid or missing data types:
'mysql' => [
'driver' => 'mysql',
...
'strict' => false,
],
So I started looking for a strict mode for SQLite and found Strict Mode here, tried setting PRAGMA strict=ON; to off
$app['config']->set('database.connections.testbench', [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
'strict' => false
]
But this did not fix it.
Is there a way to set SQLite to ignore nullable() values set in migrations (aimed at mysql configurations) so I can run my unit tests quickly with SQLite in memory?
My alternatives are:
remove all nullable() options for migrations and add defaults, which will take forever
use mysql instead of sqlite, which will be much slower

Related

Use of undefined constant SIGKILL - assumed 'SIGKILL' in Laravel 5.7 queue

I'm getting this error "Use of undefined constant SIGKILL - assumed 'SIGKILL'" from my AJAX request, that starts this artisan command ->
Artisan::call('queue:work', [
'connection' => 'database',
'--memory' => '700',
'--tries' => '1',
'--timeout' => '35000',
'--queue' => 'updates'
]);
I'm using Laravel 5.7 as framework for application.
Jobs are managed from database, configuration ->
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 18000,
],
Problem appeared recently.. That is weird, because troubles wasn't here before and all this "system" worked just fine. Now worker get some jobs done just fine, but then it drops to error, and writes to table "failed_jobs" in DB this ->
ErrorException: PDOStatement::execute(): MySQL server has gone away in /srv/migration-xxxxxx-xxxx-xxxxxx/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458
As DB I'm using Microsoft Azure MySQL DB. Microsoft specialist after consultation find nothing .. server is working correctly. Queries are just fine, not that big to fail.
Please help, don't know what to do, or what is wrong...

Laravel ignoring multiple database config

(Never write software when you are very tired. Otherwise you ask very nice people on the internet to answer very obvious questions, that you would not ask, if you were not tired, because the principle problem is ... trivial. lol. So, in this case, I had neglected to uniquely rename the connection properties of the alternate database. Sigh....)
PROBLEM:
I can't make Laravel recognize a request for a different connection (database).
As far as I know, I've correctly configured .ENV, config/database.php, config/app.php correctly, and added $connection=myconnection to my models.
But no matter what I do Laravel/Eloquent/Doctrine Ignores all attempts to have some models use the default (common) database, and others use the multi-tenant databases.
Let's distinguish between a physical server, a database server instance running on that server, and a database within that instance, and multi-tenancy within that database.
I should be able to use any of these configurations by modifying the connection at runtime:
Single app/db server, single app, single database, with multi-tenants
Single app/db server, single app, multiple databases, with multi-tenants
Single app/db server, single app, multiple database instances, each with multiple databases, with multi-tenants
Single app server, multiple database servers, multiple databases instances, each with multi-tennants.
Multiple app servers, multiple database servers, multiple databases instances, each with multi-tennants.
And any combination thereof.
And I suspect that the lack of documentation, yet the inclusion of the eloquent/model feature "$connection=connection_configuration" means there is a fairly obvious solution that I don't intuit. (and I don't have a few free days to delve into the source and figure out what's going on there.)
Thanks for any help.
-Cheers
===ENV FILE===
DB_CONNECTION=crunch
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crunch
DB_USERNAME=myapp
DB_PASSWORD=Nonsense!Talk
DB_CONNECTION=munchdata
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=munchdata
DB_USERNAME=myapp
DB_PASSWORD=Nonsense!Talk
===CONFIG/DATABASE.PHP===
'connections' => [
'crunch' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'crunch'),
'username' => env('DB_USERNAME', 'crunch'),
'password' => env('DB_PASSWORD', 'Nonsense!Talk'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'sticky' => true,
],
'munchdata' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'munchdata'),
'username' => env('DB_USERNAME', 'munchdata'),
'password' => env('DB_PASSWORD', 'Nonsense!Talk'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'sticky' => true,
],
],
===CONFIG/APP.PHP FILE===
'default' => env('DB_CONNECTION', 'crunch'),
// Default connections work fine
===A MODEL===
class EntityType extends BaseModel
{
use SoftDeletes;
public $connection = 'munchdata';
public $table = 'entity_type';
( ... )
}
// Ignores $connection
===CONSOLE===
>>> DB::connection('crunch')->getDatabaseName()
=> "crunch"
// Uses default connection
>>> DB::connection('munchdata')->getDatabaseName()
=> "crunch"
>>>
// Ignores connection
$result = DB::connection('munchdata')->select('select * from entity_type');
// Ignores the connection, and returns data from default db
$result = DB::connection('munchdata')->select('select munchdata.entity_type.* from munchdata.entity_type');
// Ignores the connection, but returns the right data anyway....
The values in the .ENV file must be unique, because the value "DB_CONNECTION=myDatabaseName" is not an array keyed from "myDatabaseName", but a 'dumb' string value. Meaning all entries in .ENV files must be uniquely named.
In other words, the .ENV files work OPPOSITELY from the Config/App > Connection[] definitions. Which... doesn't make a lot of sense, and isn't necessary.
I'd assumed that .ENV file was brought into an array with myDatabaseName as the key, and that the "DB_*" strings were constants. This seems logical.
This is probably how it SHOULD work, but it is not how it DOES work.
I suppose that since I've seen many other people post questions because of similar suppositions, that either we should request the change, or that I should write a bit of code to allow for multiple configs using the same constants as keys.
SOLUTION:
(1) If you have a small number of relatively invariant databases, continue to use the .ENV file - and give each CONSTANT a different name.
(2) If you dynamically create new databases, use .ENV for your default (boot) database, and then:
Either (a) Use your default (boot) database to store the related database connection configurations and cache them - which exposes your connection data and forces you to replicate that data for new instances,
Or (b) Use the file system to store the related database configurations, and (c) cache them.
In my case I have N (a lot) of databases, and I prefer using the db and then replication (dump and load the table with connection info) rather than a file of unknown size with the chance of 'leaking' into the real world due to dev/IT error or malice...
Cheers

Laravel 5 Testing Database MySQL

In Laravel 4, I could specify the testing database through the config/testing/database file.
This file has, of course, been removed from Laravel 5 just to make things pointlessly more difficult.
So, how do I set up a MySQL test database in Laravel 5.
I do not want to use a SQLite database.
I would suggest some code but there isn't anything on SO or through Google that even attempts to answer this question.
Thank you.
If you check out the documentation Testing - Test Environment this mentions you set environment variables in the phpunit.xml
So for example you would add
<phpunit>
<php>
<env name="DB_CONNECTION" value="sqlite"/>
</php>
</phpunit>
to set the DB_CONNECTION I know you said you don't want to use SQLite but this is just an example you can set any of the values you would normally set in your .env file.
See Using Environment Variables to Add Flexibility to PHPUnit Tests for some more details on the use of environmental variables with PHPUnit.
You could go with the following approach:
Set your default databse connection to 'testing' when the app environment is also 'testing' in your database.php file:
'default' => app()->environment() == "testing" ?
env('DB_CONNECTION_TESTING', 'testing') :
env('DB_CONNECTION', 'mysql'),
Then also in your database.php file add the testing connection:
'testing' => [
'driver' => 'mysql',
'host' => env('DB_HOST_TESTING', 'localhost'),
'database' => env('DB_DATABASE_TESTING', 'forge'),
'username' => env('DB_USERNAME_TESTING', 'forge'),
'password' => env('DB_PASSWORD_TESTING', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
In your .env file you have to add the corresponding lines:
DB_HOST_TESTING=localhost
DB_DATABASE_TESTING=database_testing
DB_USERNAME_TESTING=username_testing
DB_PASSWORD_TESTING=password_testing
So every time the app environment is testing ( which is the case in phpunit tests for example ) your application uses the testing database connection.
Of course you could also modify the phpunit.xml file like mentioned in the answer of Mark Davidson.

CakePHP connections while testing

i am currently trying to unit test some of my code. I am executing some manually entered SQL statements like this:
$db = ConnectionManager::get('default');
...
$stmt = $db->prepare($sql);
$stmt->execute();
I assumed that whenever I run unit tests and request the default connection I will get the test connection instead. If it is not defined in my config it will throw an exception.
When I run a test which executes a statement against the database it is always executed against the default connection. The test connection is never used.
Any idea what I am doing wrong?
My database config is as follows:
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'dbname',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
/**
* The test connection is used during the test suite.
*/
'test' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'dbname_test',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
]
Thanks for any help!
Edit
I think the documentation is wrong:
By default CakePHP will alias each connection in your application. Each connection defined in your application’s bootstrap that does not start with test_ will have a test_ prefixed alias created. Aliasing connections ensures, you don’t accidentally use the wrong connection in test cases. Connection aliasing is transparent to the rest of your application. For example if you use the ‘default’ connection, instead you will get the test connection in test cases. If you use the ‘replica’ connection, the test suite will attempt to use ‘test_replica’.
Link
You can read there that CakePHP is aliasing the default connection automatically to test when running unit tests. To get that behaviour you have to define that alias yourself in your phpunit bootstrap.php like so:
\Cake\Datasource\ConnectionManager::alias('test', 'default');
You can read about that here ConnectionManager::alias The funny thing is that the documentation for alias explicitly states
For example, if you alias 'default' to 'test', fetching 'default' will always return the 'test' connection as long as the alias is defined.
We also had the same error, for some tables tests were getting default db instead of test db for no reason. In the end using code at the top of the setUp function (before parent::setUp()) solved the problem (we have a main test class from which we extend all tests, do some setting up. We put it there)
TableRegistry::clear();
The connection aliasing is done by default when you load the fixtures manager listener in our phpunit.xml config as it is distributed in the app template:
https://github.com/cakephp/app/blob/master/phpunit.xml.dist#L23-L31

Laravel failing to connect to DB after 4.2 upgrade

I just upgraded my Laravel install from 4.1.(something) to 4.2.7 using the steps recommended here: http://laravel.com/docs/upgrade
Now I'm getting this error on every page:
PDOException (2002)
SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket '' (111)
MySQL is not running locally, but it's not supposed to be. I don't have any configuration for connecting to local MySQL, my development SQL server is remote. Why is it trying to connect to local?
Is there some config change that isn't mentioned in the upgrade guide? Everything was peachy in 4.1.
From my app/config/database.php file:
'default' => 'mysql',
...
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'myrealdb.us-east-1.rds.amazonaws.com',
'database' => 'myrealdbname',
'username' => 'myrealuser',
'password' => 'myrealpass',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'database_port' => '3306',
'unix_socket' => '',
),
...
);
I tried php artisan clear-compiled and php artisan dump-autoload just in case. No effect.
Edit: I submitted a fix for this that has been merged into the 4.2 branch. You shouldn't have to worry about this error anymore.
I got it! This appears to be a change in the way Laravel uses the database configuration, I hope this answer helps others.
The short version is: if your connection is configured like mine (in the question), delete the unix_socket entry from the array.
Previously, I always copied and edited the default entries in the connections array, leaving in the unix_socket parameter as empty. Apparently now there's a check that assumes if unix_socket is present, it should use a socket DSN string. The empty string in my config passed the check. You can see how this happens in /vendor/laravel/framework/src/Illuminate/Database/Connectors/MySqlConnector.php. The functions getDsn, getSocketDsn, and getHostDsn tell the story.
Pasted because this will eventually change:
protected function getDsn(array $config)
{
return isset($config['unix_socket']) ? $this->getSocketDsn($config) : $this->getHostDsn($config);
}
...
protected function getSocketDsn(array $config)
{
extract($config);
return "mysql:unix_socket={$config['unix_socket']};dbname={$database}";
}
...
protected function getHostDsn(array $config)
{
extract($config);
return isset($config['port'])
? "mysql:host={$host};port={$port};dbname={$database}"
: "mysql:host={$host};dbname={$database}";
}