Files
piratepoet/mailpoet/tests/integration/Mailer/Methods/AmazonSESTest.php
2024-04-08 11:12:59 +02:00

287 lines
10 KiB
PHP

<?php declare(strict_types = 1);
namespace MailPoet\Test\Mailer\Methods;
use Codeception\Stub;
use MailPoet\Mailer\MailerError;
use MailPoet\Mailer\Methods\AmazonSES;
use MailPoet\Mailer\Methods\Common\BlacklistCheck;
use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
use MailPoet\WP\Functions as WPFunctions;
class AmazonSESTest extends \MailPoetTest {
public $extraParams;
public $newsletter;
public $subscriber;
/** @var AmazonSES */
public $mailer;
public $returnPath;
public $replyTo;
public $sender;
public $settings;
public function _before() {
parent::_before();
$this->settings = [
'method' => 'AmazonSES',
'access_key' => getenv('WP_TEST_MAILER_AMAZON_ACCESS') ?
getenv('WP_TEST_MAILER_AMAZON_ACCESS') :
'1234567890',
'secret_key' => getenv('WP_TEST_MAILER_AMAZON_SECRET') ?
getenv('WP_TEST_MAILER_AMAZON_SECRET') :
'abcdefghijk',
'region' => getenv('WP_TEST_MAILER_AMAZON_REGION') ?
getenv('WP_TEST_MAILER_AMAZON_REGION') :
'us-west-2',
];
$this->sender = [
'from_name' => 'Sender',
'from_email' => 'staff@mailpoet.com',
'from_name_email' => 'Sender <staff@mailpoet.com>',
];
$this->replyTo = [
'reply_to_name' => 'Reply To',
'reply_to_email' => 'reply-to@mailpoet.com',
'reply_to_name_email' => 'Reply To <reply-to@mailpoet.com>',
];
$this->returnPath = 'bounce@mailpoet.com';
$this->mailer = new AmazonSES(
$this->settings['region'],
$this->settings['access_key'],
$this->settings['secret_key'],
$this->sender,
$this->replyTo,
$this->returnPath,
new AmazonSESMapper(),
new WPFunctions()
);
$this->subscriber = 'Recipient <blackhole@mailpoet.com>';
$this->newsletter = [
'subject' => 'testing AmazonSES … © & ěščřžýáíéůėꀿąß∂ 😊👨‍👩‍👧‍👧', // try some special chars
'body' => [
'html' => 'HTML body',
'text' => 'TEXT body',
],
];
$this->extraParams = [
'unsubscribe_url' => 'https://www.mailpoet.com',
];
}
public function testItsConstructorWorks() {
verify($this->mailer->awsEndpoint)
->equals(
sprintf('email.%s.amazonaws.com', $this->settings['region'])
);
verify($this->mailer->url)
->equals(
sprintf('https://email.%s.amazonaws.com', $this->settings['region'])
);
verify(preg_match('!^\d{8}T\d{6}Z$!', $this->mailer->date))->equals(1);
verify(preg_match('!^\d{8}$!', $this->mailer->dateWithoutTime))->equals(1);
}
public function testItChecksForValidRegion() {
try {
$mailer = new AmazonSES(
'random_region',
$this->settings['access_key'],
$this->settings['secret_key'],
$this->sender,
$this->replyTo,
$this->returnPath,
new AmazonSESMapper(),
new WPFunctions()
);
$this->fail('Unsupported region exception was not thrown');
} catch (\Exception $e) {
verify($e->getMessage())->equals('Unsupported Amazon SES region');
}
}
public function testItCanGenerateBody() {
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
verify($body['Action'])->equals('SendRawEmail');
verify($body['Version'])->equals('2010-12-01');
verify($body['Source'])->equals($this->sender['from_name_email']);
verify($body['RawMessage.Data'])
->equals($this->mailer->encodeMessage($this->mailer->rawMessage));
}
public function testItCanCreateMessage() {
$mailer = $this->mailer->configureMailerWithMessage($this->newsletter, $this->subscriber, $this->extraParams);
verify($mailer->CharSet)->equals('UTF-8'); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->getToAddresses())->equals([[
'blackhole@mailpoet.com',
'Recipient',
]]);
verify($mailer->getAllRecipientAddresses())->equals(['blackhole@mailpoet.com' => true]);
verify($mailer->From)->equals($this->sender['from_email']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->FromName)->equals($this->sender['from_name']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->getReplyToAddresses())->equals([
$this->replyTo['reply_to_email'] => [
$this->replyTo['reply_to_email'],
$this->replyTo['reply_to_name'],
],
]);
verify($mailer->Sender)->equals($this->returnPath); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->ContentType)->equals('text/html'); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->Subject)->equals($this->newsletter['subject']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->Body)->equals($this->newsletter['body']['html']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->AltBody)->equals($this->newsletter['body']['text']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
verify($mailer->getCustomHeaders())->equals([
['List-Unsubscribe-Post', 'List-Unsubscribe=One-Click'],
['List-Unsubscribe', '<https://www.mailpoet.com>'],
]);
}
public function testItCanCreateRequest() {
$request = $this->mailer->request($this->newsletter, $this->subscriber);
// preserve the original message
$rawMessage = $this->mailer->encodeMessage($this->mailer->rawMessage);
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
// substitute the message to synchronize hashes
$body['RawMessage.Data'] = $rawMessage;
$body = array_map('urlencode', $body);
verify($request['timeout'])->equals(10);
verify($request['httpversion'])->equals('1.1');
verify($request['method'])->equals('POST');
verify($request['headers']['Host'])->equals($this->mailer->awsEndpoint);
verify($request['headers']['Authorization'])
->equals($this->mailer->signRequest($body));
verify($request['headers']['X-Amz-Date'])->equals($this->mailer->date);
verify($request['body'])->equals(urldecode(http_build_query($body)));
}
public function testItCanCreateCanonicalRequest() {
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
$canonicalRequest = explode(
"\n",
$this->mailer->getCanonicalRequest($body)
);
verify($canonicalRequest)
->equals(
[
'POST',
'/',
'',
'host:' . $this->mailer->awsEndpoint,
'x-amz-date:' . $this->mailer->date,
'',
'host;x-amz-date',
hash(
$this->mailer->hashAlgorithm,
urldecode(http_build_query($body))
),
]
);
}
public function testItCanCreateCredentialScope() {
$credentialScope = $this->mailer->getCredentialScope();
verify($credentialScope)
->equals(
$this->mailer->dateWithoutTime . '/' .
$this->mailer->awsRegion . '/' .
$this->mailer->awsService . '/' .
$this->mailer->awsTerminationString
);
}
public function testItCanCreateStringToSign() {
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
$credentialScope = $this->mailer->getCredentialScope();
$canonicalRequest = $this->mailer->getCanonicalRequest($body);
$stringToSing = $this->mailer->createStringToSign(
$credentialScope,
$canonicalRequest
);
$stringToSing = explode("\n", $stringToSing);
verify($stringToSing)
->equals(
[
$this->mailer->awsSigningAlgorithm,
$this->mailer->date,
$credentialScope,
hash($this->mailer->hashAlgorithm, $canonicalRequest),
]
);
}
public function testItCanSignRequest() {
$body = $this->mailer->getBody($this->newsletter, $this->subscriber);
$signedRequest = $this->mailer->signRequest($body);
verify($signedRequest)
->stringContainsString(
$this->mailer->awsSigningAlgorithm . ' Credential=' .
$this->mailer->awsAccessKey . '/' .
$this->mailer->getCredentialScope() . ', ' .
'SignedHeaders=host;x-amz-date, Signature='
);
verify(preg_match('!Signature=[A-Fa-f0-9]{64}$!', $signedRequest))
->equals(1);
}
public function testItCannotSendWithoutProperAccessKey() {
if (getenv('WP_TEST_MAILER_ENABLE_SENDING') !== 'true') $this->markTestSkipped();
$this->mailer->awsAccessKey = 'somekey';
$result = $this->mailer->send(
$this->newsletter,
$this->subscriber
);
verify($result['response'])->false();
}
public function testItCatchesSendingErrors() {
$this->mailer->sender['from_name_email'] = 'invalid';
$result = $this->mailer->send($this->newsletter, 'test@example.com');
verify($result['response'])->false();
verify($result['error'])->instanceOf(MailerError::class);
verify($result['error']->getMessage())->stringContainsString("Missing final '@domain'");
}
public function testItChecksBlacklistBeforeSending() {
$blacklistedSubscriber = 'blacklist_test@example.com';
$blacklist = Stub::make(new BlacklistCheck(), ['isBlacklisted' => true], $this);
$mailer = Stub::make(
$this->mailer,
['blacklist' => $blacklist, 'errorMapper' => new AmazonSESMapper()],
$this
);
$result = $mailer->send(
$this->newsletter,
$blacklistedSubscriber
);
verify($result['response'])->false();
verify($result['error'])->instanceOf(MailerError::class);
verify($result['error']->getMessage())->stringContainsString('AmazonSES has returned an unknown error.');
}
public function testItCanSend() {
$mockedWp = $this->createMock(WPFunctions::class);
/**
* We don't want to send a real email through AmazonSES, thus mocking
*/
$mockedWp->method('wpRemotePost')
->willReturn(['response' => true]);
$mockedWp->method('wpRemoteRetrieveResponseCode')
->willReturn(200);
$mailer = new AmazonSES(
$this->settings['region'],
$this->settings['access_key'],
$this->settings['secret_key'],
$this->sender,
$this->replyTo,
$this->returnPath,
new AmazonSESMapper(),
$mockedWp
);
$result = $mailer->send(
$this->newsletter,
$this->subscriber
);
verify($result['response'])->true();
}
}