<?php namespace App\Tests\integration\Infrastructure; use App\Domain\Logger; use App\Infrastructure\SnsNotifier; use App\Tests\Helpers\Assert; use App\Tests\integration\Infrastructure\Helpers\AsyncTestHelpers; use App\Tests\unit\Utils\MockableFeatureFlags; use App\Utils\Features; use Aws\Sns\SnsClient; use Aws\Sqs\SqsClient; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use function json_decode; class SnsNotifierTest extends TestCase { private SnsClient $snsClient; private SqsClient $sqsClient; private $topicArn; private $queueUrl; private const SNS_ENDPOINT = 'http://sns:9911'; private const SQS_ENDPOINT = 'http://sqs:9324'; private const TEST_CONFIGURATION = [ 'region' => 'us-east-1', 'version' => 'latest', 'credentials' => [ 'key' => 'KEY', 'secret' => 'SECRET' ], 'use_path_style_endpoint' => true, ]; private const NOTIFIER_CONFIGURATION = [ 'region' => 'us-east-1', 'credentials' => [ 'key' => 'KEY', 'secret' => 'SECRET' ], 'endpoint' => self::SNS_ENDPOINT ]; private $logger; public function setUp(): void { $features = new MockableFeatureFlags(); Features::create($features); $this->snsClient = $this->createSnsClient(self::TEST_CONFIGURATION); $this->topicArn = $this->createTopic(); $this->sqsClient = $this->createSqsClient(self::TEST_CONFIGURATION, self::SQS_ENDPOINT); $this->queueUrl = $this->subscribeToTopic($this->topicArn); $this->logger = $this->prophesize(Logger::class); } public function tearDown(): void { $this->sqsClient->purgeQueue(['QueueUrl' => $this->queueUrl]); $this->snsClient->deleteTopic(['TopicArn' => $this->topicArn]); } /** @test */ public function shouldNotifyAnEventToSnS() { $snsNotifier = new SnsNotifier( self::NOTIFIER_CONFIGURATION, $this->topicArn, $this->logger->reveal() ); $dummyNotification = ["dummy" => 'dummy notification']; $snsNotifier->notify($dummyNotification); $this->assertNotificationWasPublished($dummyNotification); } private function assertNotificationWasPublished($expectedNotification): void { $sleepTime = 3; $numTries = 3; $errorDescription = 'Message could not be inserted in SQS'; $probe = function () { $receiveMessage = $this->sqsClient->receiveMessage([ 'QueueUrl' => $this->queueUrl, 'MaxNumberOfMessages' => 10]); return $receiveMessage['Messages']; }; $check = function ($messages) use ($expectedNotification) { if (!$messages) { return false; } $firstMessageBody = json_decode($messages[0]['Body'], true); $actualNotification = json_decode($firstMessageBody['Message'], true); Assert::strictEquals($expectedNotification, $actualNotification); return true; }; AsyncTestHelpers::assertWithPolling( $sleepTime, $numTries, $errorDescription, $probe, $check ); } private function createSqsClient(array $baseConfiguration, string $sqsEndpoint): SqsClient { return new SqsClient(array_merge($baseConfiguration, [ 'endpoint' => $sqsEndpoint, ])); } private function createSnsClient(array $baseConfiguration): SnsClient { return new SnsClient(array_merge($baseConfiguration, [ 'endpoint' => self::SNS_ENDPOINT, ])); } private function createTopic() { $topic = $this->snsClient->createTopic([ 'Name' => 'snsName-test' ]); return $topic['TopicArn']; } private function subscribeToTopic($topicArn) { $queueName = 'sqsQueue-name'; $queue = $this->sqsClient->createQueue([ 'QueueName' => $queueName ]); $this->snsClient->subscribe([ 'Protocol' => 'sqs', 'Endpoint' => "aws-sqs://{$queueName}?amazonSQSEndpoint=" . self::SQS_ENDPOINT . "&accessKey=&secretKey=", 'TopicArn' => $topicArn ]); return $queue['QueueUrl']; } }