Skip to content

Commit

Permalink
Let WebPushConfig be more lenient with TTL values
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromegamez committed Jul 9, 2022
1 parent 63b1a47 commit d477a6f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [Unreleased]

### Fixed

* The `WebPushConfig` class is now more lenient with TTL values, and urgencies are checked if they are valid
([#713](https://github.com/kreait/firebase-php/issues/716)

## [6.6.0] - 2022-07-07

### Fixed
Expand Down
46 changes: 44 additions & 2 deletions src/Firebase/Messaging/WebPushConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
namespace Kreait\Firebase\Messaging;

use JsonSerializable;
use Kreait\Firebase\Exception\Messaging\InvalidArgument;

/**
* @see https://tools.ietf.org/html/rfc8030#section-5.3 Web Push Message Urgency
*
* @phpstan-type WebPushHeadersShape array{
* TTL?: positive-int,
* TTL?: positive-int|numeric-string,
* Urgency?: self::URGENCY_*
* }
*
Expand Down Expand Up @@ -59,6 +59,13 @@ final class WebPushConfig implements JsonSerializable
private const URGENCY_NORMAL = 'normal';
private const URGENCY_HIGH = 'high';

private const VALID_URGENCIES = [
self::URGENCY_VERY_LOW,
self::URGENCY_LOW,
self::URGENCY_NORMAL,
self::URGENCY_HIGH,
];

/**
* @var WebPushConfigShape
*/
Expand All @@ -82,9 +89,44 @@ public static function new(): self
*/
public static function fromArray(array $config): self
{
if (array_key_exists('headers', $config) && is_array($config['headers'])) {
$config['headers'] = self::ensureValidHeaders($config['headers']);
}

return new self($config);
}

/**
* @param WebPushHeadersShape $headers
*
* @return WebPushHeadersShape
*/
private static function ensureValidHeaders(array $headers): array
{
if (array_key_exists('TTL', $headers) && is_int($headers['TTL'])) {
$headers['TTL'] = (string) $headers['TTL'];
}

if (
array_key_exists('TTL', $headers)
&& is_string($headers['TTL'])
&& preg_match('/^[\-0]/', $headers['TTL']) === 1
) {
throw new InvalidArgument('The TTL in the WebPushConfig must must be a positive int');
}

if (array_key_exists('Urgency', $headers)) {
if (!in_array($headers['Urgency'], self::VALID_URGENCIES, true)) {
throw new InvalidArgument(sprintf(
'The Urgency in the WebPushConfig header must must be one of %s',
implode(',', self::VALID_URGENCIES)
));
}
}

return $headers;
}

public function withHighUrgency(): self
{
return $this->withUrgency(self::URGENCY_HIGH);
Expand Down
24 changes: 24 additions & 0 deletions tests/Integration/MessagingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\MessageTarget;
use Kreait\Firebase\Messaging\RawMessageFromArray;
use Kreait\Firebase\Messaging\WebPushConfig;
use Kreait\Firebase\Tests\IntegrationTestCase;

/**
* @internal
*
* @phpstan-import-type WebPushHeadersShape from WebPushConfig
*/
final class MessagingTest extends IntegrationTestCase
{
Expand Down Expand Up @@ -381,4 +384,25 @@ public function testAndroidConfigTtlWorksWithValidValues($value): void

$this->addToAssertionCount(1);
}

/**
* @see https://github.com/kreait/firebase-php/issues/716
*
* @dataProvider \Kreait\Firebase\Tests\Unit\Messaging\WebPushConfigTest::validHeaders
*
* @param WebPushHeadersShape $headers
*/
public function testWebPushConfigTtlWorksWithValidValues(array $headers): void
{
$config = WebPushConfig::fromArray([
'headers' => $headers,
]);

$message = CloudMessage::withTarget(MessageTarget::TOKEN, $this->getTestRegistrationToken())
->withWebPushConfig($config);

$this->messaging->send($message);

$this->addToAssertionCount(1);
}
}
17 changes: 10 additions & 7 deletions tests/Unit/Messaging/AndroidConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@

namespace Kreait\Firebase\Tests\Unit\Messaging;

use Beste\Json;
use Kreait\Firebase\Exception\Messaging\InvalidArgument;
use Kreait\Firebase\Messaging\AndroidConfig;
use Kreait\Firebase\Tests\UnitTestCase;

/**
* @internal
*
* @phpstan-import-type AndroidConfigShape from AndroidConfig
*/
final class AndroidConfigTest extends UnitTestCase
{
public function testItIsEmptyWhenItIsEmpty(): void
{
$this->assertSame('[]', \json_encode(AndroidConfig::new()));
$this->assertSame('[]', Json::encode(AndroidConfig::new()));
}

public function testItHasADefaultSound(): void
Expand All @@ -27,24 +30,24 @@ public function testItHasADefaultSound(): void
];

$this->assertJsonStringEqualsJsonString(
\json_encode($expected),
\json_encode(AndroidConfig::new()->withDefaultSound())
Json::encode($expected),
Json::encode(AndroidConfig::new()->withDefaultSound())
);
}

public function testItCanHaveAPriority(): void
{
$config = AndroidConfig::new()->withNormalPriority();
$config = AndroidConfig::new()->withNormalMessagePriority();
$this->assertSame('normal', $config->jsonSerialize()['priority']);

$config = AndroidConfig::new()->withHighPriority();
$config = AndroidConfig::new()->withHighMessagePriority();
$this->assertSame('high', $config->jsonSerialize()['priority']);
}

/**
* @dataProvider validDataProvider
*
* @param array<string, array<string, mixed>> $data
* @param AndroidConfigShape $data
*/
public function testItCanBeCreatedFromAnArray(array $data): void
{
Expand Down Expand Up @@ -82,7 +85,7 @@ public function testItRejectsInvalidTtls($ttl): void
}

/**
* @return array<string, array<int, array<string, mixed>>>
* @return array<array-key, list<AndroidConfigShape>>
*/
public function validDataProvider(): array
{
Expand Down
44 changes: 42 additions & 2 deletions tests/Unit/Messaging/WebPushConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

namespace Kreait\Firebase\Tests\Unit\Messaging;

use Kreait\Firebase\Exception\Messaging\InvalidArgument;
use Kreait\Firebase\Messaging\WebPushConfig;
use Kreait\Firebase\Tests\UnitTestCase;

/**
* @internal
* @phpstan-import-type WebPushConfigShape from WebPushConfig
* @phpstan-import-type WebPushHeadersShape from WebPushConfig
*/
final class WebPushConfigTest extends UnitTestCase
{
Expand All @@ -17,7 +20,7 @@ final class WebPushConfigTest extends UnitTestCase
*
* @param array<string, mixed> $data
*/
public function testCreateFromArray(array $data): void
public function testCreateFromValidPayload(array $data): void
{
$config = WebPushConfig::fromArray($data);

Expand All @@ -40,7 +43,19 @@ public function testItCanHaveAPriority(): void
}

/**
* @return array<string, array<string, array<string, mixed>>>
* @dataProvider invalidHeaders
*
* @param WebPushHeadersShape $headers
*/
public function testItRejectsInvalidHeaders(array $headers): void
{
$this->expectException(InvalidArgument::class);

WebPushConfig::fromArray(['headers' => $headers]);
}

/**
* @return array<string, array<WebPushConfigShape>>
*/
public function validDataProvider(): array
{
Expand All @@ -58,4 +73,29 @@ public function validDataProvider(): array
],
];
}

/**
* @return array<string, array<WebPushHeadersShape>>
*/
public function validHeaders(): array
{
return [
'positive int ttl' => [['TTL' => 1]],
'positive string ttl' => [['TTL' => '1']],
];
}

/**
* @return array<string, array<array<string, mixed>>>
*/
public function invalidHeaders(): array
{
return [
'negative int ttl' => [['TTL' => -1]],
'negative string ttl' => [['TTL' => '-1']],
'zero int ttl' => [['TTL' => -1]],
'zero string ttl' => [['TTL' => '-1']],
'unsupported urgency' => [['Urgency' => 'unsupported']],
];
}
}

0 comments on commit d477a6f

Please sign in to comment.