1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00

Complete testing of TTRSS handler

Also implemented OPTIONS handling for TTRSS; improves #107
This commit is contained in:
J. King 2017-11-23 18:07:56 -05:00
parent a61aa0a22c
commit b820a004d6
2 changed files with 62 additions and 22 deletions

View file

@ -109,26 +109,25 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
const FATAL_ERR = [ const FATAL_ERR = [
'seq' => null, 'seq' => null,
'status' => 1, 'status' => 1,
'content' => ['error' => "NOT_LOGGED_IN"], 'content' => ['error' => "MALFORMED_INPUT"],
]; ];
public function __construct() { public function __construct() {
} }
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response { public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
if ($req->method != "POST") { if ($req->method=="OPTIONS") {
// only POST requests are allowed // respond to OPTIONS rquests; the response is a fib, as we technically accept any type or method
return new Response(405, self::FATAL_ERR, "application/json", ["Allow: POST"]); return new Response(204, "", "", [
"Allow: POST",
"Accept: application/json, text/json",
]);
} }
if ($req->body) { if ($req->body) {
// only JSON entities are allowed // only JSON entities are allowed, but Content-Type is ignored, as is request method
if (!preg_match("<^application/json\b|^$>", $req->type)) {
return new Response(415, self::FATAL_ERR, "application/json", ['Accept: application/json']);
}
$data = @json_decode($req->body, true); $data = @json_decode($req->body, true);
if (json_last_error() != \JSON_ERROR_NONE || !is_array($data)) { if (json_last_error() != \JSON_ERROR_NONE || !is_array($data)) {
// non-JSON input indicates an error return new Response(200, self::FATAL_ERR);
return new Response(400, self::FATAL_ERR);
} }
try { try {
// normalize input // normalize input
@ -144,16 +143,8 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
} }
$method = "op".ucfirst($data['op']); $method = "op".ucfirst($data['op']);
if (!method_exists($this, $method)) { if (!method_exists($this, $method)) {
// because method names are supposed to be case insensitive, we need to try a bit harder to match // TT-RSS operations are case-insensitive by dint of PHP method names being case-insensitive; this will only trigger if the method really doesn't exist
$method = strtolower($method); throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]);
$map = get_class_methods($this);
$map = array_combine(array_map("strtolower", $map), $map);
if (!array_key_exists($method, $map)) {
// if the method really doesn't exist, throw an exception
throw new Exception("UNKNWON_METHOD", ['method' => $data['op']]);
}
// otherwise retrieve the correct camelCase and continue
$method = $map[$method];
} }
return new Response(200, [ return new Response(200, [
'seq' => $data['seq'], 'seq' => $data['seq'],
@ -171,7 +162,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
} }
} else { } else {
// absence of a request body indicates an error // absence of a request body indicates an error
return new Response(400, self::FATAL_ERR); return new Response(200, self::FATAL_ERR);
} }
} }
@ -1245,7 +1236,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
public function opGetHeadlines(array $data): array { public function opGetHeadlines(array $data): array {
// normalize input // normalize input
$data['limit'] = max(min(!$data['limit'] ? 200 : $data['limit'], 200), 0); // at most 200; not specified/zero yields 200; negative values yield no limit $data['limit'] = max(min(!$data['limit'] ? self::LIMIT_ARTICLES : $data['limit'], self::LIMIT_ARTICLES), 0); // at most 200; not specified/zero yields 200; negative values yield no limit
$tr = Arsse::$db->begin(); $tr = Arsse::$db->begin();
// retrieve the list of label names for the user // retrieve the list of label names for the user
$labels = []; $labels = [];

View file

@ -176,6 +176,20 @@ LONG_STRING;
$this->clearData(); $this->clearData();
} }
public function testHandleOptionsRequest() {
$exp = new Response(204, "", "", [
"Allow: POST",
"Accept: application/json, text/json",
]);
$this->assertEquals($exp, $this->h->dispatch(new Request("OPTIONS", "")));
}
public function testHandleInvalidData() {
$exp = $this->RESPERR("MALFORMED_INPUT");
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "", "This is not valid JSON data")));
$this->assertEquals($exp, $this->h->dispatch(new Request("POST", "", ""))); // lack of data is also an error
}
public function testLogIn() { public function testLogIn() {
Phake::when(Arsse::$user)->auth(Arsse::$user->id, "superman")->thenReturn(false); Phake::when(Arsse::$user)->auth(Arsse::$user->id, "superman")->thenReturn(false);
Phake::when(Arsse::$db)->sessionCreate->thenReturn("PriestsOfSyrinx")->thenReturn("SolarFederation"); Phake::when(Arsse::$db)->sessionCreate->thenReturn("PriestsOfSyrinx")->thenReturn("SolarFederation");
@ -196,6 +210,17 @@ LONG_STRING;
Phake::verify(Arsse::$db, Phake::times(0))->sessionResume($this->anything()); Phake::verify(Arsse::$db, Phake::times(0))->sessionResume($this->anything());
} }
public function testHandleGenericError() {
Phake::when(Arsse::$user)->auth(Arsse::$user->id, $this->anything())->thenThrow(new \JKingWeb\Arsse\Db\ExceptionTimeout("general"));
$data = [
'op' => "login",
'user' => Arsse::$user->id,
'password' => "secret",
];
$exp = new Response(500);
$this->assertEquals($exp, $this->req($data));
}
public function testLogOut() { public function testLogOut() {
Phake::when(Arsse::$db)->sessionDestroy->thenReturn(true); Phake::when(Arsse::$db)->sessionDestroy->thenReturn(true);
$data = [ $data = [
@ -219,6 +244,30 @@ LONG_STRING;
$this->assertEquals($exp, $this->req($data)); $this->assertEquals($exp, $this->req($data));
} }
public function testHandleUnknownMethods() {
$exp = $this->respErr("UNKNOWN_METHOD", ['method' => "thisMethodDoesNotExist"]);
$data = [
'op' => "thisMethodDoesNotExist",
'sid' => "PriestsOfSyrinx",
];
$this->assertEquals($exp, $this->req($data));
}
public function testHandleMixedCaseMethods() {
$data = [
'op' => "isLoggedIn",
'sid' => "PriestsOfSyrinx",
];
$exp = $this->respGood(['status' => true]);
$this->assertEquals($exp, $this->req($data));
$data['op'] = "isloggedin";
$this->assertEquals($exp, $this->req($data));
$data['op'] = "ISLOGGEDIN";
$this->assertEquals($exp, $this->req($data));
$data['op'] = "iSlOgGeDiN";
$this->assertEquals($exp, $this->req($data));
}
public function testRetrieveServerVersion() { public function testRetrieveServerVersion() {
$data = [ $data = [
'op' => "getVersion", 'op' => "getVersion",