diff --git a/src/Console/Command.php b/src/Console/Command.php index bd89c184..72cd5fc2 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -57,7 +57,7 @@ class Command extends AbstractCommand "add:validation" => GenerateValidationCommand::class, "add:event" => GenerateAppEventCommand::class, "add:listener" => GenerateEventListenerCommand::class, - "add:producer" => GenerateJobCommand::class, + "add:job" => GenerateJobCommand::class, "add:command" => GenerateConsoleCommand::class, "add:message" => GenerateMessagingCommand::class, "run:console" => ReplCommand::class, diff --git a/src/Console/Console.php b/src/Console/Console.php index 6104835d..3b080b75 100644 --- a/src/Console/Console.php +++ b/src/Console/Console.php @@ -72,40 +72,46 @@ class Console * @var array */ private static array $registers = []; + /** * The console instance * * @var ?Console */ private static ?Console $instance = null; + /** * The Setting instance * * @var Setting */ private Setting $setting; + /** - * The COMMAND instance + * The Command instance * * @var Command */ private Command $command; + /** * The Loader instance * * @var Loader */ private Loader $kernel; + /** - * Defines if console booted + * Define if console booted * * @var bool */ private bool $booted = false; + /** * The Argument instance * - * @return Argument + * @var Argument */ private Argument $arg; @@ -487,7 +493,7 @@ private function flush(): void private function getVersion(): void { $version = <<addFields($data); $this->applyCommonOptions(); - curl_setopt($this->ch, CURLOPT_PUT, true); + curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, "PUT"); $content = $this->execute(); @@ -235,7 +235,7 @@ public function put(string $url, array $data = []): Response } /** - * Make put requester + * Make DELETE request * * @param string $url * @param array $data @@ -256,7 +256,7 @@ public function delete(string $url, array $data = []): Response } /** - * Attach new file + * Attach file(s) to the request * * @param string|array $attach * @return HttpClient @@ -269,7 +269,7 @@ public function addAttach(string|array $attach): HttpClient } /** - * Set the user agent + * Set the User-Agent header * * @param string $user_agent * @return HttpClient @@ -282,7 +282,7 @@ public function setUserAgent(string $user_agent): HttpClient } /** - * Set the json accept prop to format the sent content in json + * Configure client to accept and send JSON data * * @return HttpClient */ @@ -296,7 +296,7 @@ public function acceptJson(): HttpClient } /** - * Add additional header + * Add custom HTTP headers * * @param array $headers * @return HttpClient diff --git a/src/Messaging/CanSendMessage.php b/src/Messaging/CanSendMessage.php index 94fca638..7a26512d 100644 --- a/src/Messaging/CanSendMessage.php +++ b/src/Messaging/CanSendMessage.php @@ -23,7 +23,7 @@ public function sendMessage(Messaging $message): void */ public function setMessageQueue(Messaging $message): void { - $producer = new MessagingQueueProducer($this, $message); + $producer = new MessagingQueueJob($this, $message); queue($producer); } @@ -37,7 +37,7 @@ public function setMessageQueue(Messaging $message): void */ public function sendMessageQueueOn(string $queue, Messaging $message): void { - $producer = new MessagingQueueProducer($this, $message); + $producer = new MessagingQueueJob($this, $message); $producer->setQueue($queue); @@ -53,7 +53,7 @@ public function sendMessageQueueOn(string $queue, Messaging $message): void */ public function sendMessageLater(int $delay, Messaging $message): void { - $producer = new MessagingQueueProducer($this, $message); + $producer = new MessagingQueueJob($this, $message); $producer->setDelay($delay); @@ -70,7 +70,7 @@ public function sendMessageLater(int $delay, Messaging $message): void */ public function sendMessageLaterOn(int $delay, string $queue, Messaging $message): void { - $producer = new MessagingQueueProducer($this, $message); + $producer = new MessagingQueueJob($this, $message); $producer->setQueue($queue); $producer->setDelay($delay); diff --git a/src/Messaging/MessagingQueueProducer.php b/src/Messaging/MessagingQueueJob.php similarity index 91% rename from src/Messaging/MessagingQueueProducer.php rename to src/Messaging/MessagingQueueJob.php index 91079c02..6d398737 100644 --- a/src/Messaging/MessagingQueueProducer.php +++ b/src/Messaging/MessagingQueueJob.php @@ -6,7 +6,7 @@ use Bow\Queue\QueueJob; use Throwable; -class MessagingQueueProducer extends QueueJob +class MessagingQueueJob extends QueueJob { /** * The message bag @@ -16,7 +16,7 @@ class MessagingQueueProducer extends QueueJob private array $bags = []; /** - * MessagingQueueProducer constructor + * MessagingQueueJob constructor * * @param Model $context * @param Messaging $message diff --git a/tests/Messaging/MessagingTest.php b/tests/Messaging/MessagingTest.php index 840636b5..aecb11ec 100644 --- a/tests/Messaging/MessagingTest.php +++ b/tests/Messaging/MessagingTest.php @@ -4,8 +4,10 @@ use Bow\View\View; use Bow\Mail\Envelop; +use Bow\Messaging\Messaging; use Bow\Database\Database; use Bow\Database\Barry\Model; +use Bow\Mail\Mail; use PHPUnit\Framework\TestCase; use Bow\Tests\Config\TestingConfiguration; use Bow\Tests\Messaging\Stubs\TestMessage; @@ -14,20 +16,28 @@ class MessagingTest extends TestCase { - private MockObject|Model $context; + private TestNotifiableModel $context; private MockObject|TestMessage $message; public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - // Initialize queue connection $config = TestingConfiguration::getConfig(); - Database::configure($config["database"]); + Database::configure($config["database"]); + Mail::configure($config["mail"]); View::configure($config["view"]); } + protected function setUp(): void + { + parent::setUp(); + + $this->context = new TestNotifiableModel(); + $this->message = $this->createMock(TestMessage::class); + } + public function test_can_send_message_synchronously(): void { $this->message->expects($this->once()) @@ -39,61 +49,58 @@ public function test_can_send_message_synchronously(): void public function test_message_sends_to_correct_channels(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); + $channels = $message->channels($this->context); - $channels = $message->channels($context); - + $this->assertIsArray($channels); + $this->assertCount(5, $channels); $this->assertEquals(['mail', 'database', 'slack', 'sms', 'telegram'], $channels); } public function test_message_can_send_to_mail(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); - - $mailMessage = $message->toMail($context); - [$email] = $mailMessage->getTo(); + $mailMessage = $message->toMail($this->context); $this->assertInstanceOf(Envelop::class, $mailMessage); + + [$email] = $mailMessage->getTo(); $this->assertEquals('test@example.com', $email[1]); $this->assertEquals('Test Message', $mailMessage->getSubject()); } public function test_message_can_send_to_database(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); - - $data = $message->toDatabase($context); + $data = $message->toDatabase($this->context); $this->assertIsArray($data); $this->assertArrayHasKey('type', $data); $this->assertArrayHasKey('data', $data); $this->assertEquals('test_message', $data['type']); + $this->assertIsArray($data['data']); + $this->assertArrayHasKey('message', $data['data']); $this->assertEquals('Test message content', $data['data']['message']); } public function test_message_can_send_to_slack(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); - - $data = $message->toSlack($context); + $data = $message->toSlack($this->context); $this->assertIsArray($data); $this->assertArrayHasKey('webhook_url', $data); $this->assertArrayHasKey('content', $data); $this->assertEquals('https://hooks.slack.com/services/test', $data['webhook_url']); + $this->assertIsArray($data['content']); + $this->assertArrayHasKey('text', $data['content']); $this->assertEquals('Test message for Slack', $data['content']['text']); } public function test_message_can_send_to_sms(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); - - $data = $message->toSms($context); + $data = $message->toSms($this->context); $this->assertIsArray($data); $this->assertArrayHasKey('to', $data); @@ -104,10 +111,8 @@ public function test_message_can_send_to_sms(): void public function test_message_can_send_to_telegram(): void { - $context = new TestNotifiableModel(); $message = new TestMessage(); - - $data = $message->toTelegram($context); + $data = $message->toTelegram($this->context); $this->assertIsArray($data); $this->assertArrayHasKey('chat_id', $data); @@ -118,11 +123,161 @@ public function test_message_can_send_to_telegram(): void $this->assertEquals('HTML', $data['parse_mode']); } - protected function setUp(): void + public function test_process_calls_all_channels(): void { - parent::setUp(); + $message = $this->getMockBuilder(TestMessage::class) + ->onlyMethods(['channels', 'toMail', 'toDatabase']) + ->getMock(); - $this->context = new TestNotifiableModel(); - $this->message = $this->createMock(TestMessage::class); + $message->expects($this->once()) + ->method('channels') + ->with($this->context) + ->willReturn(['mail', 'database']); + + $message->expects($this->once()) + ->method('toMail') + ->with($this->context) + ->willReturn((new Envelop())->to('test@example.com')->subject('Test')); + + $message->expects($this->once()) + ->method('toDatabase') + ->with($this->context) + ->willReturn(['type' => 'test', 'data' => []]); + + $message->process($this->context); + } + + public function test_message_returns_empty_array_for_unconfigured_channels(): void + { + $messaging = new class extends Messaging { + public function channels(Model $context): array + { + return []; + } + }; + + $this->assertEquals([], $messaging->toDatabase($this->context)); + $this->assertEquals([], $messaging->toSms($this->context)); + $this->assertEquals([], $messaging->toSlack($this->context)); + $this->assertEquals([], $messaging->toTelegram($this->context)); + $this->assertNull($messaging->toMail($this->context)); + } + + public function test_can_push_custom_channels(): void + { + $customChannels = [ + 'custom' => \stdClass::class, + ]; + + $result = Messaging::pushChannels($customChannels); + + $this->assertIsArray($result); + $this->assertArrayHasKey('custom', $result); + $this->assertArrayHasKey('mail', $result); + $this->assertArrayHasKey('database', $result); + } + + public function test_message_process_skips_invalid_channels(): void + { + $message = $this->getMockBuilder(TestMessage::class) + ->onlyMethods(['channels', 'toMail']) + ->getMock(); + + $message->expects($this->once()) + ->method('channels') + ->with($this->context) + ->willReturn(['invalid_channel', 'mail']); + + $message->expects($this->once()) + ->method('toMail') + ->with($this->context) + ->willReturn((new Envelop())->to('test@example.com')->subject('Test')); + + // Should not throw exception for invalid channel + $message->process($this->context); + + $this->assertTrue(true); + } + + public function test_mail_message_returns_correct_envelop_instance(): void + { + $message = new TestMessage(); + $mailMessage = $message->toMail($this->context); + + $this->assertInstanceOf(Envelop::class, $mailMessage); + $this->assertNotNull($mailMessage->getSubject()); + $this->assertNotEmpty($mailMessage->getTo()); + } + + public function test_database_message_has_required_structure(): void + { + $message = new TestMessage(); + $data = $message->toDatabase($this->context); + + // Verify required structure + $this->assertIsArray($data); + $this->assertArrayHasKey('type', $data); + $this->assertIsString($data['type']); + $this->assertNotEmpty($data['type']); + } + + public function test_slack_message_has_valid_webhook_url(): void + { + $message = new TestMessage(); + $data = $message->toSlack($this->context); + + $this->assertArrayHasKey('webhook_url', $data); + $this->assertIsString($data['webhook_url']); + $this->assertStringStartsWith('https://', $data['webhook_url']); + } + + public function test_sms_message_has_valid_phone_number(): void + { + $message = new TestMessage(); + $data = $message->toSms($this->context); + + $this->assertArrayHasKey('to', $data); + $this->assertIsString($data['to']); + $this->assertStringStartsWith('+', $data['to']); + } + + public function test_telegram_message_has_valid_parse_mode(): void + { + $message = new TestMessage(); + $data = $message->toTelegram($this->context); + + $this->assertArrayHasKey('parse_mode', $data); + $this->assertContains($data['parse_mode'], ['HTML', 'Markdown', 'MarkdownV2']); + } + + public function test_context_has_send_message_trait(): void + { + $this->assertTrue( + method_exists($this->context, 'sendMessage'), + 'Context should have sendMessage method from CanSendMessage trait' + ); + + $this->assertTrue( + method_exists($this->context, 'setMessageQueue'), + 'Context should have setMessageQueue method from CanSendMessage trait' + ); + + $this->assertTrue( + method_exists($this->context, 'sendMessageQueueOn'), + 'Context should have sendMessageQueueOn method from CanSendMessage trait' + ); + } + + public function test_channels_method_is_abstract_and_must_be_implemented(): void + { + $message = new TestMessage(); + + $this->assertTrue( + method_exists($message, 'channels'), + 'Message class must implement channels method' + ); + + $channels = $message->channels($this->context); + $this->assertIsArray($channels); } } diff --git a/tests/Queue/MessagingQueueTest.php b/tests/Queue/MessagingQueueTest.php index 8047cca7..68dd62c2 100644 --- a/tests/Queue/MessagingQueueTest.php +++ b/tests/Queue/MessagingQueueTest.php @@ -8,7 +8,7 @@ use Bow\Database\Barry\Model; use Bow\Database\DatabaseConfiguration; use Bow\Mail\MailConfiguration; -use Bow\Messaging\MessagingQueueProducer; +use Bow\Messaging\MessagingQueueJob; use Bow\Queue\Connection as QueueConnection; use Bow\Queue\QueueConfiguration; use Bow\Tests\Config\TestingConfiguration; @@ -55,10 +55,10 @@ public function test_can_send_message_synchronously(): void public function test_can_send_message_to_queue(): void { - $producer = new MessagingQueueProducer($this->context, $this->message); + $producer = new MessagingQueueJob($this->context, $this->message); // Verify that the producer is created with correct parameters - $this->assertInstanceOf(MessagingQueueProducer::class, $producer); + $this->assertInstanceOf(MessagingQueueJob::class, $producer); // Push to queue and verify static::$connection->setConnection("beanstalkd")->getAdapter()->push($producer); @@ -69,10 +69,10 @@ public function test_can_send_message_to_queue(): void public function test_can_send_message_to_specific_queue(): void { $queue = 'high-priority'; - $producer = new MessagingQueueProducer($this->context, $this->message); + $producer = new MessagingQueueJob($this->context, $this->message); // Verify that the producer is created with correct parameters - $this->assertInstanceOf(MessagingQueueProducer::class, $producer); + $this->assertInstanceOf(MessagingQueueJob::class, $producer); // Push to specific queue and verify $adapter = static::$connection->setConnection("beanstalkd")->getAdapter(); @@ -85,10 +85,10 @@ public function test_can_send_message_to_specific_queue(): void public function test_can_send_message_with_delay(): void { $delay = 3600; - $producer = new MessagingQueueProducer($this->context, $this->message); + $producer = new MessagingQueueJob($this->context, $this->message); // Verify that the producer is created with correct parameters - $this->assertInstanceOf(MessagingQueueProducer::class, $producer); + $this->assertInstanceOf(MessagingQueueJob::class, $producer); // Push to queue and verify $adapter = static::$connection->setConnection("beanstalkd")->getAdapter(); @@ -102,10 +102,10 @@ public function test_can_send_message_with_delay_on_specific_queue(): void { $delay = 3600; $queue = 'delayed-notifications'; - $producer = new MessagingQueueProducer($this->context, $this->message); + $producer = new MessagingQueueJob($this->context, $this->message); // Verify that the producer is created with correct parameters - $this->assertInstanceOf(MessagingQueueProducer::class, $producer); + $this->assertInstanceOf(MessagingQueueJob::class, $producer); // Push to specific queue with delay and verify $adapter = static::$connection->setConnection("beanstalkd")->getAdapter();