Skip to content

Commit 61e5f98

Browse files
Moved to GitHub Actions and increased test coverage
1 parent 5f20997 commit 61e5f98

File tree

7 files changed

+191
-82
lines changed

7 files changed

+191
-82
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: 'CI'
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- 'main'
8+
9+
env:
10+
COMPOSER_ROOT_VERSION: '1.99.99'
11+
12+
jobs:
13+
lint:
14+
name: 'Lint'
15+
runs-on: 'ubuntu-latest'
16+
steps:
17+
- uses: 'actions/checkout@v2'
18+
- uses: 'shivammathur/setup-php@v2'
19+
with:
20+
php-version: '7.4'
21+
coverage: 'none'
22+
ini-values: 'memory_limit=-1'
23+
tools: 'composer:v2'
24+
- uses: 'ramsey/composer-install@v1'
25+
- name: 'Lint the PHP source code'
26+
run: './vendor/bin/parallel-lint src test'
27+
28+
coding-standards:
29+
name: 'Coding Standards'
30+
runs-on: 'ubuntu-latest'
31+
steps:
32+
- uses: 'actions/checkout@v2'
33+
- uses: 'shivammathur/setup-php@v2'
34+
with:
35+
php-version: '7.4'
36+
coverage: 'none'
37+
ini-values: 'memory_limit=-1'
38+
tools: 'composer:v2'
39+
- uses: 'ramsey/composer-install@v1'
40+
- name: 'Check coding standards'
41+
run: './vendor/bin/phpcs src --standard=psr2 -sp --colors'
42+
43+
unit-tests:
44+
name: 'Unit Tests'
45+
runs-on: 'ubuntu-latest'
46+
continue-on-error: ${{ matrix.experimental }}
47+
strategy:
48+
fail-fast: false
49+
matrix:
50+
php-version:
51+
- '5.6'
52+
- '7.0'
53+
- '7.1'
54+
- '7.2'
55+
- '7.3'
56+
- '7.4'
57+
- '8.0'
58+
experimental:
59+
- false
60+
include:
61+
- php-version: '8.1'
62+
experimental: true
63+
composer-options: '--ignore-platform-reqs'
64+
steps:
65+
- uses: 'actions/checkout@v2'
66+
- uses: 'shivammathur/setup-php@v2'
67+
with:
68+
php-version: '${{ matrix.php-version }}'
69+
coverage: 'pcov'
70+
ini-values: 'memory_limit=-1'
71+
tools: 'composer:v2'
72+
- name: 'Prepare for tests'
73+
run: 'mkdir -p build/logs'
74+
- uses: 'ramsey/composer-install@v1'
75+
with:
76+
composer-options: '${{ matrix.composer-options }}'
77+
- name: 'Run unit tests'
78+
run: './vendor/bin/phpunit --colors=always --coverage-clover build/logs/clover.xml'
79+
- name: 'Publish coverage report to Codecov'
80+
uses: 'codecov/codecov-action@v1'

.travis.yml

-67
This file was deleted.

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ All Notable changes to `oauth2-apple` will be documented in this file
1818
### Security
1919
- Nothing
2020

21+
## 0.2.6 - 2021-08-25
22+
23+
### Added
24+
- GitHub Actions CI
25+
26+
### Removed
27+
- Travis CI
28+
29+
### Fixed
30+
- Fixed bug with serialization of AppleAccessToken [#29](https://github.com/patrickbussmann/oauth2-apple/pull/29) (thanks to [tjveldhuizen](https://github.com/tjveldhuizen))
31+
2132
## 0.2.5 - 2021-03-10
2233

2334
### Fixed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"require-dev": {
2828
"phpunit/phpunit": "^5.7 || ^6.0 || ^9.3",
2929
"mockery/mockery": "^1.3",
30+
"php-parallel-lint/php-parallel-lint": "^1.3",
3031
"squizlabs/php_codesniffer": "^2.3 || ^3.0",
3132
"ext-json": "*"
3233
},

src/Provider/Apple.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private function getAppleKeys()
8888
{
8989
$response = $this->httpClient->request('GET', 'https://appleid.apple.com/auth/keys');
9090

91-
if ($response) {
91+
if ($response && $response->getStatusCode() === 200) {
9292
return JWK::parseKeySet(json_decode($response->getBody()->getContents(), true));
9393
}
9494

test/src/Provider/AppleTest.php

+58-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use League\OAuth2\Client\Provider\Apple;
1010
use League\OAuth2\Client\Provider\AppleResourceOwner;
1111
use League\OAuth2\Client\Token\AccessToken;
12+
use League\OAuth2\Client\Token\AppleAccessToken;
1213
use League\OAuth2\Client\Tool\QueryBuilderTrait;
1314
use PHPUnit\Framework\TestCase;
1415
use Mockery as m;
@@ -164,6 +165,40 @@ public function testGetAccessToken()
164165
]);
165166
}
166167

168+
public function testGetAccessTokenFailedBecauseAppleHasError()
169+
{
170+
$this->expectException('Exception');
171+
$this->expectExceptionMessage('Got no data within "id_token"!');
172+
173+
$provider = new TestApple([
174+
'clientId' => 'mock.example',
175+
'teamId' => 'mock.team.id',
176+
'keyFileId' => 'mock.file.id',
177+
'keyFilePath' => __DIR__ . '/../../resources/p256-private-key.p8',
178+
'redirectUri' => 'none'
179+
]);
180+
$provider = m::mock($provider);
181+
182+
$client = m::mock(ClientInterface::class);
183+
$client->shouldReceive('request')
184+
->times(1)
185+
->andReturn(new Response(500, [], 'Internal Server Error'));
186+
$client->shouldReceive('send')
187+
->times(1)
188+
->andReturn(new Response(200, [], json_encode([
189+
'access_token' => 'aad897dee58fe4f66bf220c181adaf82b.0.mrwxq.hmiE0djj1vJqoNisKmF-pA',
190+
'token_type' => 'Bearer',
191+
'expires_in' => 3600,
192+
'refresh_token' => 'r4a6e8b9c50104b78bc86b0d2649353fa.0.mrwxq.54joUj40j0cpuMANRtRjfg',
193+
'id_token' => 'abc'
194+
])));
195+
$provider->setHttpClient($client);
196+
197+
$provider->getAccessToken('authorization_code', [
198+
'code' => 'hello-world'
199+
]);
200+
}
201+
167202
public function testFetchingOwnerDetails()
168203
{
169204
$provider = $this->getProvider();
@@ -206,6 +241,7 @@ public function testNotImplementedGetResourceOwnerDetailsUrl()
206241
public function testCheckResponse()
207242
{
208243
$this->expectException('\League\OAuth2\Client\Provider\Exception\AppleAccessDeniedException');
244+
$this->expectExceptionMessage('invalid_client');
209245
$provider = $this->getProvider();
210246
$class = new \ReflectionClass($provider);
211247
$method = $class->getMethod('checkResponse');
@@ -217,7 +253,7 @@ public function testCheckResponse()
217253
]]);
218254
}
219255

220-
public function testCreationOfResourceOwner()
256+
public function testCreationOfResourceOwnerWithName()
221257
{
222258
$provider = $this->getProvider();
223259
$class = new \ReflectionClass($provider);
@@ -247,6 +283,27 @@ public function testCreationOfResourceOwner()
247283
$this->assertArrayHasKey('name', $data->toArray());
248284
}
249285

286+
public function testCreationOfResourceOwnerWithoutName()
287+
{
288+
$provider = $this->getProvider();
289+
$class = new \ReflectionClass($provider);
290+
$method = $class->getMethod('createResourceOwner');
291+
$method->setAccessible(true);
292+
293+
/** @var AppleResourceOwner $data */
294+
$data = $method->invokeArgs($provider, [
295+
[],
296+
new AccessToken([
297+
'access_token' => 'hello',
298+
'email' => '[email protected]',
299+
'resource_owner_id' => '123.4.567'
300+
])
301+
]);
302+
$this->assertEquals('[email protected]', $data->getEmail());
303+
$this->assertNull($data->getLastName());
304+
$this->assertNull($data->getFirstName());
305+
}
306+
250307
public function testGetConfiguration()
251308
{
252309
$provider = m::mock(Apple::class)->makePartial();

test/src/Token/AppleAccessTokenTest.php

+40-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace League\OAuth2\Client\Test\Token;
44

5-
use GuzzleHttp\Psr7\Response;
65
use League\OAuth2\Client\Token\AppleAccessToken;
76
use PHPUnit\Framework\TestCase;
87
use Mockery as m;
@@ -20,7 +19,10 @@ public function testCreatingAccessToken()
2019
->with('something', 'examplekey', ['RS256'])
2120
->once()
2221
->andReturn([
23-
'sub' => '123.abc.123'
22+
'sub' => '123.abc.123',
23+
'email_verified' => true,
24+
'email' => '[email protected]',
25+
'is_private_email' => true
2426
]);
2527

2628
$accessToken = new AppleAccessToken(['examplekey'], [
@@ -33,6 +35,21 @@ public function testCreatingAccessToken()
3335
$this->assertEquals('something', $accessToken->getIdToken());
3436
$this->assertEquals('123.abc.123', $accessToken->getResourceOwnerId());
3537
$this->assertEquals('access_token', $accessToken->getToken());
38+
$this->assertEquals('[email protected]', $accessToken->getEmail());
39+
$this->assertTrue($accessToken->isPrivateEmail());
40+
}
41+
42+
public function testCreateFailsBecauseNoIdTokenIsSet()
43+
{
44+
$this->expectException('\InvalidArgumentException');
45+
$this->expectExceptionMessage('Required option not passed: "id_token"');
46+
47+
new AppleAccessToken(['examplekey'], [
48+
'access_token' => 'access_token',
49+
'token_type' => 'Bearer',
50+
'expires_in' => 3600,
51+
'refresh_token' => 'abc.0.def'
52+
]);
3653
}
3754

3855
public function testCreatingRefreshToken()
@@ -45,17 +62,27 @@ public function testCreatingRefreshToken()
4562
$this->assertEquals('access_token', $refreshToken->getToken());
4663
}
4764

48-
private function getClient($times)
65+
/**
66+
* @runInSeparateProcess
67+
* @preserveGlobalState disabled
68+
*/
69+
public function testCreatingAccessTokenFailsBecauseNoDecodingIsPossible()
4970
{
50-
$client = m::mock('GuzzleHttp\ClientInterface');
51-
if ($times > 0) {
52-
$client->shouldReceive('request')
53-
->times($times)
54-
->withArgs(['GET', 'https://appleid.apple.com/auth/keys'])
55-
->andReturn(new Response())
56-
;
57-
}
58-
59-
return $client;
71+
$this->expectException('\Exception');
72+
$this->expectExceptionMessage('Got no data within "id_token"!');
73+
74+
$externalJWTMock = m::mock('overload:Firebase\JWT\JWT');
75+
$externalJWTMock->shouldReceive('decode')
76+
->with('something', 'examplekey', ['RS256'])
77+
->once()
78+
->andReturnNull();
79+
80+
new AppleAccessToken(['examplekey'], [
81+
'access_token' => 'access_token',
82+
'token_type' => 'Bearer',
83+
'expires_in' => 3600,
84+
'refresh_token' => 'abc.0.def',
85+
'id_token' => 'something'
86+
]);
6087
}
6188
}

0 commit comments

Comments
 (0)