mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Tests for sessions
This commit is contained in:
parent
b7ac63b9de
commit
91432d4e16
6 changed files with 163 additions and 4 deletions
|
@ -9,7 +9,7 @@ use JKingWeb\Arsse\Misc\Context;
|
||||||
use JKingWeb\Arsse\Misc\Date;
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
|
|
||||||
class Database {
|
class Database {
|
||||||
const SCHEMA_VERSION = 1;
|
const SCHEMA_VERSION = 2;
|
||||||
|
|
||||||
/** @var Db\Driver */
|
/** @var Db\Driver */
|
||||||
public $db;
|
public $db;
|
||||||
|
@ -267,7 +267,7 @@ class Database {
|
||||||
return $this->db->prepare("DELETE FROM arsse_sessions where expires < CURRENT_TIMESTAMP or created < ?", "datetime")->run($maxAge)->changes();
|
return $this->db->prepare("DELETE FROM arsse_sessions where expires < CURRENT_TIMESTAMP or created < ?", "datetime")->run($maxAge)->changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function sessionExpiringSoon(DateTimeInterface $expiry): bool {
|
protected function sessionExpiringSoon(\DateTimeInterface $expiry): bool {
|
||||||
// calculate half the session timeout as a number of seconds
|
// calculate half the session timeout as a number of seconds
|
||||||
$now = time();
|
$now = time();
|
||||||
$max = Date::add(Arsse::$conf->userSessionTimeout, $now)->getTimestamp();
|
$max = Date::add(Arsse::$conf->userSessionTimeout, $now)->getTimestamp();
|
||||||
|
|
|
@ -3,7 +3,7 @@ create table arsse_sessions (
|
||||||
id text primary key, -- UUID of session
|
id text primary key, -- UUID of session
|
||||||
created datetime not null default CURRENT_TIMESTAMP, -- Session start timestamp
|
created datetime not null default CURRENT_TIMESTAMP, -- Session start timestamp
|
||||||
expires datetime not null, -- Time at which session is no longer valid
|
expires datetime not null, -- Time at which session is no longer valid
|
||||||
user text not null references arsse_users(id) on delete cascade on update cascade, -- user associated with the session
|
user text not null references arsse_users(id) on delete cascade on update cascade -- user associated with the session
|
||||||
) without rowid;
|
) without rowid;
|
||||||
|
|
||||||
-- User-defined article labels for Tiny Tiny RSS
|
-- User-defined article labels for Tiny Tiny RSS
|
||||||
|
@ -26,4 +26,4 @@ create table arsse_label_members (
|
||||||
|
|
||||||
-- set version marker
|
-- set version marker
|
||||||
pragma user_version = 2;
|
pragma user_version = 2;
|
||||||
insert into arsse_meta(key,value) values('schema_version','2');
|
update arsse_meta set value = '2' where key is 'schema_version';
|
10
tests/Db/SQLite3/Database/TestDatabaseSessionSQLite3.php
Normal file
10
tests/Db/SQLite3/Database/TestDatabaseSessionSQLite3.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse;
|
||||||
|
|
||||||
|
/** @covers \JKingWeb\Arsse\Database<extended> */
|
||||||
|
class TestDatabaseSessionSQLite3 extends Test\AbstractTest {
|
||||||
|
use Test\Database\Setup;
|
||||||
|
use Test\Database\DriverSQLite3;
|
||||||
|
use Test\Database\SeriesSession;
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ trait SeriesCleanup {
|
||||||
$daybefore = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
$daybefore = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
||||||
$daysago = gmdate("Y-m-d H:i:s", strtotime("now - 7 days"));
|
$daysago = gmdate("Y-m-d H:i:s", strtotime("now - 7 days"));
|
||||||
$weeksago = gmdate("Y-m-d H:i:s", strtotime("now - 21 days"));
|
$weeksago = gmdate("Y-m-d H:i:s", strtotime("now - 21 days"));
|
||||||
|
$soon = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
||||||
|
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
||||||
$this->data = [
|
$this->data = [
|
||||||
'arsse_users' => [
|
'arsse_users' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -25,6 +27,21 @@ trait SeriesCleanup {
|
||||||
["john.doe@example.com", "", "John Doe"],
|
["john.doe@example.com", "", "John Doe"],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'arsse_sessions' => [
|
||||||
|
'columns' => [
|
||||||
|
'id' => "str",
|
||||||
|
'created' => "datetime",
|
||||||
|
'expires' => "datetime",
|
||||||
|
'user' => "str",
|
||||||
|
],
|
||||||
|
'rows' => [
|
||||||
|
["a", $nowish, $faroff, "jane.doe@example.com"], // not expired and recently created, thus kept
|
||||||
|
["b", $nowish, $soon, "jane.doe@example.com"], // not expired and recently created, thus kept
|
||||||
|
["c", $daysago, $soon, "jane.doe@example.com"], // created more than a day ago, thus deleted
|
||||||
|
["d", $nowish, $nowish, "jane.doe@example.com"], // recently created but expired, thus deleted
|
||||||
|
["e", $daysago, $nowish, "jane.doe@example.com"], // created more than a day ago and expired, thus deleted
|
||||||
|
],
|
||||||
|
],
|
||||||
'arsse_feeds' => [
|
'arsse_feeds' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'id' => "int",
|
'id' => "int",
|
||||||
|
@ -165,4 +182,16 @@ trait SeriesCleanup {
|
||||||
]);
|
]);
|
||||||
$this->compareExpectations($state);
|
$this->compareExpectations($state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCleanUpExpiredSessions() {
|
||||||
|
Arsse::$db->sessionCleanup();
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_sessions' => ["id"]
|
||||||
|
]);
|
||||||
|
foreach ([3,4,5] as $id) {
|
||||||
|
unset($state['arsse_sessions']['rows'][$id - 1]);
|
||||||
|
}
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
119
tests/lib/Database/SeriesSession.php
Normal file
119
tests/lib/Database/SeriesSession.php
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\Test\Database;
|
||||||
|
|
||||||
|
use JKingWeb\Arsse\Arsse;
|
||||||
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
|
use Phake;
|
||||||
|
|
||||||
|
trait SeriesSession {
|
||||||
|
|
||||||
|
public function setUpSeries() {
|
||||||
|
// set up the test data
|
||||||
|
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
||||||
|
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
||||||
|
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
||||||
|
$old = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
||||||
|
$this->data = [
|
||||||
|
'arsse_users' => [
|
||||||
|
'columns' => [
|
||||||
|
'id' => 'str',
|
||||||
|
'password' => 'str',
|
||||||
|
'name' => 'str',
|
||||||
|
],
|
||||||
|
'rows' => [
|
||||||
|
["jane.doe@example.com", "", "Jane Doe"],
|
||||||
|
["john.doe@example.com", "", "John Doe"],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'arsse_sessions' => [
|
||||||
|
'columns' => [
|
||||||
|
'id' => "str",
|
||||||
|
'user' => "str",
|
||||||
|
'created' => "datetime",
|
||||||
|
'expires' => "datetime",
|
||||||
|
],
|
||||||
|
'rows' => [
|
||||||
|
["80fa94c1a11f11e78667001e673b2560", "jane.doe@example.com", $past, $faroff],
|
||||||
|
["27c6de8da13311e78667001e673b2560", "jane.doe@example.com", $past, $past], // expired
|
||||||
|
["ab3b3eb8a13311e78667001e673b2560", "jane.doe@example.com", $old, $future], // too old
|
||||||
|
["da772f8fa13c11e78667001e673b2560", "john.doe@example.com", $past, $future],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResumeAValidSession() {
|
||||||
|
$exp1 = [
|
||||||
|
'id' => "80fa94c1a11f11e78667001e673b2560",
|
||||||
|
'user' => "jane.doe@example.com"
|
||||||
|
];
|
||||||
|
$exp2 = [
|
||||||
|
'id' => "da772f8fa13c11e78667001e673b2560",
|
||||||
|
'user' => "john.doe@example.com"
|
||||||
|
];
|
||||||
|
$this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560"));
|
||||||
|
$this->assertArraySubset($exp2, Arsse::$db->sessionResume("da772f8fa13c11e78667001e673b2560"));
|
||||||
|
$now = time();
|
||||||
|
// sessions near timeout should be refreshed automatically
|
||||||
|
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
|
||||||
|
$state['arsse_sessions']['rows'][3][2] = Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql");
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
// session resumption should not check authorization
|
||||||
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
|
$this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResumeAMissingSession() {
|
||||||
|
$this->assertException("invalid", "User", "ExceptionSession");
|
||||||
|
Arsse::$db->sessionResume("thisSessionDoesNotExist");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResumeAnExpiredSession() {
|
||||||
|
$this->assertException("invalid", "User", "ExceptionSession");
|
||||||
|
Arsse::$db->sessionResume("27c6de8da13311e78667001e673b2560");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testResumeAStaleSession() {
|
||||||
|
$this->assertException("invalid", "User", "ExceptionSession");
|
||||||
|
Arsse::$db->sessionResume("ab3b3eb8a13311e78667001e673b2560");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateASession() {
|
||||||
|
$user = "jane.doe@example.com";
|
||||||
|
$id = Arsse::$db->sessionCreate($user);
|
||||||
|
$now = time();
|
||||||
|
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
|
||||||
|
$state['arsse_sessions']['rows'][] = [$id, Date::transform($now, "sql"), Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql"), $user];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateASessionWithoutAuthority() {
|
||||||
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
Arsse::$db->sessionCreate("jane.doe@example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDestroyASession() {
|
||||||
|
$user = "jane.doe@example.com";
|
||||||
|
$id = "80fa94c1a11f11e78667001e673b2560";
|
||||||
|
$this->assertTrue(Arsse::$db->sessionDestroy($user, $id));
|
||||||
|
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
|
||||||
|
unset($state['arsse_sessions']['rows'][0]);
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
// destroying a session which does not exist is not an error
|
||||||
|
$this->assertFalse(Arsse::$db->sessionDestroy($user, $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDestroyASessionForTheWrongUser() {
|
||||||
|
$user = "john.doe@example.com";
|
||||||
|
$id = "80fa94c1a11f11e78667001e673b2560";
|
||||||
|
$this->assertFalse(Arsse::$db->sessionDestroy($user, $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDestroyASessionWithoutAuthority() {
|
||||||
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
Arsse::$db->sessionDestroy("jane.doe@example.com", "80fa94c1a11f11e78667001e673b2560");
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,7 @@
|
||||||
<file>Db/SQLite3/Database/TestDatabaseMiscellanySQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseMiscellanySQLite3.php</file>
|
||||||
<file>Db/SQLite3/Database/TestDatabaseMetaSQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseMetaSQLite3.php</file>
|
||||||
<file>Db/SQLite3/Database/TestDatabaseUserSQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseUserSQLite3.php</file>
|
||||||
|
<file>Db/SQLite3/Database/TestDatabaseSessionSQLite3.php</file>
|
||||||
<file>Db/SQLite3/Database/TestDatabaseFolderSQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseFolderSQLite3.php</file>
|
||||||
<file>Db/SQLite3/Database/TestDatabaseFeedSQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseFeedSQLite3.php</file>
|
||||||
<file>Db/SQLite3/Database/TestDatabaseSubscriptionSQLite3.php</file>
|
<file>Db/SQLite3/Database/TestDatabaseSubscriptionSQLite3.php</file>
|
||||||
|
|
Loading…
Reference in a new issue