Skip to content

PouyaPour/laravel-refreshdatabase-sqlite-bug

Repository files navigation

Laravel RefreshDatabase SQLite In-Memory Bug Reproduction

Reproduction repository for: laravel/framework#57716

The Bug

When using RefreshDatabase trait with SQLite in-memory database, tests fail with "no such table" errors after a test that performs a transaction rollback.

Quick Start

composer install
cp .env.example .env
php artisan key:generate
php artisan test

Expected vs Actual Results

Expected: All 6 tests pass ✅

Actual (without the fix):

✓ Test 1: before exception - PASSES
✓ Test 2: before exception 2 - PASSES  
✓ Test 3: throws exception and breaks connection - PASSES
✓ Test 4: first after exception - PASSES
✗ Test 5: second after exception - FAILS ❌
✗ Test 6: third after exception - FAILS ❌

Error message:

SQLSTATE[HY000]: General error: 1 no such table: users

Why Test 4 Passes But Tests 5-6 Fail

This is the key to understanding the bug:

Test Execution Flow:

Test 3:

  • Performs DB::rollBack()
  • Connection exits transaction state
  • Sets RefreshDatabaseState::$migrated = false

Test 4:

  • Calls refreshTestDatabase()
  • Since $migrated = false, runs migrateDatabases()
  • Creates NEW PDO connection with fresh tables
  • ✅ Test passes using this new connection
  • Next tests, beginDatabaseTransaction() calls restoreInMemoryDatabase():
protected function restoreInMemoryDatabase()
{
    foreach ($this->connectionsToTransact() as $name) {
        if (isset(RefreshDatabaseState::$inMemoryConnections[$name])) {
            // ⚠️ This overwrites the NEW PDO with the OLD stale PDO!
            $database->connection($name)->setPdo(
                RefreshDatabaseState::$inMemoryConnections[$name]
            );
        }
    }
}

Tests 5-6:

  • Now using the OLD PDO (restored by restoreInMemoryDatabase())
  • Old PDO doesn't have any tables
  • ❌ Tests fail with "no such table: users"

Root Cause

The problem occurs in this sequence:

  1. Test 3 performs rollback → connection not in transaction
  2. beginDatabaseTransaction() detects this and sets RefreshDatabaseState::$migrated = false
  3. Test 4 triggers re-migration, creating a NEW PDO with tables
  4. Test 4 passes ✅
  5. restoreInMemoryDatabase() overwrites the new PDO with the old stale PDO from RefreshDatabaseState::$inMemoryConnections
  6. Tests 5+ fail because they're using the old PDO without tables ❌

The core issue: RefreshDatabaseState::$inMemoryConnections is never updated after re-migration, so restoreInMemoryDatabase() keeps restoring the wrong (stale) PDO instance.

The Fix

The PR adds a call to updateInMemoryConnections() after migrateDatabases():

protected function refreshTestDatabase()
{
    if (! RefreshDatabaseState::$migrated) {
        $this->migrateDatabases();
        $this->app[Kernel::class]->setArtisan(null);
        
        // 🔧 Update the cached PDO references with new connections
        $this->updateInMemoryConnections();
        
        RefreshDatabaseState::$migrated = true;
    }

    $this->beginDatabaseTransaction();
}

protected function updateInMemoryConnections()
{
    $database = $this->app->make('db');

    foreach ($this->connectionsToTransact() as $name) {
        if ($this->usingInMemoryDatabase($name)) {
            $connection = $database->connection($name);
            // Update cache with current PDO reference
            RefreshDatabaseState::$inMemoryConnections[$name] = $connection->getPdo();
        }
    }
}

This ensures that after re-migration, the cached PDO references point to the new connections with migrated tables, so restoreInMemoryDatabase() restores the correct connection.

Configuration

This reproduction uses SQLite in-memory database configured in config/database.php:

'sqlite' => [
    'driver' => 'sqlite',
    'database' => ':memory:',
],

Or in .env:

DB_CONNECTION=sqlite
DB_DATABASE=:memory:

Files Structure

  • app/Services/TestService.php - Service that simulates transaction rollback
  • tests/Feature/TestServiceTest.php - Test suite that reproduces the bug
  • database/migrations/ - Standard Laravel user migration

Related Laravel Code

The bug exists in these Laravel framework files:

  • Illuminate\Foundation\Testing\RefreshDatabase
  • Illuminate\Foundation\Testing\RefreshDatabaseState

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages