diff --git a/src/Sushi.php b/src/Sushi.php index 097394c..8494881 100644 --- a/src/Sushi.php +++ b/src/Sushi.php @@ -100,7 +100,7 @@ protected static function configureSushiConnection() $states['no-caching-capabilities'](); break; - case file_exists($cachePath) && filemtime($dataPath) <= filemtime($cachePath): + case file_exists($cachePath) && filesize($cachePath) > 0 && filemtime($dataPath) <= filemtime($cachePath): $states['cache-file-found-and-up-to-date'](); break; @@ -116,13 +116,24 @@ protected static function configureSushiConnection() protected static function cacheFileNotFoundOrStale($cachePath, $dataPath, $instance) { - file_put_contents($cachePath, ''); + $tempPath = $cachePath.'.tmp.'.str_replace('.', '', uniqid('', true)); - static::setSqliteConnection($cachePath); + try { + file_put_contents($tempPath, ''); + + static::setSqliteConnection($tempPath); + + $instance->migrate(); - $instance->migrate(); + touch($tempPath, filemtime($dataPath)); + rename($tempPath, $cachePath); - touch($cachePath, filemtime($dataPath)); + static::setSqliteConnection($cachePath); + } finally { + if (file_exists($tempPath)) { + @unlink($tempPath); + } + } } protected function newRelatedInstance($class) diff --git a/tests/SushiTest.php b/tests/SushiTest.php index 3ee6d9b..3fa1665 100644 --- a/tests/SushiTest.php +++ b/tests/SushiTest.php @@ -106,6 +106,20 @@ function test_caches_sqlite_file_if_storage_cache_folder_is_available() ); } + function test_rebuilds_empty_cache_file_even_when_its_timestamp_is_fresh() + { + $cachePath = $this->cachePath.'/sushi-tests-foo.sqlite'; + $referencePath = (new \ReflectionClass(Foo::class))->getFileName(); + + file_put_contents($cachePath, ''); + touch($cachePath, filemtime($referencePath) + 10); + + Foo::resetStatics(); + + $this->assertEquals(3, Foo::count()); + $this->assertGreaterThan(0, filesize($cachePath)); + } + function test_avoids_error_when_creating_database_concurrently() { $actualFactory = app(ConnectionFactory::class); @@ -115,15 +129,17 @@ function test_avoids_error_when_creating_database_concurrently() ]); $connectionFactory = $this->createMock(ConnectionFactory::class); - $connectionFactory->expects($this->once()) + $connectionFactory->expects($this->atLeastOnce()) ->method('make') ->willReturnCallback(function () use ($actualConnection) { // Simulate a concurrent request that creates the table at a point in time // where our main execution has already determined that it does not exist // and is about to create it. - $actualConnection->getSchemaBuilder()->create('blanks', function ($table) { - $table->increments('id'); - }); + if (! $actualConnection->getSchemaBuilder()->hasTable('blanks')) { + $actualConnection->getSchemaBuilder()->create('blanks', function ($table) { + $table->increments('id'); + }); + } return $actualConnection; });