['2026-10-21T15:59:59Z', '20261021'], 'Beijing midnight' => ['2026-10-21T16:00:00Z', '20261022'], 'midnight scheduled delivery' => ['2026-10-21T16:15:00Z', '20261022'], 'morning scheduled delivery' => ['2026-10-21T22:15:00Z', '20261022'], 'noon scheduled delivery' => ['2026-10-22T04:15:00Z', '20261022'], ]; } #[DataProvider('receivingTimes')] #[RunInSeparateProcess] #[PreserveGlobalState(false)] public function testReceiverWritesAllFormatsUnderBeijingDate(string $instant, string $date): void { $previousDirectory = getcwd(); $previousTimezone = date_default_timezone_get(); $directory = sys_get_temp_dir().'/nodehub-date-test-'.bin2hex(random_bytes(6)); mkdir($directory, 0700); // Keep the real controller and filesystem, but never send Telegram in a test. $telegram = Mockery::mock('alias:App\Services\TomTool\Telegram\Slave'); $telegram->shouldReceive('log')->once()->andReturnSelf(); $telegram->shouldReceive('enableDetail')->with(false)->once()->andReturnSelf(); $telegram->shouldReceive('send')->once(); try { config(['app.timezone' => 'UTC', 'app.is_loc' => true]); date_default_timezone_set('UTC'); CarbonImmutable::setTestNow(new CarbonImmutable($instant)); chdir($directory); $raw = ['v2ray' => 'fixture-uri', 'clash' => 'fixture-clash', 'singbox' => 'fixture-singbox']; $request = Request::create('/api/freenode/file/put', 'POST', ['site_code_short' => 'cfn', 'raw' => $raw]); $response = (new FreenodeController())->filePut($request); self::assertTrue($response->getData(true)['isDone']); $token = substr(hash_hmac('sha256', $date.'nodes', 'wocaonide'), 0, 16); foreach ($raw as $format => $content) { $extension = $format === 'clash' ? '.yaml' : '.txt'; self::assertSame($content, file_get_contents($directory.'/cfn/'.$token.'/'.$date.'-'.$format.$extension)); } self::assertCount(3, glob($directory.'/cfn/*/*')); self::assertSame('UTC', date_default_timezone_get()); self::assertSame('UTC', config('app.timezone')); } finally { CarbonImmutable::setTestNow(); date_default_timezone_set($previousTimezone); chdir($previousDirectory); $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST); foreach ($files as $file) { $file->isDir() ? rmdir($file->getPathname()) : unlink($file->getPathname()); } rmdir($directory); Mockery::close(); } } }