2018-01-06 17:02:45 +00:00
|
|
|
<?php
|
|
|
|
/** @license MIT
|
|
|
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
|
|
|
* See LICENSE and AUTHORS files for details */
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace JKingWeb\Arsse\TestCase\REST;
|
|
|
|
|
2018-01-11 20:48:29 +00:00
|
|
|
use JKingWeb\Arsse\Arsse;
|
|
|
|
use JKingWeb\Arsse\User;
|
2018-01-06 17:02:45 +00:00
|
|
|
use JKingWeb\Arsse\REST;
|
2018-01-07 17:59:10 +00:00
|
|
|
use JKingWeb\Arsse\REST\Handler;
|
2018-01-06 17:02:45 +00:00
|
|
|
use JKingWeb\Arsse\REST\Exception501;
|
2019-12-05 18:02:02 +00:00
|
|
|
use JKingWeb\Arsse\REST\NextcloudNews\V1_2 as NCN;
|
2018-01-07 17:59:10 +00:00
|
|
|
use JKingWeb\Arsse\REST\TinyTinyRSS\API as TTRSS;
|
|
|
|
use Psr\Http\Message\RequestInterface;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
2020-01-20 15:40:05 +00:00
|
|
|
use Laminas\Diactoros\Request;
|
|
|
|
use Laminas\Diactoros\Response;
|
|
|
|
use Laminas\Diactoros\ServerRequest;
|
|
|
|
use Laminas\Diactoros\Response\TextResponse;
|
|
|
|
use Laminas\Diactoros\Response\EmptyResponse;
|
2018-01-06 17:02:45 +00:00
|
|
|
|
|
|
|
/** @covers \JKingWeb\Arsse\REST */
|
|
|
|
class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
|
|
|
|
|
|
|
/** @dataProvider provideApiMatchData */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testMatchAUrlToAnApi($apiList, string $input, array $exp): void {
|
2018-01-06 17:02:45 +00:00
|
|
|
$r = new REST($apiList);
|
|
|
|
try {
|
|
|
|
$out = $r->apiMatch($input);
|
|
|
|
} catch (Exception501 $e) {
|
|
|
|
$out = [];
|
|
|
|
}
|
|
|
|
$this->assertEquals($exp, $out);
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideApiMatchData(): iterable {
|
2018-01-06 17:02:45 +00:00
|
|
|
$real = null;
|
|
|
|
$fake = [
|
|
|
|
'unstripped' => ['match' => "/full/url", 'strip' => "", 'class' => "UnstrippedProtocol"],
|
|
|
|
];
|
|
|
|
return [
|
2019-12-05 18:02:02 +00:00
|
|
|
[$real, "/index.php/apps/news/api/v1-2/feeds", ["ncn_v1-2", "/feeds", \JKingWeb\Arsse\REST\NextcloudNews\V1_2::class]],
|
|
|
|
[$real, "/index.php/apps/news/api/v1-2", ["ncn", "/v1-2", \JKingWeb\Arsse\REST\NextcloudNews\Versions::class]],
|
|
|
|
[$real, "/index.php/apps/news/api/", ["ncn", "/", \JKingWeb\Arsse\REST\NextcloudNews\Versions::class]],
|
|
|
|
[$real, "/index%2Ephp/apps/news/api/", ["ncn", "/", \JKingWeb\Arsse\REST\NextcloudNews\Versions::class]],
|
2018-01-06 17:02:45 +00:00
|
|
|
[$real, "/index.php/apps/news/", []],
|
|
|
|
[$real, "/index!php/apps/news/api/", []],
|
|
|
|
[$real, "/tt-rss/api/index.php", ["ttrss_api", "/index.php", \JKingWeb\Arsse\REST\TinyTinyRSS\API::class]],
|
|
|
|
[$real, "/tt-rss/api", ["ttrss_api", "", \JKingWeb\Arsse\REST\TinyTinyRSS\API::class]],
|
|
|
|
[$real, "/tt-rss/API", []],
|
|
|
|
[$real, "/tt-rss/api-bogus", []],
|
|
|
|
[$real, "/tt-rss/api bogus", []],
|
|
|
|
[$real, "/tt-rss/feed-icons/", ["ttrss_icon", "", \JKingWeb\Arsse\REST\TinyTinyRSS\Icon::class]],
|
|
|
|
[$real, "/tt-rss/feed-icons/", ["ttrss_icon", "", \JKingWeb\Arsse\REST\TinyTinyRSS\Icon::class]],
|
|
|
|
[$real, "/tt-rss/feed-icons", []],
|
|
|
|
[$fake, "/full/url/", ["unstripped", "/full/url/", "UnstrippedProtocol"]],
|
|
|
|
[$fake, "/full/url-not", []],
|
|
|
|
];
|
|
|
|
}
|
2018-10-26 18:58:04 +00:00
|
|
|
|
2018-01-11 20:48:29 +00:00
|
|
|
/** @dataProvider provideAuthenticableRequests */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testAuthenticateRequests(array $serverParams, array $expAttr): void {
|
2018-01-11 20:48:29 +00:00
|
|
|
$r = new REST();
|
|
|
|
// create a mock user manager
|
2019-09-05 14:03:32 +00:00
|
|
|
Arsse::$user = \Phake::mock(User::class);
|
|
|
|
\Phake::when(Arsse::$user)->auth->thenReturn(false);
|
|
|
|
\Phake::when(Arsse::$user)->auth("john.doe@example.com", "secret")->thenReturn(true);
|
|
|
|
\Phake::when(Arsse::$user)->auth("john.doe@example.com", "")->thenReturn(true);
|
|
|
|
\Phake::when(Arsse::$user)->auth("someone.else@example.com", "")->thenReturn(true);
|
2018-01-11 20:48:29 +00:00
|
|
|
// create an input server request
|
|
|
|
$req = new ServerRequest($serverParams);
|
|
|
|
// create the expected output
|
|
|
|
$exp = $req;
|
|
|
|
foreach ($expAttr as $key => $value) {
|
|
|
|
$exp = $exp->withAttribute($key, $value);
|
|
|
|
}
|
|
|
|
$act = $r->authenticateRequest($req);
|
|
|
|
$this->assertMessage($exp, $act);
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideAuthenticableRequests(): iterable {
|
2018-01-11 20:48:29 +00:00
|
|
|
return [
|
|
|
|
[['PHP_AUTH_USER' => "john.doe@example.com", 'PHP_AUTH_PW' => "secret"], ['authenticated' => true, 'authenticatedUser' => "john.doe@example.com"]],
|
|
|
|
[['PHP_AUTH_USER' => "john.doe@example.com", 'PHP_AUTH_PW' => "secret", 'REMOTE_USER' => "jane.doe@example.com"], ['authenticated' => true, 'authenticatedUser' => "john.doe@example.com"]],
|
2018-10-26 18:40:20 +00:00
|
|
|
[['PHP_AUTH_USER' => "jane.doe@example.com", 'PHP_AUTH_PW' => "secret"], ['authenticationFailed' => true]],
|
|
|
|
[['PHP_AUTH_USER' => "john.doe@example.com", 'PHP_AUTH_PW' => "superman"], ['authenticationFailed' => true]],
|
2018-01-11 20:48:29 +00:00
|
|
|
[['REMOTE_USER' => "john.doe@example.com"], ['authenticated' => true, 'authenticatedUser' => "john.doe@example.com"]],
|
|
|
|
[['REMOTE_USER' => "someone.else@example.com"], ['authenticated' => true, 'authenticatedUser' => "someone.else@example.com"]],
|
2018-10-26 18:40:20 +00:00
|
|
|
[['REMOTE_USER' => "jane.doe@example.com"], ['authenticationFailed' => true]],
|
|
|
|
[[], []],
|
2018-01-11 20:48:29 +00:00
|
|
|
];
|
|
|
|
}
|
2018-01-07 17:59:10 +00:00
|
|
|
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testSendAuthenticationChallenges(): void {
|
2018-11-23 00:55:54 +00:00
|
|
|
self::setConf();
|
2018-01-11 20:48:29 +00:00
|
|
|
$r = new REST();
|
|
|
|
$in = new EmptyResponse(401);
|
2019-09-27 21:16:34 +00:00
|
|
|
$exp = $in->withHeader("WWW-Authenticate", 'Basic realm="OOK", charset="UTF-8"');
|
2018-01-11 20:48:29 +00:00
|
|
|
$act = $r->challenge($in, "OOK");
|
|
|
|
$this->assertMessage($exp, $act);
|
2019-09-27 21:16:34 +00:00
|
|
|
$exp = $in->withHeader("WWW-Authenticate", 'Basic realm="'.Arsse::$conf->httpRealm.'", charset="UTF-8"');
|
2018-01-11 20:48:29 +00:00
|
|
|
$act = $r->challenge($in);
|
|
|
|
$this->assertMessage($exp, $act);
|
|
|
|
}
|
2018-10-26 18:58:04 +00:00
|
|
|
|
2018-01-09 17:31:40 +00:00
|
|
|
/** @dataProvider provideUnnormalizedOrigins */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testNormalizeOrigins(string $origin, string $exp, array $ports = null): void {
|
2018-01-09 17:31:40 +00:00
|
|
|
$r = new REST();
|
|
|
|
$act = $r->corsNormalizeOrigin($origin, $ports);
|
|
|
|
$this->assertSame($exp, $act);
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUnnormalizedOrigins(): iterable {
|
2018-01-09 17:31:40 +00:00
|
|
|
return [
|
|
|
|
["null", "null"],
|
|
|
|
["http://example.com", "http://example.com"],
|
|
|
|
["http://example.com:80", "http://example.com"],
|
|
|
|
["http://example.com:8%30", "http://example.com"],
|
|
|
|
["http://example.com:8080", "http://example.com:8080"],
|
|
|
|
["http://[2001:0db8:0:0:0:0:2:1]", "http://[2001:db8::2:1]"],
|
|
|
|
["http://example", "http://example"],
|
|
|
|
["http://ex%41mple", "http://example"],
|
|
|
|
["http://ex%41mple.co.uk", "http://example.co.uk"],
|
|
|
|
["http://ex%41mple.co%2euk", "http://example.co%2Euk"],
|
|
|
|
["http://example/", ""],
|
|
|
|
["http://example?", ""],
|
|
|
|
["http://example#", ""],
|
|
|
|
["http://user@example", ""],
|
|
|
|
["http://user:pass@example", ""],
|
|
|
|
["http://[example", ""],
|
|
|
|
["http://[2bef]", ""],
|
|
|
|
["http://example%2F", "http://example%2F"],
|
|
|
|
["HTTP://example", "http://example"],
|
|
|
|
["HTTP://EXAMPLE", "http://example"],
|
|
|
|
["%48%54%54%50://example", "http://example"],
|
|
|
|
["http:%2F%2Fexample", ""],
|
|
|
|
["https://example", "https://example"],
|
|
|
|
["https://example:443", "https://example"],
|
|
|
|
["https://example:80", "https://example:80"],
|
|
|
|
["ssh://example", "ssh://example"],
|
|
|
|
["ssh://example:22", "ssh://example:22"],
|
|
|
|
["ssh://example:22", "ssh://example", ['ssh' => 22]],
|
|
|
|
["SSH://example:22", "ssh://example", ['ssh' => 22]],
|
|
|
|
["ssh://example:22", "ssh://example", ['ssh' => "22"]],
|
|
|
|
["ssh://example:22", "ssh://example:22", ['SSH' => "22"]],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideCorsNegotiations */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testNegotiateCors($origin, bool $exp, string $allowed = null, string $denied = null): void {
|
2018-11-23 00:55:54 +00:00
|
|
|
self::setConf();
|
2019-09-05 14:03:32 +00:00
|
|
|
$r = \Phake::partialMock(REST::class);
|
|
|
|
\Phake::when($r)->corsNormalizeOrigin->thenReturnCallback(function($origin) {
|
2018-01-09 17:31:40 +00:00
|
|
|
return $origin;
|
|
|
|
});
|
2018-10-26 20:27:18 +00:00
|
|
|
$headers = isset($origin) ? ['Origin' => $origin] : [];
|
|
|
|
$req = new Request("", "GET", "php://memory", $headers);
|
2018-01-09 17:31:40 +00:00
|
|
|
$act = $r->corsNegotiate($req, $allowed, $denied);
|
|
|
|
$this->assertSame($exp, $act);
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideCorsNegotiations(): iterable {
|
2018-01-09 17:31:40 +00:00
|
|
|
return [
|
|
|
|
["http://example", true ],
|
|
|
|
["http://example", true, "http://example", "*" ],
|
|
|
|
["http://example", false, "http://example", "http://example"],
|
|
|
|
["http://example", false, "https://example", "*" ],
|
|
|
|
["http://example", false, "*", "*" ],
|
|
|
|
["http://example", true, "*", "" ],
|
|
|
|
["http://example", false, "", "" ],
|
|
|
|
["null", false ],
|
|
|
|
["null", true, "null", "*" ],
|
|
|
|
["null", false, "null", "null" ],
|
|
|
|
["null", false, "*", "*" ],
|
|
|
|
["null", false, "*", "" ],
|
|
|
|
["null", false, "", "" ],
|
|
|
|
["", false ],
|
|
|
|
["", false, "", "*" ],
|
|
|
|
["", false, "", "" ],
|
|
|
|
["", false, "*", "*" ],
|
|
|
|
["", false, "*", "" ],
|
|
|
|
[["null", "http://example"], false, "*", "" ],
|
2018-10-26 20:27:18 +00:00
|
|
|
[null, false, "*", "" ],
|
2018-01-09 17:31:40 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideCorsHeaders */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testAddCorsHeaders(string $reqMethod, array $reqHeaders, array $resHeaders, array $expHeaders): void {
|
2018-01-09 17:31:40 +00:00
|
|
|
$r = new REST();
|
|
|
|
$req = new Request("", $reqMethod, "php://memory", $reqHeaders);
|
|
|
|
$res = new EmptyResponse(204, $resHeaders);
|
|
|
|
$exp = new EmptyResponse(204, $expHeaders);
|
|
|
|
$act = $r->corsApply($res, $req);
|
2018-01-11 16:09:25 +00:00
|
|
|
$this->assertMessage($exp, $act);
|
2018-01-09 17:31:40 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideCorsHeaders(): iterable {
|
2018-01-09 17:31:40 +00:00
|
|
|
return [
|
|
|
|
["GET", ['Origin' => "null"], [], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "null",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["GET", ['Origin' => "http://example"], [], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["GET", ['Origin' => "http://example"], ['Content-Type' => "text/plain; charset=utf-8"], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Vary' => "Origin",
|
|
|
|
'Content-Type' => "text/plain; charset=utf-8",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["GET", ['Origin' => "http://example"], ['Vary' => "Content-Type"], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Vary' => ["Content-Type", "Origin"],
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["OPTIONS", ['Origin' => "http://example"], [], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["OPTIONS", ['Origin' => "http://example"], ['Allow' => "GET, PUT, HEAD, OPTIONS"], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Allow' => "GET, PUT, HEAD, OPTIONS",
|
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Methods' => "GET, PUT, HEAD, OPTIONS",
|
|
|
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => "Content-Type, If-None-Match"], [], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Headers' => "Content-Type, If-None-Match",
|
|
|
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => ["Content-Type", "If-None-Match"]], [], [
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Origin' => "http://example",
|
2018-01-09 17:31:40 +00:00
|
|
|
'Access-Control-Allow-Credentials' => "true",
|
2020-03-01 20:16:50 +00:00
|
|
|
'Access-Control-Allow-Headers' => "Content-Type,If-None-Match",
|
|
|
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
|
|
|
'Vary' => "Origin",
|
2018-01-09 17:31:40 +00:00
|
|
|
]],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2018-01-07 17:59:10 +00:00
|
|
|
/** @dataProvider provideUnnormalizedResponses */
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testNormalizeHttpResponses(ResponseInterface $res, ResponseInterface $exp, RequestInterface $req = null): void {
|
2019-09-05 14:03:32 +00:00
|
|
|
$r = \Phake::partialMock(REST::class);
|
|
|
|
\Phake::when($r)->corsNegotiate->thenReturn(true);
|
|
|
|
\Phake::when($r)->challenge->thenReturnCallback(function($res) {
|
2018-01-11 20:48:29 +00:00
|
|
|
return $res->withHeader("WWW-Authenticate", "Fake Value");
|
|
|
|
});
|
2019-09-05 14:03:32 +00:00
|
|
|
\Phake::when($r)->corsApply->thenReturnCallback(function($res) {
|
2018-01-09 17:31:40 +00:00
|
|
|
return $res;
|
|
|
|
});
|
2018-01-07 17:59:10 +00:00
|
|
|
$act = $r->normalizeResponse($res, $req);
|
2018-01-11 16:09:25 +00:00
|
|
|
$this->assertMessage($exp, $act);
|
2018-01-07 17:59:10 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideUnnormalizedResponses(): iterable {
|
2018-01-07 17:59:10 +00:00
|
|
|
$stream = fopen("php://memory", "w+b");
|
2018-01-12 14:48:33 +00:00
|
|
|
fwrite($stream, "ook");
|
2018-01-07 17:59:10 +00:00
|
|
|
return [
|
|
|
|
[new EmptyResponse(204), new EmptyResponse(204)],
|
2018-01-11 20:48:29 +00:00
|
|
|
[new EmptyResponse(401), new EmptyResponse(401, ['WWW-Authenticate' => "Fake Value"])],
|
2018-01-07 17:59:10 +00:00
|
|
|
[new EmptyResponse(204, ['Allow' => "PUT"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => "PUT,OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => ["PUT", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, DELETE, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => "HEAD,GET"]), new EmptyResponse(204, ['Allow' => "HEAD, GET, OPTIONS"])],
|
|
|
|
[new EmptyResponse(204, ['Allow' => "GET"]), new EmptyResponse(204, ['Allow' => "GET, HEAD, OPTIONS"])],
|
|
|
|
[new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])],
|
|
|
|
[new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])],
|
|
|
|
[new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])],
|
|
|
|
[new TextResponse("", 404), new TextResponse("", 404)],
|
|
|
|
[new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")],
|
|
|
|
[new Response($stream, 200), new EmptyResponse(200, ['Content-Length' => "3"]), new Request("", "HEAD")],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2020-01-20 18:52:48 +00:00
|
|
|
public function testCreateHandlers(): void {
|
2018-01-07 17:59:10 +00:00
|
|
|
$r = new REST();
|
|
|
|
foreach (REST::API_LIST as $api) {
|
|
|
|
$class = $api['class'];
|
|
|
|
$this->assertInstanceOf(Handler::class, $r->getHandler($class));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @dataProvider provideMockRequests */
|
2020-03-01 20:16:50 +00:00
|
|
|
public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target = ""): void {
|
2019-09-05 14:03:32 +00:00
|
|
|
$r = \Phake::partialMock(REST::class);
|
|
|
|
\Phake::when($r)->normalizeResponse->thenReturnCallback(function($res) {
|
2018-01-09 17:31:40 +00:00
|
|
|
return $res;
|
|
|
|
});
|
2019-09-05 14:03:32 +00:00
|
|
|
\Phake::when($r)->authenticateRequest->thenReturnCallback(function($req) {
|
2018-01-11 20:48:29 +00:00
|
|
|
return $req;
|
|
|
|
});
|
2018-01-07 17:59:10 +00:00
|
|
|
if ($called) {
|
2019-09-05 14:03:32 +00:00
|
|
|
$h = \Phake::mock($class);
|
|
|
|
\Phake::when($r)->getHandler($class)->thenReturn($h);
|
|
|
|
\Phake::when($h)->dispatch->thenReturn(new EmptyResponse(204));
|
2018-01-07 17:59:10 +00:00
|
|
|
}
|
|
|
|
$out = $r->dispatch($req);
|
|
|
|
$this->assertInstanceOf(ResponseInterface::class, $out);
|
|
|
|
if ($called) {
|
2019-09-05 14:03:32 +00:00
|
|
|
\Phake::verify($r)->authenticateRequest;
|
2019-09-05 14:13:17 +00:00
|
|
|
\Phake::verify($h)->dispatch(\Phake::capture($in));
|
2018-01-07 17:59:10 +00:00
|
|
|
$this->assertSame($method, $in->getMethod());
|
|
|
|
$this->assertSame($target, $in->getRequestTarget());
|
|
|
|
} else {
|
|
|
|
$this->assertSame(501, $out->getStatusCode());
|
|
|
|
}
|
2019-09-05 14:03:32 +00:00
|
|
|
\Phake::verify($r)->apiMatch;
|
|
|
|
\Phake::verify($r)->normalizeResponse;
|
2018-01-07 17:59:10 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 18:42:43 +00:00
|
|
|
public function provideMockRequests(): iterable {
|
2018-01-07 17:59:10 +00:00
|
|
|
return [
|
2018-01-12 14:48:33 +00:00
|
|
|
[new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "GET"), "GET", true, NCN::class, "/feeds"],
|
|
|
|
[new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "HEAD"), "GET", true, NCN::class, "/feeds"],
|
|
|
|
[new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "get"), "GET", true, NCN::class, "/feeds"],
|
|
|
|
[new ServerRequest([], [], "/index.php/apps/news/api/v1-2/feeds", "head"), "GET", true, NCN::class, "/feeds"],
|
|
|
|
[new ServerRequest([], [], "/tt-rss/api/", "POST"), "POST", true, TTRSS::class, "/"],
|
2018-01-07 17:59:10 +00:00
|
|
|
[new ServerRequest([], [], "/no/such/api/", "HEAD"), "GET", false],
|
|
|
|
[new ServerRequest([], [], "/no/such/api/", "GET"), "GET", false],
|
|
|
|
];
|
|
|
|
}
|
2018-01-12 14:48:33 +00:00
|
|
|
}
|