|
|
@@ -8,6 +8,7 @@ use App\Models\ActivityReward;
|
|
|
use App\Services\ActivityRewardService;
|
|
|
use App\Services\Sharing\ShareDefaults;
|
|
|
use App\Support\ActivityCatalog;
|
|
|
+use Carbon\Carbon;
|
|
|
use Illuminate\Config\Repository;
|
|
|
use Illuminate\Database\Capsule\Manager;
|
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
|
@@ -71,6 +72,7 @@ class ActivityCatalogTest extends TestCase
|
|
|
|
|
|
protected function tearDown(): void
|
|
|
{
|
|
|
+ Carbon::setTestNow();
|
|
|
DB::disconnect(); Facade::clearResolvedInstances(); parent::tearDown();
|
|
|
}
|
|
|
|
|
|
@@ -119,6 +121,74 @@ class ActivityCatalogTest extends TestCase
|
|
|
return DB::table('activity_rewards')->insertGetId($data);
|
|
|
}
|
|
|
|
|
|
+ public function test_expiry_updates_only_ended_published_activities_and_is_repeatable(): void
|
|
|
+ {
|
|
|
+ Carbon::setTestNow(Carbon::parse('2026-11-05 12:00:00', 'Asia/Shanghai'));
|
|
|
+ $expired = [];
|
|
|
+ foreach ([1, 2, 3, 4, 5, 6] as $type) {
|
|
|
+ $id = $this->rawActivity(['type'=>$type, 'lang'=>$type % 2 ? 'zh' : 'en']);
|
|
|
+ DB::table('activity_rewards')->where('id', $id)->update(['end_time'=>now()->timestamp - 1, 'rewarded_count'=>2, 'budget_used'=>'12.34']);
|
|
|
+ $expired[] = $id;
|
|
|
+ }
|
|
|
+ $unchanged = [];
|
|
|
+ foreach ([[1, 0], [1, 3600], [0, -1]] as [$status, $offset]) {
|
|
|
+ $id = $this->rawActivity(['status'=>$status]);
|
|
|
+ DB::table('activity_rewards')->where('id', $id)->update(['end_time'=>now()->timestamp + $offset]);
|
|
|
+ $unchanged[] = $id;
|
|
|
+ }
|
|
|
+ $before = DB::table('activity_rewards')->get()->keyBy('id');
|
|
|
+ $this->assertSame(6, ActivityRewardService::expire());
|
|
|
+ foreach ($expired as $id) {
|
|
|
+ $expected = (array)$before[$id];
|
|
|
+ $expected['status'] = 0;
|
|
|
+ $expected['updated_at'] = now()->format('Y-m-d H:i:s');
|
|
|
+ $this->assertSame($expected, (array)DB::table('activity_rewards')->where('id', $id)->first());
|
|
|
+ }
|
|
|
+ foreach ($unchanged as $id) $this->assertSame((array)$before[$id], (array)DB::table('activity_rewards')->where('id', $id)->first());
|
|
|
+ $this->assertSame(0, ActivityRewardService::expire());
|
|
|
+ Carbon::setTestNow(now()->addSecond());
|
|
|
+ $this->assertSame(1, ActivityRewardService::expire()); // The end timestamp itself is still inclusive.
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_admin_list_expires_before_status_filter_count_and_pagination(): void
|
|
|
+ {
|
|
|
+ Carbon::setTestNow(Carbon::parse('2026-11-05 12:00:00', 'Asia/Shanghai'));
|
|
|
+ $expired = [];
|
|
|
+ for ($i = 0; $i < 3; ++$i) {
|
|
|
+ $id = $this->rawActivity(['sort'=>100]);
|
|
|
+ DB::table('activity_rewards')->where('id', $id)->update(['end_time'=>now()->timestamp - 1]);
|
|
|
+ $expired[] = $id;
|
|
|
+ }
|
|
|
+ $active = [$this->rawActivity(), $this->rawActivity()];
|
|
|
+ $manual = $this->rawActivity(['status'=>0]);
|
|
|
+ $page = $this->listing(['status'=>0, 'page'=>1, 'limit'=>2]);
|
|
|
+ $this->assertSame(4, $page['total']);
|
|
|
+ $this->assertSame([$expired[2], $expired[1]], array_column($page['data'], 'id'));
|
|
|
+ $second = $this->listing(['status'=>0, 'page'=>2, 'limit'=>2]);
|
|
|
+ $this->assertSame(4, $second['total']);
|
|
|
+ $this->assertSame([$expired[0], $manual], array_column($second['data'], 'id'));
|
|
|
+ $up = $this->listing(['status'=>1]);
|
|
|
+ $this->assertSame(2, $up['total']);
|
|
|
+ $this->assertSame(array_reverse($active), array_column($up['data'], 'id'));
|
|
|
+ $this->assertSame(6, $this->listing()['total']);
|
|
|
+ $this->assertSame(0, (int)DB::table('activity_rewards')->where('id', $expired[0])->value('status'));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_scheduled_sync_expires_the_legacy_catalog_without_promotion_tables(): void
|
|
|
+ {
|
|
|
+ Carbon::setTestNow(Carbon::parse('2026-11-05 12:00:00', 'Asia/Shanghai'));
|
|
|
+ $id = $this->rawActivity();
|
|
|
+ DB::table('activity_rewards')->where('id', $id)->update(['end_time'=>now()->timestamp - 1]);
|
|
|
+ $command = new \App\Console\Commands\SyncPromotions();
|
|
|
+ $command->setLaravel($this->app);
|
|
|
+ $tester = new \Symfony\Component\Console\Tester\CommandTester($command);
|
|
|
+ $this->assertSame(0, $tester->execute([]));
|
|
|
+ $this->assertSame(0, (int)DB::table('activity_rewards')->where('id', $id)->value('status'));
|
|
|
+ $this->assertStringContainsString('到期下架:1', $tester->getDisplay());
|
|
|
+ $this->assertSame(0, $tester->execute([]));
|
|
|
+ $this->assertStringContainsString('到期下架:0', $tester->getDisplay());
|
|
|
+ }
|
|
|
+
|
|
|
public function test_dual_routes_round_trip_through_admin_save_and_listing_with_cover_and_detail(): void
|
|
|
{
|
|
|
foreach (['cover', 'detail'] as $position) {
|