Skip to content

Commit

Permalink
Use GitHub Actions for testing (#330)
Browse files Browse the repository at this point in the history
* Add workflow file for tests on github actions

* Remove travis ci

* Check CI variable correctly and fix PHPStan issue

* Stop running tests on PHP 7.2

* Use openssl_pkey_get_* methods on keys before passing to openssl_pkey_derive

* Update link to badge in README

* Reduce setup-php extensions to bare minimum

* Remove PR branch from workflows file

* Add builds for PHP 8.1

* Stop skipping PushServiceTest on CI

* Run tests with web-push-testing

* Remove invalid assert from PushServiceTest

* Add fallback for running WebPushTest on CI environment

* Remove PHP 7.2 from tests as that is no longer supported

* Resolve phpstan errors

* Skip running php-cs-fixer on PHP 8.1

PHP 8.1 is currently not supported by this.

* Remove extra conversions of public & private key strings

* Throw exception instead of silent fallback when unpack fails
  • Loading branch information
marc1706 authored Feb 13, 2022
1 parent 92dace6 commit 199c83e
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 152 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Tests

on:
push:
branches:
- master
tags:
- 'v*'
pull_request:
branches:
- master

jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.3', '7.4', '8.0', '8.1']

name: PHP ${{ matrix.php }}

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: curl, mbstring, openssl, gmp
coverage: none

- name: Setup node
uses: actions/setup-node@v2
with:
node-version: '16'

- name: Cache Composer dependencies
uses: actions/cache@v2
with:
path: /tmp/composer-cache
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}

- name: Prepare composer
run: |
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then
>&2 echo 'ERROR: Invalid installer checksum'
rm composer-setup.php
exit 1
fi
sudo php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer
RESULT=$?
rm composer-setup.php
composer config discard-changes true
composer install
- name: Setup web-push-testing-service
run: |
npm install web-push-testing -g
- name: Run tests
run: |
web-push-testing --port 9012 start
composer test:unit
web-push-testing --port 9012 stop
- name: Run PHPStan
run: composer test:typing

- name: Run php-cs-fixer
if: ${{ matrix.php != '8.1' }}
run: composer test:syntax
54 changes: 0 additions & 54 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# WebPush
> Web Push library for PHP
[![Build Status](https://travis-ci.org/web-push-libs/web-push-php.svg?branch=master)](https://travis-ci.org/web-push-libs/web-push-php)
[![Build Status](https://github.com/web-push-libs/web-push-php/actions/workflows/tests.yml/badge.svg)](https://github.com/web-push-libs/web-push-php/actions/workflows/tests.yml)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d60e8eea-aea1-4739-8ce0-a3c3c12c6ccf/mini.png)](https://insight.sensiolabs.com/projects/d60e8eea-aea1-4739-8ce0-a3c3c12c6ccf)

WebPush can be used to send notifications to endpoints which server delivers Web Push notifications as described in
Expand Down
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ parameters:
paths:
- src
checkMissingIterableValueType: false
reportUnmatchedIgnoredErrors: false
ignoreErrors:
- '#Unreachable statement \- code above always terminates\.#'
- '#Unreachable statement \- code above always terminates\.#'
17 changes: 14 additions & 3 deletions src/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,6 @@ public static function deterministicEncrypt(string $payload, string $userPublicK
$sharedSecret = self::calculateAgreementKey($localJwk, $userJwk);

$sharedSecret = str_pad($sharedSecret, 32, chr(0), STR_PAD_LEFT);
if (!$sharedSecret) {
throw new \ErrorException('Failed to convert shared secret from hexadecimal to binary');
}

// section 4.3
$ikm = self::getIKM($userAuthToken, $userPublicKey, $localPublicKey, $sharedSecret, $contentEncoding);
Expand Down Expand Up @@ -362,17 +359,31 @@ private static function calculateAgreementKey(JWK $private_key, JWK $public_key)
}
}

/**
* @throws \ErrorException
*/
private static function convertBase64ToBigInteger(string $value): BigInteger
{
$value = unpack('H*', Base64Url::decode($value));

if ($value === false) {
throw new \ErrorException('Unable to unpack hex value from string');
}

return BigInteger::fromBase($value[1], 16);
}

/**
* @throws \ErrorException
*/
private static function convertBase64ToGMP(string $value): \GMP
{
$value = unpack('H*', Base64Url::decode($value));

if ($value === false) {
throw new \ErrorException('Unable to unpack hex value from string');
}

return gmp_init($value[1], 16);
}

Expand Down
4 changes: 2 additions & 2 deletions src/WebPush.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,10 @@ protected function prepare(array $notifications): array
$encryptionContentCodingHeader = Encryption::getContentCodingHeader($salt, $localPublicKey, $contentEncoding);
$content = $encryptionContentCodingHeader.$cipherText;

$headers['Content-Length'] = Utils::safeStrlen($content);
$headers['Content-Length'] = (string) Utils::safeStrlen($content);
} else {
$headers = [
'Content-Length' => 0,
'Content-Length' => '0',
];

$content = '';
Expand Down
97 changes: 22 additions & 75 deletions tests/PushServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ final class PushServiceTest extends PHPUnit\Framework\TestCase
{
private static $timeout = 30;
private static $portNumber = 9012;
private static $testSuiteId;
private static $testServiceUrl;
private static $vapidKeys = [
public static $vapidKeys = [
'subject' => 'http://test.com',
'publicKey' => 'BA6jvk34k6YjElHQ6S0oZwmrsqHdCNajxcod6KJnI77Dagikfb--O_kYXcR2eflRz6l3PcI2r8fPCH3BElLQHDk',
'privateKey' => '-3CdhFOqjzixgAbUSa0Zv9zi-dwDVmWO7672aBxSFPQ',
Expand All @@ -37,34 +36,13 @@ public static function setUpBeforeClass(): void
self::$testServiceUrl = 'http://localhost:'.self::$portNumber;
}

/**
* {@inheritdoc}
*/
protected function setUp(): void
{
if (!(getenv('TRAVIS') || getenv('CI'))) {
$this->markTestSkipped('This test does not run on Travis.');
}

$startApiCurl = curl_init(self::$testServiceUrl.'/api/start-test-suite/');
curl_setopt_array($startApiCurl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => self::$timeout,
]);

$parsedResp = $this->getResponse($startApiCurl);
self::$testSuiteId = $parsedResp->{'data'}->{'testSuiteId'};
}

public function browserProvider()
{
return [
['firefox', 'stable', ['VAPID' => self::$vapidKeys]],
['firefox', 'beta', ['VAPID' => self::$vapidKeys]],
['chrome', 'stable', ['VAPID' => self::$vapidKeys]],
['chrome', 'beta', ['VAPID' => self::$vapidKeys]],
['firefox', ['VAPID' => self::$vapidKeys]],
['chrome', ['VAPID' => self::$vapidKeys]],
['firefox', []],
['chrome', []],
];
}

Expand Down Expand Up @@ -92,30 +70,25 @@ public function retryTest($retryCount, $test)
* @dataProvider browserProvider
* Run integration tests with browsers
*/
public function testBrowsers($browserId, $browserVersion, $options)
public function testBrowsers($browserId, $options)
{
$this->retryTest(2, $this->createClosureTest($browserId, $browserVersion, $options));
$this->retryTest(2, $this->createClosureTest($browserId, $options));
}

protected function createClosureTest($browserId, $browserVersion, $options)
protected function createClosureTest($browserId, $options)
{
return function () use ($browserId, $browserVersion, $options) {
return function () use ($browserId, $options) {
$this->webPush = new WebPush($options);
$this->webPush->setAutomaticPadding(false);

$subscriptionParameters = [
'testSuiteId' => self::$testSuiteId,
'browserName' => $browserId,
'browserVersion' => $browserVersion,
];
$subscriptionParameters = [];

if (array_key_exists('VAPID', $options)) {
$subscriptionParameters['vapidPublicKey'] = self::$vapidKeys['publicKey'];
$subscriptionParameters['applicationServerKey'] = self::$vapidKeys['publicKey'];
}

$subscriptionParameters = json_encode($subscriptionParameters, JSON_THROW_ON_ERROR);

$getSubscriptionCurl = curl_init(self::$testServiceUrl.'/api/get-subscription/');
$getSubscriptionCurl = curl_init(self::$testServiceUrl.'/subscribe');
curl_setopt_array($getSubscriptionCurl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $subscriptionParameters,
Expand All @@ -128,18 +101,17 @@ protected function createClosureTest($browserId, $browserVersion, $options)
]);

$parsedResp = $this->getResponse($getSubscriptionCurl);
$testId = $parsedResp->{'data'}->{'testId'};
$subscription = $parsedResp->{'data'}->{'subscription'};
$subscription = $parsedResp->{'data'};

$supportedContentEncodings = property_exists($subscription, 'supportedContentEncodings') ?
$subscription->{'supportedContentEncodings'} :
["aesgcm"];
$supportedContentEncodings = ['aesgcm', 'aes128gcm'];

$endpoint = $subscription->{'endpoint'};
$keys = $subscription->{'keys'};
$auth = $keys->{'auth'};
$p256dh = $keys->{'p256dh'};
$clientHash = $subscription->{'clientHash'};
$payload = 'hello';
$messageIndex = 0;

foreach ($supportedContentEncodings as $contentEncoding) {
if (!in_array($contentEncoding, ['aesgcm', 'aes128gcm'])) {
Expand All @@ -150,16 +122,14 @@ protected function createClosureTest($browserId, $browserVersion, $options)

$subscription = new Subscription($endpoint, $p256dh, $auth, $contentEncoding);
$report = $this->webPush->sendOneNotification($subscription, $payload);
$this->assertInstanceOf(\Generator::class, $report);
$this->assertInstanceOf(\Minishlink\WebPush\MessageSentReport::class, $report);
$this->assertTrue($report->isSuccess());

$dataString = json_encode([
'testSuiteId' => self::$testSuiteId,
'testId' => $testId,
], JSON_THROW_ON_ERROR);
'clientHash' => $clientHash,
]);

$getNotificationCurl = curl_init(self::$testServiceUrl.'/api/get-notification-status/');
$getNotificationCurl = curl_init(self::$testServiceUrl.'/get-notifications');
curl_setopt_array($getNotificationCurl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $dataString,
Expand All @@ -174,39 +144,16 @@ protected function createClosureTest($browserId, $browserVersion, $options)
$parsedResp = $this->getResponse($getNotificationCurl);

if (!property_exists($parsedResp->{'data'}, 'messages')) {
throw new Exception('web-push-testing-service error, no messages: '.json_encode($parsedResp, JSON_THROW_ON_ERROR));
throw new Exception('web-push-testing error, no messages: '.json_encode($parsedResp));
}

$messages = $parsedResp->{'data'}->{'messages'};
$this->assertEquals(1, is_countable($messages) ? count($messages) : 0);
$this->assertEquals($payload, $messages[0]);
$this->assertEquals($payload, $messages[$messageIndex]);
$this->assertCount(++$messageIndex, $messages);
}
};
}

protected function tearDown(): void
{
$dataString = '{ "testSuiteId": '.self::$testSuiteId.' }';
$curl = curl_init(self::$testServiceUrl.'/api/end-test-suite/');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $dataString,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: '.strlen($dataString),
],
CURLOPT_TIMEOUT => self::$timeout,
]);
$this->getResponse($curl);
self::$testSuiteId = null;
}

public static function tearDownAfterClass(): void
{
exec('web-push-testing-service stop phpunit');
}

private function getResponse($ch)
{
$resp = curl_exec($ch);
Expand Down
Loading

0 comments on commit 199c83e

Please sign in to comment.