count(3)->create(); $code = Artisan::call('artworks:check-user-refs', [ '--chunk' => 2, '--show-missing' => 5, ]); $output = Artisan::output(); file_put_contents(storage_path('logs/check-artwork-user-refs-test-output.log'), $output); expect($code)->toBe(0) ->and($output)->toContain('Checked 3 artworks: 3 valid, 0 missing user references, 0 null user_id values.') ->and($output)->toContain('No missing user references found in artworks.user_id.'); }); it('fails and reports orphaned artwork user references', function (): void { $validArtwork = Artwork::factory()->create(); $orphanedArtwork = Artwork::factory()->create(); DB::table('artworks') ->where('id', $orphanedArtwork->id) ->update(['user_id' => 999999]); $code = Artisan::call('artworks:check-user-refs', [ '--chunk' => 1, '--show-missing' => 5, ]); $output = Artisan::output(); expect($validArtwork->fresh())->not->toBeNull() ->and($code)->toBe(1) ->and($output)->toContain('Checked 2 artworks: 1 valid, 1 missing user references, 0 null user_id values.') ->and($output)->toContain('Found artworks with missing user references.') ->and($output)->toContain((string) $orphanedArtwork->id) ->and($output)->toContain('999999'); }); it('can copy missing referenced users from the legacy users table by the same id', function (): void { $legacyUserId = 777; $artwork = Artwork::factory()->create(); DB::table('artworks') ->where('id', $artwork->id) ->update(['user_id' => $legacyUserId]); config()->set('database.connections.legacy', config('database.connections.' . config('database.default'))); DB::purge('legacy'); Schema::connection('legacy')->dropIfExists('legacy_users'); Schema::connection('legacy')->create('legacy_users', function (Blueprint $table): void { $table->unsignedBigInteger('user_id')->primary(); $table->string('uname')->nullable(); $table->string('real_name')->nullable(); $table->string('email')->nullable(); $table->unsignedTinyInteger('active')->default(1); $table->timestamp('joinDate')->nullable(); $table->timestamp('LastVisit')->nullable(); $table->string('country')->nullable(); $table->string('country_code', 2)->nullable(); $table->string('web')->nullable(); $table->text('about_me')->nullable(); $table->text('description')->nullable(); $table->string('gender', 16)->nullable(); }); DB::connection('legacy')->table('legacy_users')->insert([ 'user_id' => $legacyUserId, 'uname' => 'legacy_artist', 'real_name' => 'Legacy Artist', 'email' => 'legacy.artist@example.test', 'active' => 1, 'joinDate' => '2020-01-02 03:04:05', 'LastVisit' => '2025-01-05 06:07:08', 'country' => 'Finland', 'country_code' => 'FI', 'web' => 'legacy.example.test', 'about_me' => 'Imported from legacy.', 'gender' => 'F', ]); $code = Artisan::call('artworks:check-user-refs', [ '--chunk' => 1, '--show-missing' => 5, '--copy-missing-from-legacy' => true, '--legacy-users-table' => 'legacy_users', ]); $output = Artisan::output(); file_put_contents(storage_path('logs/check-artwork-user-refs-copy-test-output.log'), $output); expect($code)->toBe(0) ->and(DB::table('users')->where('id', $legacyUserId)->exists())->toBeTrue() ->and(DB::table('user_profiles')->where('user_id', $legacyUserId)->value('country_code'))->toBe('FI') ->and($output)->toContain('[copied] imported legacy user #777 username=@legacy_artist name="Legacy Artist" email=') ->and($output)->toContain('Checked 1 artworks: 1 valid, 0 missing user references, 0 null user_id values.') ->and($output)->toContain('Legacy copy summary: requested 1 users, copied 1, would copy 0, conflicts 0, not found in legacy 0, errors 0.') ->and($output)->toContain('Copied or would-copy user ids: 777'); Schema::connection('legacy')->dropIfExists('legacy_users'); }); it('shows dry run copy details for legacy imports', function (): void { $legacyUserId = 778; $artwork = Artwork::factory()->create(); DB::table('artworks') ->where('id', $artwork->id) ->update(['user_id' => $legacyUserId]); config()->set('database.connections.legacy', config('database.connections.' . config('database.default'))); DB::purge('legacy'); Schema::connection('legacy')->dropIfExists('legacy_users'); Schema::connection('legacy')->create('legacy_users', function (Blueprint $table): void { $table->unsignedBigInteger('user_id')->primary(); $table->string('uname')->nullable(); $table->string('real_name')->nullable(); $table->string('email')->nullable(); $table->unsignedTinyInteger('active')->default(1); $table->timestamp('joinDate')->nullable(); $table->timestamp('LastVisit')->nullable(); $table->string('country')->nullable(); $table->string('country_code', 2)->nullable(); $table->string('web')->nullable(); $table->text('about_me')->nullable(); $table->text('description')->nullable(); $table->string('gender', 16)->nullable(); }); DB::connection('legacy')->table('legacy_users')->insert([ 'user_id' => $legacyUserId, 'uname' => 'legacy_preview', 'real_name' => 'Legacy Preview', 'email' => 'legacy.preview@example.test', 'active' => 1, ]); $code = Artisan::call('artworks:check-user-refs', [ '--chunk' => 1, '--show-missing' => 5, '--copy-missing-from-legacy' => true, '--dry-run-copy' => true, '--legacy-users-table' => 'legacy_users', ]); $output = Artisan::output(); expect($code)->toBe(1) ->and(DB::table('users')->where('id', $legacyUserId)->exists())->toBeFalse() ->and($output)->toContain('[dry-run] would import legacy user #778 username=@legacy_preview name="Legacy Preview" email=') ->and($output)->toContain('Legacy copy summary: requested 1 users, copied 0, would copy 1, conflicts 0, not found in legacy 0, errors 0.'); Schema::connection('legacy')->dropIfExists('legacy_users'); });