laravel / dusk

Laravel Dusk provides simple end-to-end testing and browser automation.
https://laravel.com/docs/dusk
MIT License
1.88k stars 323 forks source link

Dusk 2/Laravel 5.5 with sqlite foreign keys enabled #358

Closed ohnotnow closed 6 years ago

ohnotnow commented 7 years ago

Hi,

Slightly edge-case setup I guess. But when using DatabaseMigrations with sqlite and enforcing foreign key constraints, dusk fails with a rather confusing error about the database being readonly. Plain phpunit still runs ok. L5.4/Dusk1.x ran ok with this setup too.

Clean L5.5 install, install/publish dusk as per. Database set to sqlite. Artisan make:auth just so there's something to migrate. Running dusk at this point works ok. But if you enable sqlite's foreign key constrains by adding the code below (as has been regular working practice until now) to your AppServiceProvider then you get the 'readonly' error.

if (DB::connection() instanceof \Illuminate\Database\SQLiteConnection) {
    DB::statement(DB::raw('PRAGMA foreign_keys=1'));
}

results in:


1) Tests\Browser\ExampleTest::testBasicExample
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database (SQL: create table "users" ("id" integer not null primary key autoincrement, "name" varchar not null, "email" varchar not null, "password" varchar not null, "remember_token" varchar null, "created_at" datetime null, "updated_at" datetime null))

/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:624
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:459
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Blueprint.php:86
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php:252
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php:165
/dusk-test/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:221
/dusk-test/database/migrations/2014_10_12_000000_create_users_table.php:23
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:359
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:365
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:177
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:146
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:95
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php:69
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:180
/dusk-test/vendor/symfony/console/Command/Command.php:264
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:167
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:195
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/FreshCommand.php:45
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:180
/dusk-test/vendor/symfony/console/Command/Command.php:264
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:167
/dusk-test/vendor/symfony/console/Application.php:888
/dusk-test/vendor/symfony/console/Application.php:224
/dusk-test/vendor/symfony/console/Application.php:125
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Application.php:88
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Application.php:177
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:249
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php:18
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/DatabaseMigrations.php:16
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:108
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:71
/dusk-test/vendor/laravel/dusk/src/TestCase.php:40

Caused by
PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database

/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:657
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:624
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Connection.php:459
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Blueprint.php:86
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php:252
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Schema/Builder.php:165
/dusk-test/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:221
/dusk-test/database/migrations/2014_10_12_000000_create_users_table.php:23
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:359
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:365
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:177
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:146
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php:95
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/MigrateCommand.php:69
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:180
/dusk-test/vendor/symfony/console/Command/Command.php:264
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:167
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:195
/dusk-test/vendor/laravel/framework/src/Illuminate/Database/Console/Migrations/FreshCommand.php:45
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:29

/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:87
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:31
/dusk-test/vendor/laravel/framework/src/Illuminate/Container/Container.php:549
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:180
/dusk-test/vendor/symfony/console/Command/Command.php:264
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Command.php:167
/dusk-test/vendor/symfony/console/Application.php:888
/dusk-test/vendor/symfony/console/Application.php:224
/dusk-test/vendor/symfony/console/Application.php:125
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Application.php:88
/dusk-test/vendor/laravel/framework/src/Illuminate/Console/Application.php:177
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:249
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php:18
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/DatabaseMigrations.php:16
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:108
/dusk-test/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:71
/dusk-test/vendor/laravel/dusk/src/TestCase.php:40

I can work around it by checking for the app environment rather than purely checking for sqlite - but it's less than ideal as I'm sure it'll bite me at some point.

if ($this->app->environment('testing')) {
    DB::statement(DB::raw('PRAGMA foreign_keys=1'));
}

Anyway - it's maybe not a very common setup, but it caught me out.

deleugpn commented 7 years ago

I'm not sure but to me it looks like a deadlock state.

Process 1: php artisan dusk. Runs AppServiceProvider and sets the file to enforce Foreign Key. This locks the file to ensure every database activity gets properly analyzed before committing to the sqlite file. Process 2: Browser. The browser will hit AppServiceProvider in a separate process in parallel with the previous process and try to lock the file again. Because the previous process didn't finish yet (Browser is child of Process 1), the file is locked.

Since SQLite is a simplistic single-file database, the second process just assumes that the file is not writable because the first process locked it.


Again, I'm not sure but I think when you check for environment variable, Process 1 (php artisan dusk) might not be set to run as testing, which means the database never gets changed by Process 1, which might be fine if you ensure every seed/factory that you do before running your Browser Test respects foreign keys without database enforcement.

ohnotnow commented 7 years ago

@deleugpn yeah - the APP_ENV for phpunit and dusk are set to testing/local respectively so they can do their thing. I'm in the lucky spot where the dusk tests for the app I originally spotted this in are really just a basic 'happy path' walkthrough of the site + javascript popups and the like - not really the 'meat' of the app - otherwise it would probably fail when onDelete()'s weren't happening.

I'm just not sure why it worked in L5.4/dusk1.x if it's a deadlock as it worked much the same way. But I'm not sure if it's a framework thing, a dusk thing, or some other underlying component. It's even faintly possible if dusk2 is running a bit faster I'm just hitting a lock that I was just missing before.

bbashy commented 7 years ago

I'm getting the same issue after upgrading. Multiple apps as well.

https://laracasts.com/discuss/channels/testing/after-upgrading-to-55-phpunit-fails-with-sqlite

acacha commented 7 years ago

Same problem here! If you need a project/case to test the error please contact me.

deleugpn commented 7 years ago

If anybody can create a clean installation that is capable of replicating the problem and posting the repository here, I'll take a look.

acacha commented 7 years ago

@deleugpn please see: https://github.com/acacha/duskSqliteErrorReadOnly

A project recently created (fresh Laravel installation I only added to simple models an migrations with a foregin key relation bettween the tables).

If you run:

php artisan migrate --database=sqlite_testing

It works but:

php artisan dusk

Give the readonly error!

DerJacques commented 7 years ago

We're experiencing the same problem. In our case we don't enable foreign keys, but simply run \Schema::hasTable('settings') in one of our Service Providers. This also locks the database.

Jono20201 commented 7 years ago

Also experiencing, but I have no idea why at this point.

acacha commented 7 years ago

@deleugpn ping or maybe someone else could check https://github.com/acacha/duskSqliteErrorReadOnly

driesvints commented 6 years ago

Closing this issue because it's already solved, old or not relevant anymore. Feel free to reply if you're still experiencing this issue.

hekin1 commented 5 years ago

I have this same issue on L5.7. The tests fail on my machine but strangely everything runs ok on bitbucket pipeline. Did not manage to locate the difference in environments.

staudenmeir commented 5 years ago

@hekin1 Please provide a minimal application to reproduce the issue.

hekin1 commented 5 years ago

Experimented a bit more, and now I nailed it down to this: