MessageServicesTest.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. declare(strict_types=1);
  3. namespace Luolongfei\Tests\Unit;
  4. use Luolongfei\Libs\Config;
  5. use Luolongfei\Libs\Message;
  6. use Luolongfei\Libs\MessageServices\Bark;
  7. use Luolongfei\Libs\MessageServices\Mail;
  8. use Luolongfei\Libs\MessageServices\Pushplus;
  9. use Luolongfei\Libs\MessageServices\ServerChan;
  10. use Luolongfei\Libs\MessageServices\TelegramBot;
  11. use Luolongfei\Libs\MessageServices\WeChat;
  12. use Luolongfei\Tests\Support\FakeHttpClient;
  13. use Luolongfei\Tests\TestCase;
  14. final class MessageServicesTest extends TestCase
  15. {
  16. public function testMailReturnsExpectedProviderConfiguration(): void
  17. {
  18. $this->setEnvValues([
  19. 'CUSTOM_LANGUAGE' => 'zh',
  20. 'MAIL_USERNAME' => '[email protected]',
  21. 'MAIL_PASSWORD' => 'secret',
  22. 'TO' => '[email protected]',
  23. ]);
  24. $mail = new Mail();
  25. self::assertSame(['smtp.office365.com', \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS, 587], $mail->getBasicMailConf('[email protected]'));
  26. self::assertStringContainsString('alpha.tk', $mail->genDomainsHtml(['alpha.tk']));
  27. self::assertStringContainsString('还有', $mail->genDomainStatusHtml(['alpha.tk' => 10]));
  28. }
  29. public function testBarkSendBuildsExpectedRequest(): void
  30. {
  31. $this->setEnvValues([
  32. 'CUSTOM_LANGUAGE' => 'zh',
  33. 'BARK_KEY' => 'https://api.day.app/demo-key/test',
  34. 'BARK_URL' => 'https://api.day.app',
  35. 'BARK_GROUP' => 'FreeNom',
  36. 'BARK_LEVEL' => 'active',
  37. 'BARK_ENABLE' => '1',
  38. ]);
  39. $service = new Bark();
  40. $client = new FakeHttpClient();
  41. $client->queue('post', FakeHttpClient::jsonResponse(['code' => 200]));
  42. $this->setProperty($service, 'client', $client);
  43. self::assertTrue($service->send('hello', 'subject'));
  44. self::assertSame('https://api.day.app/demo-key/', $client->requests[0]['url']);
  45. }
  46. public function testServerChanSendFormatsMarkdownBody(): void
  47. {
  48. $this->setEnvValues([
  49. 'CUSTOM_LANGUAGE' => 'zh',
  50. 'SCT_SEND_KEY' => 'send-key',
  51. ]);
  52. $service = new ServerChan();
  53. $client = new FakeHttpClient();
  54. $client->queue('post', FakeHttpClient::jsonResponse(['code' => 0]));
  55. $this->setProperty($service, 'client', $client);
  56. self::assertTrue($service->send("line1\nline2", 'subject'));
  57. self::assertStringContainsString("\n\n", $client->requests[0]['options']['form_params']['desp']);
  58. }
  59. public function testPushplusSendUsesHttpsEndpoint(): void
  60. {
  61. $this->setEnvValues([
  62. 'CUSTOM_LANGUAGE' => 'zh',
  63. 'PUSHPLUS_KEY' => 'push-token',
  64. ]);
  65. $service = new Pushplus();
  66. $client = new FakeHttpClient();
  67. $client->queue('post', FakeHttpClient::jsonResponse(['code' => 200]));
  68. $this->setProperty($service, 'client', $client);
  69. self::assertTrue($service->send('content', 'subject'));
  70. self::assertSame(Pushplus::API_URL, $client->requests[0]['url']);
  71. }
  72. public function testTelegramBotEscapesMarkdownAndPreservesLinks(): void
  73. {
  74. $this->setEnvValues([
  75. 'CUSTOM_LANGUAGE' => 'zh',
  76. 'TELEGRAM_CHAT_ID' => '100',
  77. 'TELEGRAM_BOT_TOKEN' => 'bot-token',
  78. 'CUSTOM_TELEGRAM_HOST' => 'api.telegram.org',
  79. ]);
  80. $service = new TelegramBot();
  81. $client = new FakeHttpClient();
  82. $client->queue('post', FakeHttpClient::jsonResponse(['ok' => true]));
  83. $this->setProperty($service, 'client', $client);
  84. self::assertTrue($service->send("Release:\n* item\nraw \\ slash\n[example](http://example.com/path?a=1)", 'subject'));
  85. $request = $client->requests[0];
  86. self::assertSame('MarkdownV2', $request['options']['form_params']['parse_mode']);
  87. self::assertStringContainsString('\* item', $request['options']['form_params']['text']);
  88. self::assertStringContainsString('[example](http://example.com/path?a=1)', $request['options']['form_params']['text']);
  89. }
  90. public function testWeChatSendFetchesTokenAndPostsMessage(): void
  91. {
  92. $this->setEnvValues([
  93. 'CUSTOM_LANGUAGE' => 'zh',
  94. 'WECHAT_CORP_ID' => 'corp-id',
  95. 'WECHAT_CORP_SECRET' => 'corp-secret',
  96. 'WECHAT_AGENT_ID' => '1000001',
  97. 'WECHAT_USER_ID' => '@all',
  98. ]);
  99. $service = new WeChat();
  100. $client = new FakeHttpClient();
  101. $client->queue('get', FakeHttpClient::jsonResponse([
  102. 'errcode' => 0,
  103. 'access_token' => 'access-token',
  104. 'expires_in' => 7200,
  105. ]));
  106. $client->queue('post', FakeHttpClient::jsonResponse([
  107. 'errcode' => 0,
  108. 'errmsg' => 'ok',
  109. ]));
  110. $this->setProperty($service, 'client', $client);
  111. $tempFile = tempnam(sys_get_temp_dir(), 'wechat-token-');
  112. $this->setProperty($service, 'accessTokenFile', $tempFile);
  113. try {
  114. self::assertTrue($service->send('hello', 'subject'));
  115. self::assertCount(2, $client->requests);
  116. self::assertStringContainsString('WECHAT_ACCESS_TOKEN=access-token', (string) file_get_contents($tempFile));
  117. } finally {
  118. @unlink($tempFile);
  119. }
  120. }
  121. public function testMessageDispatcherFallsThroughAfterBrokenChannel(): void
  122. {
  123. $config = $this->newInstanceWithoutConstructor(Config::class);
  124. $this->setProperty($config, 'allConfig', [
  125. 'message' => [
  126. [
  127. 'enable' => 1,
  128. 'not_enabled_tips' => false,
  129. 'class' => BrokenMessageService::class,
  130. 'name' => 'broken',
  131. ],
  132. [
  133. 'enable' => 1,
  134. 'not_enabled_tips' => false,
  135. 'class' => WorkingMessageService::class,
  136. 'name' => 'working',
  137. ],
  138. ],
  139. 'custom_language' => 'zh',
  140. ]);
  141. $this->seedBaseInstance(Config::class, $config);
  142. ob_start();
  143. try {
  144. self::assertTrue(Message::send('payload'));
  145. } finally {
  146. ob_end_clean();
  147. }
  148. self::assertSame(1, WorkingMessageService::$sendCalls);
  149. }
  150. }
  151. final class BrokenMessageService implements \Luolongfei\Libs\Connector\MessageServiceInterface
  152. {
  153. public function send(string $content, string $subject = '', int $type = 1, array $data = [], ?string $recipient = null, ...$params)
  154. {
  155. throw new \RuntimeException('boom');
  156. }
  157. }
  158. final class WorkingMessageService implements \Luolongfei\Libs\Connector\MessageServiceInterface
  159. {
  160. public static int $sendCalls = 0;
  161. public function send(string $content, string $subject = '', int $type = 1, array $data = [], ?string $recipient = null, ...$params)
  162. {
  163. self::$sendCalls++;
  164. return true;
  165. }
  166. }