From 8adeed434d61255f068a1f16e5f310a932447587 Mon Sep 17 00:00:00 2001 From: dakriy Date: Fri, 10 Apr 2020 18:51:17 -0700 Subject: [PATCH] Use database transactions to make tests faster and add last_seen_at for doors --- src/web/backend/app/Door.php | 4 ++- .../2020_01_10_081002_create_doors_table.php | 1 + src/web/backend/src/Entities/Door.php | 18 +++++++++- .../Doors/DatabaseDoorsRepository.php | 14 +++++--- .../Doors/InMemoryDoorsRepository.php | 1 + .../backend/src/UseCases/BasePresenter.php | 1 + .../Door/Authenticate/Authenticate.php | 6 +--- .../tests/Database/DoorDatabaseTest.php | 6 +++- .../tests/Database/DoorUserDatabaseTest.php | 22 ++++++------ .../tests/Database/GroupDatabaseTest.php | 23 ++++++------- .../tests/Database/GroupUserDatabaseTest.php | 34 ++++++++++++------- .../tests/Database/TokenDatabaseTest.php | 18 ++++++---- .../tests/Database/UserDatabaseTest.php | 28 +++++++-------- src/web/backend/tests/DatabaseTestCase.php | 4 +-- .../UseCases/Doors/GetDoor/PresenterTest.php | 2 ++ 15 files changed, 112 insertions(+), 70 deletions(-) diff --git a/src/web/backend/app/Door.php b/src/web/backend/app/Door.php index c0232adb..aef0c4a4 100644 --- a/src/web/backend/app/Door.php +++ b/src/web/backend/app/Door.php @@ -8,7 +8,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Door extends Authenticatable { - protected $fillable = ['id', 'name', 'location', 'created_at', 'updated_at']; + protected $fillable = ['id', 'name', 'location', 'created_at', 'updated_at', 'last_seen_at']; + + protected $dates = ['last_seen_at']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany diff --git a/src/web/backend/database/migrations/2020_01_10_081002_create_doors_table.php b/src/web/backend/database/migrations/2020_01_10_081002_create_doors_table.php index 49263c11..19e96c53 100644 --- a/src/web/backend/database/migrations/2020_01_10_081002_create_doors_table.php +++ b/src/web/backend/database/migrations/2020_01_10_081002_create_doors_table.php @@ -21,6 +21,7 @@ class CreateDoorsTable extends Migration // hashed $table->string('api_token')->unique(); $table->timestamps(); + $table->timestamp('last_seen_at')->nullable(); }); } diff --git a/src/web/backend/src/Entities/Door.php b/src/web/backend/src/Entities/Door.php index 1d20a029..9817d5b5 100644 --- a/src/web/backend/src/Entities/Door.php +++ b/src/web/backend/src/Entities/Door.php @@ -37,6 +37,11 @@ class Door */ protected ?Carbon $updatedAt; + /** + * @var \Carbon\Carbon|null + */ + protected ?Carbon $lastSeenAt; + /** * @param int $id * @param string $location @@ -44,6 +49,7 @@ class Door * @param \Source\Entities\HashedSearchable $token * @param Carbon|null $createdAt * @param Carbon|null $updatedAt + * @param \Carbon\Carbon|null $lastSeenAt */ public function __construct( int $id, @@ -51,7 +57,8 @@ class Door string $name, HashedSearchable $token, ?Carbon $createdAt = null, - ?Carbon $updatedAt = null + ?Carbon $updatedAt = null, + ?Carbon $lastSeenAt = null ) { $this->id = $id; $this->location = $location; @@ -59,6 +66,7 @@ class Door $this->token = $token; $this->createdAt = $createdAt; $this->updatedAt = $updatedAt; + $this->lastSeenAt = $lastSeenAt; } /** @@ -101,6 +109,14 @@ class Door return $this->updatedAt; } + /** + * @return \Carbon\Carbon|null + */ + public function getLastSeenAt(): ?Carbon + { + return $this->lastSeenAt; + } + /** * @param \Source\Entities\HashedSearchable|null $token * @return bool diff --git a/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php b/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php index dcfb62bf..e5b6bd98 100644 --- a/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/DatabaseDoorsRepository.php @@ -3,6 +3,7 @@ namespace Source\Gateways\Doors; +use Carbon\Carbon; use Source\Entities\Door; use Source\Sanitize\CastsTo; use Source\Entities\HashedSearchable; @@ -42,7 +43,8 @@ class DatabaseDoorsRepository implements DoorsRepository $door->name, new HashedSearchable($door->api_token), $door->created_at, - $door->updated_at + $door->updated_at, + $door->last_seen_at ); } @@ -55,13 +57,17 @@ class DatabaseDoorsRepository implements DoorsRepository return null; } - $dbDoor = \App\Door::where('api_token', $token->getHash())->first(); + $door = \App\Door::where('api_token', $token->getHash())->first(); - if (!$dbDoor) { + if (!$door) { return null; } - return self::makeDoorFromDb($dbDoor); + // Anytime a door is matched update last_seen_at + $door->last_seen_at = Carbon::now(); + $door->save(); + + return self::makeDoorFromDb($door); } /** diff --git a/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php b/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php index f56799f1..096f0adb 100644 --- a/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php +++ b/src/web/backend/src/Gateways/Doors/InMemoryDoorsRepository.php @@ -3,6 +3,7 @@ namespace Source\Gateways\Doors; +use Carbon\Carbon; use Source\Entities\Door; use Source\Entities\HashedSearchable; use Source\Exceptions\EntityExistsException; diff --git a/src/web/backend/src/UseCases/BasePresenter.php b/src/web/backend/src/UseCases/BasePresenter.php index cb708553..6fe2e459 100644 --- a/src/web/backend/src/UseCases/BasePresenter.php +++ b/src/web/backend/src/UseCases/BasePresenter.php @@ -98,6 +98,7 @@ abstract class BasePresenter 'location' => $door->getLocation(), 'created_at' => $this->formatDateTime($door->getCreatedAt()), 'updated_at' => $this->formatDateTime($door->getUpdatedAt()), + 'last_seen_at' => $this->formatDateTime($door->getLastSeenAt()), ]; } diff --git a/src/web/backend/src/UseCases/Door/Authenticate/Authenticate.php b/src/web/backend/src/UseCases/Door/Authenticate/Authenticate.php index aa60e340..7a052f68 100644 --- a/src/web/backend/src/UseCases/Door/Authenticate/Authenticate.php +++ b/src/web/backend/src/UseCases/Door/Authenticate/Authenticate.php @@ -25,11 +25,7 @@ class Authenticate implements AuthenticateUseCase */ public function check(Presenter $presenter, string $salt, ?string $token): void { - $found = null; - - if ($token) { - $found = $this->doors->getByToken(HashedSearchable::hash($salt, $token)); - } + $found = $this->doors->getByToken(HashedSearchable::hash($salt, $token)); $response = new ResponseModel(); diff --git a/src/web/backend/tests/Database/DoorDatabaseTest.php b/src/web/backend/tests/Database/DoorDatabaseTest.php index aaecfe29..b209656c 100644 --- a/src/web/backend/tests/Database/DoorDatabaseTest.php +++ b/src/web/backend/tests/Database/DoorDatabaseTest.php @@ -27,7 +27,11 @@ class DoorDatabaseTest extends DatabaseTestCase { $door = $this->doors->create(new Door(0, 'loc', 'name', new HashedSearchable('token'))); - $this->assertEquals($door, $this->doors->getByToken(new HashedSearchable('token'))); + $found = $this->doors->getByToken(new HashedSearchable('token')); + + $this->assertEquals('loc', $found->getLocation()); + $this->assertEquals('name', $found->getName()); + $this->assertNotNull($found->getLastSeenAt()); $this->assertNull($this->doors->getByToken(new HashedSearchable('i am autistic'))); } diff --git a/src/web/backend/tests/Database/DoorUserDatabaseTest.php b/src/web/backend/tests/Database/DoorUserDatabaseTest.php index 13999280..6d57b117 100644 --- a/src/web/backend/tests/Database/DoorUserDatabaseTest.php +++ b/src/web/backend/tests/Database/DoorUserDatabaseTest.php @@ -74,25 +74,25 @@ class DoorUserDatabaseTest extends DatabaseTestCase */ public function it_selects_the_group_intersection_of_doors_and_users(): void { - $this->groups->create(new Group( + $g1 = $this->groups->create(new Group( 0, 'title', 'description' )); - $this->groups->create(new Group( + $g2 = $this->groups->create(new Group( 0, 'title2', 'description2' )); - $this->users->create(new User( + $u1 = $this->users->create(new User( 0, 'first', 'last', 'display', 'email' )); - $this->users->create(new User( + $u2 = $this->users->create(new User( 0, 'first2', 'last2', @@ -100,24 +100,24 @@ class DoorUserDatabaseTest extends DatabaseTestCase 'email2' )); - $this->doors->create(new Door( + $d1 = $this->doors->create(new Door( 0, 'location', 'name', new HashedSearchable('hash') )); - $this->doors->create(new Door( + $d2 = $this->doors->create(new Door( 0, 'location2', 'name2', new HashedSearchable('hash2') )); - $this->doorGroups->addDoorToGroup(1, 1); - $this->doorGroups->addDoorToGroup(2, 2); - $this->groupUsers->addUserToGroup(1, 1); - $this->groupUsers->addUserToGroup(2, 2); + $this->doorGroups->addDoorToGroup($d1->getId(), $g1->getId()); + $this->doorGroups->addDoorToGroup($d2->getId(), $g2->getId()); + $this->groupUsers->addUserToGroup($u1->getId(), $g1->getId()); + $this->groupUsers->addUserToGroup($u1->getId(), $g2->getId()); - $groups = $this->db->getDoorUserGroupIntersection('1', '1'); + $groups = $this->db->getDoorUserGroupIntersection($d1->getId(), $u1->getId()); $this->assertCount(1, $groups); $this->assertEquals('title', $groups[0]->getTitle()); $this->assertEquals('description', $groups[0]->getDescription()); diff --git a/src/web/backend/tests/Database/GroupDatabaseTest.php b/src/web/backend/tests/Database/GroupDatabaseTest.php index ba5ada3e..d24e801c 100644 --- a/src/web/backend/tests/Database/GroupDatabaseTest.php +++ b/src/web/backend/tests/Database/GroupDatabaseTest.php @@ -49,7 +49,7 @@ class GroupDatabaseTest extends DatabaseTestCase $group = $this->groups->create(new Group(0, '', '')); - $this->assertEquals($group, $this->groups->get(1)); + $this->assertEquals($group, $this->groups->get($group->getId())); } /** @@ -67,7 +67,7 @@ class GroupDatabaseTest extends DatabaseTestCase { $group = $this->groups->create(new Group(0, '', '')); - $this->assertEquals($group, $this->groups->get(1)); + $this->assertEquals($group, $this->groups->get($group->getId())); } /** @@ -75,11 +75,11 @@ class GroupDatabaseTest extends DatabaseTestCase */ public function it_deletes_a_group(): void { - $this->groups->create(new Group(0, '', '')); + $group = $this->groups->create(new Group(0, '', '')); - $this->assertTrue($this->groups->delete(1)); + $this->assertTrue($this->groups->delete($group->getId())); - $this->assertFalse($this->groups->exists(new Group(2, '', ''))); + $this->assertFalse($this->groups->exists(new Group(9999999, '', ''))); $this->assertFalse($this->groups->delete(2)); @@ -91,11 +91,10 @@ class GroupDatabaseTest extends DatabaseTestCase */ public function it_checks_existence_of_groups(): void { - $this->groups->create(new Group(0, '', '')); + $g = $this->groups->create(new Group(0, '', '')); - $this->assertTrue($this->groups->exists(new Group(1, 'asdf', 'asdf'))); - $this->assertFalse($this->groups->exists(new Group(2, 'asdf', 'asdf'))); - $this->assertTrue($this->groups->exists(new Group(3, '', ''))); + $this->assertFalse($this->groups->exists(new Group(0, 'asdf', 'asdf'))); + $this->assertTrue($this->groups->exists(new Group(0, '', ''))); } /** @@ -103,11 +102,11 @@ class GroupDatabaseTest extends DatabaseTestCase */ public function it_updates_a_group(): void { - $this->groups->create(new Group(0, 'title', 'description')); + $g = $this->groups->create(new Group(0, 'title', 'description')); - $this->groups->update(1, new Group(0, 'new title', 'new desc')); + $this->groups->update($g->getId(), new Group(0, 'new title', 'new desc')); - $group = $this->groups->get(1); + $group = $this->groups->get($g->getId()); $this->assertEquals('new title', $group->getTitle()); $this->assertEquals('new desc', $group->getDescription()); diff --git a/src/web/backend/tests/Database/GroupUserDatabaseTest.php b/src/web/backend/tests/Database/GroupUserDatabaseTest.php index 9631fd16..452c260f 100644 --- a/src/web/backend/tests/Database/GroupUserDatabaseTest.php +++ b/src/web/backend/tests/Database/GroupUserDatabaseTest.php @@ -28,6 +28,16 @@ class GroupUserDatabaseTest extends DatabaseTestCase */ protected DatabaseGroupUserRepository $groupUsers; + /** + * @var \Source\Entities\User|null + */ + protected User $user; + + /** + * @var \Source\Entities\Group + */ + protected Group $group; + public function setUp(): void { parent::setUp(); @@ -35,8 +45,8 @@ class GroupUserDatabaseTest extends DatabaseTestCase $this->users = new DatabaseUsersRepository(); $this->groups = new DatabaseGroupsRepository(); $this->groupUsers = new DatabaseGroupUserRepository(); - $this->users->create(new User(0, '', '', '', '', null, null, null)); - $this->groups->create(new Group(0, '', '')); + $this->user = $this->users->create(new User(0, '', '', '', '', null, null, null)); + $this->group = $this->groups->create(new Group(0, '', '')); } /** @@ -69,7 +79,7 @@ class GroupUserDatabaseTest extends DatabaseTestCase { $this->expectException(EntityNotFoundException::class); - $this->groupUsers->addUserToGroup('1', 'ree'); + $this->groupUsers->addUserToGroup($this->user->getId(), 'ree'); } /** @@ -80,7 +90,7 @@ class GroupUserDatabaseTest extends DatabaseTestCase { $this->expectException(EntityNotFoundException::class); - $this->groupUsers->addUserToGroup('re', '1'); + $this->groupUsers->addUserToGroup('re', $this->group->getId()); } @@ -92,7 +102,7 @@ class GroupUserDatabaseTest extends DatabaseTestCase { $this->expectException(EntityNotFoundException::class); - $this->groupUsers->removeUserFromGroup('1', 'ree'); + $this->groupUsers->removeUserFromGroup($this->user->getId(), 'ree'); } /** @@ -103,7 +113,7 @@ class GroupUserDatabaseTest extends DatabaseTestCase { $this->expectException(EntityNotFoundException::class); - $this->groupUsers->removeUserFromGroup('re', '1'); + $this->groupUsers->removeUserFromGroup('re', $this->group->getId()); } /** @@ -112,13 +122,13 @@ class GroupUserDatabaseTest extends DatabaseTestCase */ public function it_can_add_remove_and_get_groups_for_users(): void { - $this->groupUsers->addUserToGroup('1', '1'); + $this->groupUsers->addUserToGroup($this->user->getId(), $this->group->getId()); - $this->assertCount(1, $this->groupUsers->getGroupsForUser('1')); + $this->assertCount(1, $this->groupUsers->getGroupsForUser($this->user->getId())); - $this->groupUsers->removeUserFromGroup('1', '1'); + $this->groupUsers->removeUserFromGroup($this->user->getId(), $this->group->getId()); - $this->assertCount(0, $this->groupUsers->getGroupsForUser('1')); + $this->assertCount(0, $this->groupUsers->getGroupsForUser($this->user->getId())); } /** @@ -127,8 +137,8 @@ class GroupUserDatabaseTest extends DatabaseTestCase */ public function it_can_get_users_for_a_group(): void { - $this->groupUsers->addUserToGroup('1', '1'); + $this->groupUsers->addUserToGroup($this->user->getId(), $this->group->getId()); - $this->assertCount(1, $this->groupUsers->getUsersForGroup('1')); + $this->assertCount(1, $this->groupUsers->getUsersForGroup($this->group->getId())); } } diff --git a/src/web/backend/tests/Database/TokenDatabaseTest.php b/src/web/backend/tests/Database/TokenDatabaseTest.php index fc47909e..84b14eba 100644 --- a/src/web/backend/tests/Database/TokenDatabaseTest.php +++ b/src/web/backend/tests/Database/TokenDatabaseTest.php @@ -23,13 +23,18 @@ class TokenDatabaseTest extends DatabaseTestCase */ protected DatabaseUsersRepository $users; + /** + * @var \Source\Entities\User + */ + protected User $user; + public function setUp(): void { parent::setUp(); $this->tokens = new DatabaseTokensRepository(); $this->users = new DatabaseUsersRepository(); - $this->users->create(new User(0, '', '', '', '', null, null, null)); + $this->user = $this->users->create(new User(0, '', '', '', '', null, null, null)); } /** @@ -38,12 +43,11 @@ class TokenDatabaseTest extends DatabaseTestCase */ public function it_creates_and_finds_tokens(): void { - $token = $this->tokens->create(new Token(0, 1, 'token')); + $token = $this->tokens->create(new Token(0, $this->user->getId(), 'token')); $dbToken = $this->tokens->findValidToken('token'); $this->assertEquals($token, $dbToken); - $this->assertEquals(1, $dbToken->getUserId()); $nullToken = $this->tokens->findValidToken('reeee'); @@ -56,7 +60,7 @@ class TokenDatabaseTest extends DatabaseTestCase */ public function it_cannot_find_expired_tokens(): void { - $this->tokens->create(new Token(0, 1, 'token', 'nomen', Carbon::now()->subDays(1))); + $this->tokens->create(new Token(0, $this->user->getId(), 'token', 'nomen', Carbon::now()->subDays(1))); $token = $this->tokens->findValidToken('token'); @@ -69,7 +73,7 @@ class TokenDatabaseTest extends DatabaseTestCase */ public function it_can_find_tokens_with_an_expired_date_in_the_future(): void { - $t = $this->tokens->create(new Token(0, 1, 'token', 'nomen', Carbon::now()->addDays(1))); + $t = $this->tokens->create(new Token(0, $this->user->getId(), 'token', 'nomen', Carbon::now()->addDays(1))); $token = $this->tokens->findValidToken('token'); @@ -84,7 +88,7 @@ class TokenDatabaseTest extends DatabaseTestCase { $this->expectException(EntityNotFoundException::class); - $this->tokens->create(new Token(0, 500, 'token')); + $this->tokens->create(new Token(0, 999999, 'token')); } /** @@ -93,7 +97,7 @@ class TokenDatabaseTest extends DatabaseTestCase */ public function it_invalidates_tokens(): void { - $this->tokens->create(new Token(0, 1, 'token', 'nomen', Carbon::now()->addDays(1))); + $this->tokens->create(new Token(0, $this->user->getId(), 'token', 'nomen', Carbon::now()->addDays(1))); $this->tokens->invalidateToken('token'); diff --git a/src/web/backend/tests/Database/UserDatabaseTest.php b/src/web/backend/tests/Database/UserDatabaseTest.php index 3db7357e..46f12893 100644 --- a/src/web/backend/tests/Database/UserDatabaseTest.php +++ b/src/web/backend/tests/Database/UserDatabaseTest.php @@ -61,9 +61,9 @@ class UserDatabaseTest extends DatabaseTestCase { $user = $this->users->create($this->createUser()); - $this->assertEquals($this->users->get(1), $user); + $this->assertEquals($user, $this->users->get($user->getId())); - $user = $this->users->get(1); + $user = $this->users->get($user->getId()); $this->assertEquals('doorcode', $user->getDoorcode()->getHash()); $this->assertEquals('password', $user->getPassword()->getHash()); @@ -75,7 +75,7 @@ class UserDatabaseTest extends DatabaseTestCase $user = $this->users->create($this->createUser()); // Test that it won't change password and doorcode if they are equal to whats in DB - $this->users->update(1, new User( + $this->users->update($user->getId(), new User( 0, 'new first', 'new last', @@ -86,7 +86,7 @@ class UserDatabaseTest extends DatabaseTestCase $user->getDoorcode() )); - $user = $this->users->get(1); + $user = $this->users->get($user->getId()); $this->assertEquals('password', $user->getPassword()->getHash()); $this->assertEquals('doorcode', $user->getDoorcode()->getHash()); @@ -99,7 +99,7 @@ class UserDatabaseTest extends DatabaseTestCase // Test that it will change password and doorcode if they are not equal to whats in DB - $this->users->update(1, new User( + $this->users->update($user->getId(), new User( 0, 'new first', 'new last', @@ -110,7 +110,7 @@ class UserDatabaseTest extends DatabaseTestCase new HashedSearchable('new') )); - $user = $this->users->get(1); + $user = $this->users->get($user->getId()); $this->assertEquals('new', $user->getDoorcode()->getHash()); $this->assertEquals('new', $user->getPassword()->getHash()); @@ -133,13 +133,13 @@ class UserDatabaseTest extends DatabaseTestCase */ public function it_deletes_a_user(): void { - $this->users->create($this->createUser()); + $user = $this->users->create($this->createUser()); - $this->assertTrue($this->users->delete(1)); + $this->assertTrue($this->users->delete($user->getId())); - $this->assertFalse($this->users->exists(1)); + $this->assertFalse($this->users->exists($user->getId())); - $this->assertFalse($this->users->delete(2)); + $this->assertFalse($this->users->delete(9999999)); $this->assertFalse($this->users->delete('asdf')); } @@ -151,7 +151,7 @@ class UserDatabaseTest extends DatabaseTestCase { $user = $this->users->create($this->createUser()); - $userToCompare = $this->users->get(1); + $userToCompare = $this->users->get($user->getId()); $this->assertEquals($user, $userToCompare); } @@ -169,10 +169,10 @@ class UserDatabaseTest extends DatabaseTestCase */ public function it_checks_existence_of_users(): void { - $this->users->create($this->createUser()); + $user = $this->users->create($this->createUser()); - $this->assertTrue($this->users->exists(1)); - $this->assertFalse($this->users->exists(2)); + $this->assertTrue($this->users->exists($user->getId())); + $this->assertFalse($this->users->exists(999999)); $this->assertFalse($this->users->exists('asdf')); } diff --git a/src/web/backend/tests/DatabaseTestCase.php b/src/web/backend/tests/DatabaseTestCase.php index 63a13830..829e1d0a 100644 --- a/src/web/backend/tests/DatabaseTestCase.php +++ b/src/web/backend/tests/DatabaseTestCase.php @@ -2,9 +2,9 @@ namespace Tests; -use Illuminate\Foundation\Testing\DatabaseMigrations; +use Illuminate\Foundation\Testing\RefreshDatabase; abstract class DatabaseTestCase extends TestCase { - use DatabaseMigrations; + use RefreshDatabase; } diff --git a/src/web/backend/tests/Unit/Source/UseCases/Doors/GetDoor/PresenterTest.php b/src/web/backend/tests/Unit/Source/UseCases/Doors/GetDoor/PresenterTest.php index 46beb49f..93cf2b01 100644 --- a/src/web/backend/tests/Unit/Source/UseCases/Doors/GetDoor/PresenterTest.php +++ b/src/web/backend/tests/Unit/Source/UseCases/Doors/GetDoor/PresenterTest.php @@ -56,6 +56,7 @@ class PresenterTest extends TestCase new HashedSearchable('how are you'), new Carbon('2020-03-11 00:49:25'), new Carbon('2020-03-11 00:49:29'), + new Carbon('2020-04-10 18:49:00') )); $this->assertEquals([ @@ -64,6 +65,7 @@ class PresenterTest extends TestCase 'name' => 'nameeee yee haw', 'created_at' => '2020-03-11T00:49:25+00:00', 'updated_at' => '2020-03-11T00:49:29+00:00', + 'last_seen_at' => '2020-04-10T18:49:00+00:00', ], $this->response['door']); } } -- GitLab