J. King
4 years ago
13 changed files with 328 additions and 33 deletions
@ -0,0 +1,19 @@ |
|||||
|
<?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\REST\Miniflux; |
||||
|
|
||||
|
use JKingWeb\Arsse\Arsse; |
||||
|
|
||||
|
class ErrorResponse extends \Laminas\Diactoros\Response\JsonResponse { |
||||
|
public function __construct($data, int $status = 400, array $headers = [], int $encodingOptions = self::DEFAULT_JSON_FLAGS) { |
||||
|
assert(isset(Arsse::$lang) && Arsse::$lang instanceof \JKingWeb\Arsse\Lang, new \Exception("Language database must be initialized before use")); |
||||
|
$data = (array) $data; |
||||
|
$msg = array_shift($data); |
||||
|
$data = ["error_message" => Arsse::$lang->msg("API.Miniflux.Error.".$msg, $data)]; |
||||
|
parent::__construct($data, $status, $headers, $encodingOptions); |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
<?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\REST\Miniflux; |
||||
|
|
||||
|
use Psr\Http\Message\ServerRequestInterface; |
||||
|
use Psr\Http\Message\ResponseInterface; |
||||
|
use Laminas\Diactoros\Response\EmptyResponse; |
||||
|
use Laminas\Diactoros\Response\TextResponse; |
||||
|
|
||||
|
class Status extends \JKingWeb\Arsse\REST\AbstractHandler { |
||||
|
public function __construct() { |
||||
|
} |
||||
|
|
||||
|
public function dispatch(ServerRequestInterface $req): ResponseInterface { |
||||
|
$target = parse_url($req->getRequestTarget())['path'] ?? ""; |
||||
|
if (!in_array($target, ["/version", "/healthcheck"])) { |
||||
|
return new EmptyResponse(404); |
||||
|
} |
||||
|
$method = $req->getMethod(); |
||||
|
if ($method === "OPTIONS") { |
||||
|
return new EmptyResponse(204, ['Allow' => "HEAD, GET"]); |
||||
|
} elseif ($method !== "GET") { |
||||
|
return new EmptyResponse(405, ['Allow' => "HEAD, GET"]); |
||||
|
} |
||||
|
$out = ""; |
||||
|
if ($target === "/version") { |
||||
|
$out = V1::VERSION; |
||||
|
} elseif ($target === "/healthcheck") { |
||||
|
$out = "OK"; |
||||
|
} |
||||
|
return new TextResponse($out); |
||||
|
} |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
<?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\Miniflux; |
||||
|
|
||||
|
use JKingWeb\Arsse\REST\Miniflux\ErrorResponse; |
||||
|
|
||||
|
/** @covers \JKingWeb\Arsse\REST\Miniflux\ErrorResponse */ |
||||
|
class TestErrorResponse extends \JKingWeb\Arsse\Test\AbstractTest { |
||||
|
public function testCreateConstantResponse(): void { |
||||
|
$act = new ErrorResponse("401", 401); |
||||
|
$this->assertSame('{"error_message":"Access Unauthorized"}', (string) $act->getBody()); |
||||
|
} |
||||
|
|
||||
|
public function testCreateVariableResponse(): void { |
||||
|
$act = new ErrorResponse(["invalidBodyJSON", "Doh!"], 401); |
||||
|
$this->assertSame('{"error_message":"Invalid JSON payload: Doh!"}', (string) $act->getBody()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
<?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\Miniflux; |
||||
|
|
||||
|
use JKingWeb\Arsse\REST\Miniflux\Status; |
||||
|
use JKingWeb\Arsse\REST\Miniflux\V1; |
||||
|
use Psr\Http\Message\ResponseInterface; |
||||
|
use Laminas\Diactoros\Response\EmptyResponse; |
||||
|
use Laminas\Diactoros\Response\TextResponse; |
||||
|
|
||||
|
/** @covers \JKingWeb\Arsse\REST\Miniflux\Status */ |
||||
|
class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest { |
||||
|
/** @dataProvider provideRequests */ |
||||
|
public function testAnswerStatusRequests(string $url, string $method, ResponseInterface $exp): void { |
||||
|
$act = (new Status)->dispatch($this->serverRequest($method, $url, "")); |
||||
|
$this->assertMessage($exp, $act); |
||||
|
} |
||||
|
|
||||
|
public function provideRequests(): iterable { |
||||
|
return [ |
||||
|
["/version", "GET", new TextResponse(V1::VERSION)], |
||||
|
["/version", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], |
||||
|
["/version", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], |
||||
|
["/healthcheck", "GET", new TextResponse("OK")], |
||||
|
["/healthcheck", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], |
||||
|
["/healthcheck", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], |
||||
|
["/version/", "GET", new EmptyResponse(404)], |
||||
|
]; |
||||
|
} |
||||
|
} |
@ -0,0 +1,118 @@ |
|||||
|
<?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\NextcloudNews; |
||||
|
|
||||
|
use JKingWeb\Arsse\Arsse; |
||||
|
use JKingWeb\Arsse\User; |
||||
|
use JKingWeb\Arsse\Database; |
||||
|
use JKingWeb\Arsse\Db\Transaction; |
||||
|
use JKingWeb\Arsse\REST\Miniflux\V1; |
||||
|
use Psr\Http\Message\ResponseInterface; |
||||
|
|
||||
|
/** @covers \JKingWeb\Arsse\REST\Miniflux\V1<extended> */ |
||||
|
class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { |
||||
|
protected $h; |
||||
|
protected $transaction; |
||||
|
|
||||
|
protected function req(string $method, string $target, $data = "", array $headers = [], bool $authenticated = true, bool $body = true): ResponseInterface { |
||||
|
$prefix = "/v1"; |
||||
|
$url = $prefix.$target; |
||||
|
if ($body) { |
||||
|
$params = []; |
||||
|
} else { |
||||
|
$params = $data; |
||||
|
$data = []; |
||||
|
} |
||||
|
$req = $this->serverRequest($method, $url, $prefix, $headers, [], $data, "application/json", $params, $authenticated ? "john.doe@example.com" : ""); |
||||
|
return $this->h->dispatch($req); |
||||
|
} |
||||
|
|
||||
|
public function setUp(): void { |
||||
|
self::clearData(); |
||||
|
self::setConf(); |
||||
|
// create a mock user manager |
||||
|
Arsse::$user = \Phake::mock(User::class); |
||||
|
Arsse::$user->id = "john.doe@example.com"; |
||||
|
// create a mock database interface |
||||
|
Arsse::$db = \Phake::mock(Database::class); |
||||
|
$this->transaction = \Phake::mock(Transaction::class); |
||||
|
\Phake::when(Arsse::$db)->begin->thenReturn($this->transaction); |
||||
|
//initialize a handler |
||||
|
$this->h = new V1(); |
||||
|
} |
||||
|
|
||||
|
public function tearDown(): void { |
||||
|
self::clearData(); |
||||
|
} |
||||
|
|
||||
|
protected function v($value) { |
||||
|
return $value; |
||||
|
} |
||||
|
|
||||
|
public function testSendAuthenticationChallenge(): void { |
||||
|
$exp = new EmptyResponse(401); |
||||
|
$this->assertMessage($exp, $this->req("GET", "/", "", [], false)); |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideInvalidPaths */ |
||||
|
public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void { |
||||
|
$exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); |
||||
|
$this->assertMessage($exp, $this->req($method, $path)); |
||||
|
} |
||||
|
|
||||
|
public function provideInvalidPaths(): array { |
||||
|
return [ |
||||
|
["/", "GET", 404], |
||||
|
["/", "POST", 404], |
||||
|
["/", "PUT", 404], |
||||
|
["/", "DELETE", 404], |
||||
|
["/", "OPTIONS", 404], |
||||
|
["/version/invalid", "GET", 404], |
||||
|
["/version/invalid", "POST", 404], |
||||
|
["/version/invalid", "PUT", 404], |
||||
|
["/version/invalid", "DELETE", 404], |
||||
|
["/version/invalid", "OPTIONS", 404], |
||||
|
["/folders/1/invalid", "GET", 404], |
||||
|
["/folders/1/invalid", "POST", 404], |
||||
|
["/folders/1/invalid", "PUT", 404], |
||||
|
["/folders/1/invalid", "DELETE", 404], |
||||
|
["/folders/1/invalid", "OPTIONS", 404], |
||||
|
["/version", "POST", 405, "GET"], |
||||
|
["/version", "PUT", 405, "GET"], |
||||
|
["/version", "DELETE", 405, "GET"], |
||||
|
["/folders", "PUT", 405, "GET, POST"], |
||||
|
["/folders", "DELETE", 405, "GET, POST"], |
||||
|
["/folders/1", "GET", 405, "PUT, DELETE"], |
||||
|
["/folders/1", "POST", 405, "PUT, DELETE"], |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
public function testRespondToInvalidInputTypes(): void { |
||||
|
$exp = new EmptyResponse(415, ['Accept' => "application/json"]); |
||||
|
$this->assertMessage($exp, $this->req("PUT", "/folders/1", '<data/>', ['Content-Type' => "application/xml"])); |
||||
|
$exp = new EmptyResponse(400); |
||||
|
$this->assertMessage($exp, $this->req("PUT", "/folders/1", '<data/>')); |
||||
|
$this->assertMessage($exp, $this->req("PUT", "/folders/1", '<data/>', ['Content-Type' => null])); |
||||
|
} |
||||
|
|
||||
|
/** @dataProvider provideOptionsRequests */ |
||||
|
public function testRespondToOptionsRequests(string $url, string $allow, string $accept): void { |
||||
|
$exp = new EmptyResponse(204, [ |
||||
|
'Allow' => $allow, |
||||
|
'Accept' => $accept, |
||||
|
]); |
||||
|
$this->assertMessage($exp, $this->req("OPTIONS", $url)); |
||||
|
} |
||||
|
|
||||
|
public function provideOptionsRequests(): array { |
||||
|
return [ |
||||
|
["/feeds", "HEAD,GET,POST", "application/json"], |
||||
|
["/feeds/2112", "DELETE", "application/json"], |
||||
|
["/user", "HEAD,GET", "application/json"], |
||||
|
]; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue