1
0

ConsoleTest.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. declare(strict_types=1);
  3. namespace Luolongfei\Tests\App;
  4. use GuzzleHttp\Cookie\CookieJar;
  5. use Luolongfei\App\Console\Base;
  6. use Luolongfei\App\Console\Cron;
  7. use Luolongfei\App\Console\FreeNom;
  8. use Luolongfei\App\Console\GlobalValue;
  9. use Luolongfei\App\Console\MigrateEnvFile;
  10. use Luolongfei\App\Console\Upgrade;
  11. use Luolongfei\App\Exceptions\LlfException;
  12. use Luolongfei\Tests\TestCase;
  13. class TestableFreeNom extends FreeNom
  14. {
  15. public array $renewResults = [];
  16. public function __construct()
  17. {
  18. }
  19. protected function renew(int $id, string $token)
  20. {
  21. return $this->renewResults[$id] ?? false;
  22. }
  23. }
  24. final class ConsoleTest extends TestCase
  25. {
  26. public function testConsoleBaseExtractsVersionNumber(): void
  27. {
  28. $base = new Base();
  29. $this->assertSame('1.2.3', $base->getVerNum('v1.2.3-beta'));
  30. $this->assertNull($base->getVerNum('invalid'));
  31. }
  32. public function testCronVerifyAcceptsAndRejectsExpressions(): void
  33. {
  34. $script = ROOT_PATH . DS . 'tests' . DS . 'fixtures' . DS . 'cron_verify_runner.php';
  35. exec(sprintf('php -d xdebug.mode=off %s --cron_exp=%s', escapeshellarg($script), escapeshellarg('* * * * *')), $output, $validCode);
  36. exec(sprintf('php -d xdebug.mode=off %s --cron_exp=%s', escapeshellarg($script), escapeshellarg('bad cron')), $output, $invalidCode);
  37. $this->assertSame(0, $validCode);
  38. $this->assertSame(1, $invalidCode);
  39. }
  40. public function testGlobalValueStoresAndRemovesEntries(): void
  41. {
  42. $globalValue = GlobalValue::getInstance();
  43. $globalValue->set('foo', 'bar');
  44. $this->assertTrue($globalValue->has('foo'));
  45. $this->assertSame('bar', $globalValue->get('foo'));
  46. $globalValue->del('foo');
  47. $this->assertFalse($globalValue->has('foo'));
  48. $this->assertNull($globalValue->get('foo'));
  49. }
  50. public function testMigrateEnvFileReadsVersionsAndUpdatesValues(): void
  51. {
  52. $dir = $this->createTempDir('migrator');
  53. file_put_contents($dir . DS . '.env', "ENV_FILE_VERSION='v1.0'\nFOO='old'\n");
  54. file_put_contents($dir . DS . '.env.example', "ENV_FILE_VERSION='v2.0'\nFOO='new'\n");
  55. $migrator = new class extends MigrateEnvFile {
  56. public string $baseDir = '';
  57. public function __construct()
  58. {
  59. }
  60. public function getEnvFilePath($filename = '.env')
  61. {
  62. return $this->baseDir . DS . $filename;
  63. }
  64. };
  65. $migrator->baseDir = $dir;
  66. $this->assertSame('1.0', $migrator->getEnvFileVer());
  67. $this->assertSame('2.0', $migrator->getEnvFileVer('.env.example'));
  68. $this->assertTrue($migrator->needToMigrate());
  69. $this->assertSame("FOO='value'", $migrator->formatEnvVal('FOO', 'value'));
  70. $this->assertTrue($migrator->setEnv('FOO', 'changed'));
  71. $this->assertStringContainsString("FOO='changed'", (string) file_get_contents($dir . DS . '.env'));
  72. }
  73. public function testUpgradeHelpersWorkWithInjectedReleaseInfo(): void
  74. {
  75. $dir = $this->createTempDir('upgrade');
  76. $upgrade = new class extends Upgrade {
  77. public function __construct()
  78. {
  79. }
  80. };
  81. $this->setProperty($upgrade, 'pushedVerFile', $dir . DS . 'pushed_version.txt');
  82. $this->setProperty($upgrade, 'releaseInfo', [
  83. 'published_at' => '2026-03-10T00:00:00Z',
  84. 'body' => "Bug fixes\n",
  85. 'html_url' => 'https://github.com/luolongfei/freenom/releases/tag/v9.9.9',
  86. ]);
  87. $this->setProperty($upgrade, 'latestVer', '9.9.9');
  88. $this->setProperty($upgrade, 'currVer', '0.6.2');
  89. $this->assertFalse($upgrade->isPushed('9.9.9'));
  90. $this->assertTrue($upgrade->rememberVer('9.9.9'));
  91. $this->assertTrue($upgrade->isPushed('9.9.9'));
  92. $this->assertStringContainsString('9.9.9', $upgrade->genMsgContent());
  93. $this->assertStringContainsString('2026-03-10', $upgrade->friendlyDateFormat('2026-03-10T00:00:00Z', 'UTC'));
  94. }
  95. public function testUpgradeDeclaresHttpClientProperty(): void
  96. {
  97. $this->assertTrue((new \ReflectionClass(Upgrade::class))->hasProperty('client'));
  98. }
  99. public function testFreeNomParsesAccountsDomainsAndToken(): void
  100. {
  101. $this->loadFixtureEnv([
  102. 'MULTIPLE_ACCOUNTS' => '<[email protected]>@<first-pass>|<[email protected]>@<second-pass>',
  103. ]);
  104. $freeNom = new TestableFreeNom();
  105. $accounts = $this->invokeMethod($freeNom, 'getAccounts');
  106. $this->assertCount(3, $accounts);
  107. $page = <<<'HTML'
  108. <input type="hidden" name="token" value="abc123" />
  109. <table>
  110. <tr><td>alpha.tk</td><td>Active</td><td>Expires <span class="text-danger">5 days left</span></td><td><a href="domains.php?a=renewdomain&domain=1">Renew</a></td></tr>
  111. <tr><td>beta.ml</td><td>Active</td><td>Expires <span class="text-success">20 days left</span></td><td><a href="domains.php?a=renewdomain&domain=2">Renew</a></td></tr>
  112. </table>
  113. HTML;
  114. $domains = $this->invokeMethod($freeNom, 'getAllDomains', [$page]);
  115. $this->assertCount(2, $domains);
  116. $this->assertSame('abc123', $this->invokeMethod($freeNom, 'getToken', [$page]));
  117. }
  118. public function testFreeNomLoginFailsGracefullyWhenSessionCookieMissing(): void
  119. {
  120. $freeNom = new TestableFreeNom();
  121. $client = new class {
  122. public function post(string $url, array $options)
  123. {
  124. return null;
  125. }
  126. };
  127. $this->setProperty($freeNom, 'client', $client);
  128. $this->setProperty($freeNom, 'jar', new CookieJar());
  129. $this->setProperty($freeNom, 'maxRequestRetryCount', 0);
  130. $this->expectException(LlfException::class);
  131. $this->expectExceptionMessage('(Error code: 34520002)');
  132. $this->invokeMethod($freeNom, 'login', ['[email protected]', 'secret']);
  133. }
  134. public function testFreeNomArrayUniqueAndRenewAllDomains(): void
  135. {
  136. $freeNom = new TestableFreeNom();
  137. $freeNom->renewResults = [1 => true, 2 => false];
  138. $this->setProperty($freeNom, 'username', '[email protected]');
  139. $accounts = [
  140. ['username' => 'a', 'password' => '1'],
  141. ['password' => '1', 'username' => 'a'],
  142. ['username' => 'b', 'password' => '2'],
  143. ];
  144. $this->assertTrue($freeNom->arrayUnique($accounts, ['username', 'password']));
  145. $this->assertCount(2, $accounts);
  146. $domains = [
  147. ['domain' => 'alpha.tk', 'days' => '5', 'id' => 1],
  148. ['domain' => 'beta.ml', 'days' => '10', 'id' => 2],
  149. ['domain' => 'gamma.ga', 'days' => '30', 'id' => 3],
  150. ];
  151. $this->assertTrue($freeNom->renewAllDomains($domains, 'token'));
  152. }
  153. }