PruneCommandTest.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace Illuminate\Tests\Database;
  3. use Illuminate\Container\Container;
  4. use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
  5. use Illuminate\Database\Capsule\Manager as DB;
  6. use Illuminate\Database\Console\PruneCommand;
  7. use Illuminate\Database\Eloquent\MassPrunable;
  8. use Illuminate\Database\Eloquent\Model;
  9. use Illuminate\Database\Eloquent\Prunable;
  10. use Illuminate\Database\Eloquent\SoftDeletes;
  11. use Illuminate\Database\Events\ModelsPruned;
  12. use Illuminate\Events\Dispatcher;
  13. use PHPUnit\Framework\TestCase;
  14. use Symfony\Component\Console\Input\ArrayInput;
  15. use Symfony\Component\Console\Output\BufferedOutput;
  16. class PruneCommandTest extends TestCase
  17. {
  18. protected function setUp(): void
  19. {
  20. parent::setUp();
  21. Container::setInstance($container = new Container);
  22. $container->singleton(DispatcherContract::class, function () {
  23. return new Dispatcher();
  24. });
  25. $container->alias(DispatcherContract::class, 'events');
  26. }
  27. public function testPrunableModelWithPrunableRecords()
  28. {
  29. $output = $this->artisan(['--model' => PrunableTestModelWithPrunableRecords::class]);
  30. $this->assertEquals(<<<'EOF'
  31. 10 [Illuminate\Tests\Database\PrunableTestModelWithPrunableRecords] records have been pruned.
  32. 20 [Illuminate\Tests\Database\PrunableTestModelWithPrunableRecords] records have been pruned.
  33. EOF, str_replace("\r", '', $output->fetch()));
  34. }
  35. public function testPrunableTestModelWithoutPrunableRecords()
  36. {
  37. $output = $this->artisan(['--model' => PrunableTestModelWithoutPrunableRecords::class]);
  38. $this->assertEquals(<<<'EOF'
  39. No prunable [Illuminate\Tests\Database\PrunableTestModelWithoutPrunableRecords] records found.
  40. EOF, str_replace("\r", '', $output->fetch()));
  41. }
  42. public function testPrunableSoftDeletedModelWithPrunableRecords()
  43. {
  44. $db = new DB;
  45. $db->addConnection([
  46. 'driver' => 'sqlite',
  47. 'database' => ':memory:',
  48. ]);
  49. $db->bootEloquent();
  50. $db->setAsGlobal();
  51. DB::connection('default')->getSchemaBuilder()->create('prunables', function ($table) {
  52. $table->string('value')->nullable();
  53. $table->datetime('deleted_at')->nullable();
  54. });
  55. DB::connection('default')->table('prunables')->insert([
  56. ['value' => 1, 'deleted_at' => null],
  57. ['value' => 2, 'deleted_at' => '2021-12-01 00:00:00'],
  58. ['value' => 3, 'deleted_at' => null],
  59. ['value' => 4, 'deleted_at' => '2021-12-02 00:00:00'],
  60. ]);
  61. $output = $this->artisan(['--model' => PrunableTestSoftDeletedModelWithPrunableRecords::class]);
  62. $this->assertEquals(<<<'EOF'
  63. 2 [Illuminate\Tests\Database\PrunableTestSoftDeletedModelWithPrunableRecords] records have been pruned.
  64. EOF, str_replace("\r", '', $output->fetch()));
  65. $this->assertEquals(2, PrunableTestSoftDeletedModelWithPrunableRecords::withTrashed()->count());
  66. }
  67. public function testNonPrunableTest()
  68. {
  69. $output = $this->artisan(['--model' => NonPrunableTestModel::class]);
  70. $this->assertEquals(<<<'EOF'
  71. No prunable [Illuminate\Tests\Database\NonPrunableTestModel] records found.
  72. EOF, str_replace("\r", '', $output->fetch()));
  73. }
  74. public function testNonPrunableTestWithATrait()
  75. {
  76. $output = $this->artisan(['--model' => NonPrunableTrait::class]);
  77. $this->assertEquals(<<<'EOF'
  78. No prunable models found.
  79. EOF, str_replace("\r", '', $output->fetch()));
  80. }
  81. public function testTheCommandMayBePretended()
  82. {
  83. $db = new DB;
  84. $db->addConnection([
  85. 'driver' => 'sqlite',
  86. 'database' => ':memory:',
  87. ]);
  88. $db->bootEloquent();
  89. $db->setAsGlobal();
  90. DB::connection('default')->getSchemaBuilder()->create('prunables', function ($table) {
  91. $table->string('name')->nullable();
  92. $table->string('value')->nullable();
  93. });
  94. DB::connection('default')->table('prunables')->insert([
  95. ['name' => 'zain', 'value' => 1],
  96. ['name' => 'patrice', 'value' => 2],
  97. ['name' => 'amelia', 'value' => 3],
  98. ['name' => 'stuart', 'value' => 4],
  99. ['name' => 'bello', 'value' => 5],
  100. ]);
  101. $output = $this->artisan([
  102. '--model' => PrunableTestModelWithPrunableRecords::class,
  103. '--pretend' => true,
  104. ]);
  105. $this->assertEquals(<<<'EOF'
  106. 3 [Illuminate\Tests\Database\PrunableTestModelWithPrunableRecords] records will be pruned.
  107. EOF, str_replace("\r", '', $output->fetch()));
  108. $this->assertEquals(5, PrunableTestModelWithPrunableRecords::count());
  109. }
  110. public function testTheCommandMayBePretendedOnSoftDeletedModel()
  111. {
  112. $db = new DB;
  113. $db->addConnection([
  114. 'driver' => 'sqlite',
  115. 'database' => ':memory:',
  116. ]);
  117. $db->bootEloquent();
  118. $db->setAsGlobal();
  119. DB::connection('default')->getSchemaBuilder()->create('prunables', function ($table) {
  120. $table->string('value')->nullable();
  121. $table->datetime('deleted_at')->nullable();
  122. });
  123. DB::connection('default')->table('prunables')->insert([
  124. ['value' => 1, 'deleted_at' => null],
  125. ['value' => 2, 'deleted_at' => '2021-12-01 00:00:00'],
  126. ['value' => 3, 'deleted_at' => null],
  127. ['value' => 4, 'deleted_at' => '2021-12-02 00:00:00'],
  128. ]);
  129. $output = $this->artisan([
  130. '--model' => PrunableTestSoftDeletedModelWithPrunableRecords::class,
  131. '--pretend' => true,
  132. ]);
  133. $this->assertEquals(<<<'EOF'
  134. 2 [Illuminate\Tests\Database\PrunableTestSoftDeletedModelWithPrunableRecords] records will be pruned.
  135. EOF, str_replace("\r", '', $output->fetch()));
  136. $this->assertEquals(4, PrunableTestSoftDeletedModelWithPrunableRecords::withTrashed()->count());
  137. }
  138. protected function artisan($arguments)
  139. {
  140. $input = new ArrayInput($arguments);
  141. $output = new BufferedOutput;
  142. tap(new PruneCommand())
  143. ->setLaravel(Container::getInstance())
  144. ->run($input, $output);
  145. return $output;
  146. }
  147. public function tearDown(): void
  148. {
  149. parent::tearDown();
  150. Container::setInstance(null);
  151. }
  152. }
  153. class PrunableTestModelWithPrunableRecords extends Model
  154. {
  155. use MassPrunable;
  156. protected $table = 'prunables';
  157. protected $connection = 'default';
  158. public function pruneAll()
  159. {
  160. event(new ModelsPruned(static::class, 10));
  161. event(new ModelsPruned(static::class, 20));
  162. return 20;
  163. }
  164. public function prunable()
  165. {
  166. return static::where('value', '>=', 3);
  167. }
  168. }
  169. class PrunableTestSoftDeletedModelWithPrunableRecords extends Model
  170. {
  171. use MassPrunable, SoftDeletes;
  172. protected $table = 'prunables';
  173. protected $connection = 'default';
  174. public function prunable()
  175. {
  176. return static::where('value', '>=', 3);
  177. }
  178. }
  179. class PrunableTestModelWithoutPrunableRecords extends Model
  180. {
  181. use Prunable;
  182. public function pruneAll()
  183. {
  184. return 0;
  185. }
  186. }
  187. class NonPrunableTestModel extends Model
  188. {
  189. // ..
  190. }
  191. trait NonPrunableTrait
  192. {
  193. use Prunable;
  194. }