feat: add command to purge unclaimed imported doctors and their surrogates
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Doctor;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
/**
|
||||
* `app:doctors:purge` کل جدول پزشکان را پاک میکند و باید **فقط** در dev/test اجرا
|
||||
* شود. این تست قفل میکند که هیچ راه فراری برای prod نماند و اجرای بیسوییچ فقط گزارش
|
||||
* بدهد.
|
||||
*/
|
||||
class PurgeDoctorsCommandTest extends KernelTestCase
|
||||
{
|
||||
private function tester(): CommandTester
|
||||
{
|
||||
return new CommandTester(
|
||||
(new Application(self::bootKernel()))->find('app:doctors:purge')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDryRunRunsInTestEnv(): void
|
||||
{
|
||||
$tester = $this->tester();
|
||||
$tester->execute([]);
|
||||
|
||||
$tester->assertCommandIsSuccessful();
|
||||
$this->assertStringContainsString('dry-run', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testRefusesOnProdWithNoEscapeHatch(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$original = $_ENV['APP_ENV'] ?? null;
|
||||
$_ENV['APP_ENV'] = 'prod';
|
||||
|
||||
try {
|
||||
$tester = new CommandTester(
|
||||
(new Application(self::$kernel))->find('app:doctors:purge')
|
||||
);
|
||||
$tester->execute(['--force' => true]);
|
||||
|
||||
$this->assertSame(Command::FAILURE, $tester->getStatusCode());
|
||||
$this->assertStringContainsString('فقط در محیط dev', $tester->getDisplay());
|
||||
} finally {
|
||||
if ($original === null) {
|
||||
unset($_ENV['APP_ENV']);
|
||||
} else {
|
||||
$_ENV['APP_ENV'] = $original;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Doctor;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
/**
|
||||
* `app:doctors:purge-unclaimed` فقط باید پزشکانِ ایمپورتشدهٔ claimنشده و کاربران
|
||||
* جانشینشان را حذف کند. این تست دو قرارداد بحرانی را قفل میکند: --dry-run هیچچیز
|
||||
* نمینویسد، و پزشکان claimed / با منبع دیگر هرگز پاک نمیشوند.
|
||||
*/
|
||||
class PurgeUnclaimedDoctorsCommandTest extends KernelTestCase
|
||||
{
|
||||
private function tester(): CommandTester
|
||||
{
|
||||
return new CommandTester(
|
||||
(new Application(self::bootKernel()))->find('app:doctors:purge-unclaimed')
|
||||
);
|
||||
}
|
||||
|
||||
private function makeDoctor(string $source, string $ownerStatus, int $userStatus = 0): Doctor
|
||||
{
|
||||
$em = static::getContainer()->get('doctrine')->getManager();
|
||||
$mobile = ($userStatus === 0 ? 'imp_' : '09') . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
||||
|
||||
$user = new User($mobile);
|
||||
$user->setStatus($userStatus);
|
||||
$em->persist($user);
|
||||
|
||||
$doctor = new Doctor($user, 'دکتر آزمون');
|
||||
$doctor->setSource($source);
|
||||
$doctor->setOwnerStatus($ownerStatus);
|
||||
$em->persist($doctor);
|
||||
$em->flush();
|
||||
|
||||
return $doctor;
|
||||
}
|
||||
|
||||
private function doctorExists(int $id): bool
|
||||
{
|
||||
$conn = static::getContainer()->get(Connection::class);
|
||||
|
||||
return (bool) $conn->fetchOne('SELECT COUNT(*) FROM doctors WHERE id = ?', [$id]);
|
||||
}
|
||||
|
||||
public function testDryRunDeletesNothing(): void
|
||||
{
|
||||
$doctor = $this->makeDoctor('irimc', 'unclaimed');
|
||||
$id = $doctor->getId();
|
||||
|
||||
$tester = $this->tester();
|
||||
$tester->execute([]);
|
||||
$tester->assertCommandIsSuccessful();
|
||||
|
||||
$this->assertTrue($this->doctorExists($id), 'dry-run نباید پزشک را حذف کند');
|
||||
}
|
||||
|
||||
public function testForceDeletesUnclaimedImportedDoctorAndSurrogate(): void
|
||||
{
|
||||
$doctor = $this->makeDoctor('irimc', 'unclaimed');
|
||||
$id = $doctor->getId();
|
||||
$surrogateId = $doctor->getUser()->getId();
|
||||
|
||||
$tester = $this->tester();
|
||||
$tester->execute(['--force' => true]);
|
||||
$tester->assertCommandIsSuccessful();
|
||||
|
||||
$conn = static::getContainer()->get(Connection::class);
|
||||
$this->assertFalse($this->doctorExists($id), 'پزشک claimنشده باید حذف شود');
|
||||
$this->assertFalse(
|
||||
(bool) $conn->fetchOne('SELECT COUNT(*) FROM users WHERE id = ?', [$surrogateId]),
|
||||
'کاربر جانشین یتیم باید حذف شود',
|
||||
);
|
||||
}
|
||||
|
||||
public function testClaimedAndOtherSourceDoctorsSurvive(): void
|
||||
{
|
||||
$claimed = $this->makeDoctor('irimc', 'claimed', userStatus: 1);
|
||||
$manual = $this->makeDoctor('manual', 'unclaimed');
|
||||
|
||||
$this->tester()->execute(['--force' => true]);
|
||||
|
||||
$this->assertTrue($this->doctorExists($claimed->getId()), 'پزشک claimed نباید حذف شود');
|
||||
$this->assertTrue($this->doctorExists($manual->getId()), 'منبع غیر irimc نباید با پیشفرض حذف شود');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user