diff --git a/src/ConcurrentAssignmentsStorageDecorator.php b/src/ConcurrentAssignmentsStorageDecorator.php index b8d3490..7528ac6 100644 --- a/src/ConcurrentAssignmentsStorageDecorator.php +++ b/src/ConcurrentAssignmentsStorageDecorator.php @@ -71,6 +71,7 @@ public function add(Assignment $assignment): void { $this->load(); $this->storage->add($assignment); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function hasItem(string $name): bool @@ -84,38 +85,38 @@ public function renameItem(string $oldName, string $newName): void { $this->load(); $this->storage->renameItem($oldName, $newName); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function remove(string $itemName, string $userId): void { $this->load(); $this->storage->remove($itemName, $userId); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function removeByUserId(string $userId): void { $this->load(); $this->storage->removeByUserId($userId); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function removeByItemName(string $itemName): void { $this->load(); $this->storage->removeByItemName($itemName); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function clear(): void { $this->storage->clear(); + $this->currentFileUpdatedAt = $this->getFileUpdatedAt(); } public function load(): void { $this->loadInternal($this->storage); } - - public function getFileUpdatedAt(): int - { - return $this->storage->getFileUpdatedAt(); - } } diff --git a/tests/AssignmentsStorageTest.php b/tests/AssignmentsStorageTest.php new file mode 100644 index 0000000..e9f1e7d --- /dev/null +++ b/tests/AssignmentsStorageTest.php @@ -0,0 +1,170 @@ +traitSetUp(); + } + + protected function tearDown(): void + { + $this->clearFixturesFiles(); + } + + public function testGetAllWithConcurrency(): void + { + $this->assertNotEmpty($this->getEmptyConcurrentAssignmentsStorage()->getAll()); + } + + public function testGetByUserIdWithConcurrency(): void + { + $this->assertNotEmpty($this->getEmptyConcurrentAssignmentsStorage()->getByUserId('john')); + } + + public function testGetByItemNamesWithConcurrency(): void + { + $this->assertNotEmpty($this->getEmptyConcurrentAssignmentsStorage()->getByItemNames(['Researcher'])); + } + + public function testGetWithConcurrency(): void + { + $this->assertNotEmpty($this->getEmptyConcurrentAssignmentsStorage()->get(itemName: 'Researcher', userId: 'john')); + } + + public function testExistsWithConcurrency(): void + { + $this->assertTrue( + $this->getEmptyConcurrentAssignmentsStorage()->exists(itemName: 'Researcher', userId: 'john'), + ); + } + + public function testUserHasItemWithConcurrency(): void + { + $this->assertTrue( + $this->getEmptyConcurrentAssignmentsStorage()->userHasItem(userId: 'john', itemNames: ['Researcher']), + ); + } + + public function testFilterUserItemNamesWithConcurrency(): void + { + $this->assertNotEmpty( + $this->getEmptyConcurrentAssignmentsStorage()->filterUserItemNames( + userId: 'john', + itemNames: ['Researcher'], + ), + ); + } + + public function testAddWithConcurrency(): void + { + $testStorage = new AssignmentsStorage($this->getDataPath()); + $actionStorage = $this->getAssignmentsStorage(); + + $time = time(); + $actionStorage->add(new Assignment(userId: 'jack', itemName: 'Researcher', createdAt: $time)); + $count = count($actionStorage->getByItemNames(['Researcher'])); + $actionStorage->add(new Assignment(userId: 'jeff', itemName: 'Researcher', createdAt: $time)); + + $testStorage->add(new Assignment(userId: 'jack', itemName: 'Researcher', createdAt: $time)); + $this->assertCount($count, $testStorage->getByItemNames(['Researcher'])); + } + + public function testHasItemWithConcurrency(): void + { + $this->assertTrue($this->getEmptyConcurrentAssignmentsStorage()->hasItem('Researcher')); + } + + public function testRenameItemWithConcurrency(): void + { + $testStorage = new AssignmentsStorage($this->getDataPath()); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->renameItem('Researcher', 'Researcher1'); + $actionStorage->renameItem('Accountant', 'Accountant1'); + + $testStorage->renameItem('Researcher', 'Researcher1'); + $this->assertFalse($testStorage->hasItem('Accountant1')); + } + + public function testRemoveWithConcurrency(): void + { + $testStorage = new AssignmentsStorage($this->getDataPath()); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->remove(itemName: 'Researcher', userId: 'john'); + $count = count($actionStorage->getByUserId('john')); + $actionStorage->remove(itemName: 'Accountant', userId: 'john'); + + $testStorage->remove(itemName: 'Researcher', userId: 'john'); + $this->assertCount($count, $testStorage->getByUserId('john')); + } + + public function testRemoveByUserIdWithConcurrency(): void + { + $testStorage = new AssignmentsStorage($this->getDataPath()); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->removeByUserId('john'); + $actionStorage->removeByUserId('jack'); + + $testStorage->removeByUserId('john'); + $this->assertNotEmpty($testStorage->getByUserId('jack')); + } + + public function testRemoveByItemNameWithConcurrency(): void + { + $testStorage = new AssignmentsStorage($this->getDataPath()); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->removeByItemName('Researcher'); + $actionStorage->removeByItemName('Accountant'); + + $testStorage->removeByItemName('Researcher'); + $this->assertNotEmpty($testStorage->getByItemNames(['Accountant'])); + } + + protected function createItemsStorage(): ItemsStorageInterface + { + return new ItemsStorage($this->getDataPath()); + } + + protected function createAssignmentsStorage(): AssignmentsStorageInterface + { + return new AssignmentsStorage($this->getDataPath()); + } + + protected function getAssignmentsStorageForModificationAssertions(): AssignmentsStorageInterface + { + return str_ends_with($this->name(), 'WithConcurrency') + ? $this->createAssignmentsStorage() + : $this->getAssignmentsStorage(); + } + + private function getEmptyConcurrentAssignmentsStorage(): AssignmentsStorageInterface + { + $storage = $this->getAssignmentsStorageForModificationAssertions(); + $this->getAssignmentsStorage()->clear(); + + return $storage; + } +} diff --git a/tests/AssignmentsStorageWithConcurenncyHandlingTest.php b/tests/AssignmentsStorageWithConcurenncyHandlingTest.php index 607cb99..5e08d7d 100644 --- a/tests/AssignmentsStorageWithConcurenncyHandlingTest.php +++ b/tests/AssignmentsStorageWithConcurenncyHandlingTest.php @@ -5,6 +5,7 @@ namespace Yiisoft\Rbac\Php\Tests; use PHPUnit\Framework\TestCase; +use Yiisoft\Rbac\Assignment; use Yiisoft\Rbac\AssignmentsStorageInterface; use Yiisoft\Rbac\ItemsStorageInterface; use Yiisoft\Rbac\Php\AssignmentsStorage; @@ -74,13 +75,77 @@ public function testFilterUserItemNamesWithConcurrency(): void ); } + public function testAddWithConcurrency(): void + { + $innerTestStorage = new AssignmentsStorage($this->getDataPath()); + $testStorage = new ConcurrentAssignmentsStorageDecorator($innerTestStorage); + $actionStorage = $this->getAssignmentsStorage(); + + $time = time(); + $actionStorage->add(new Assignment(userId: 'jack', itemName: 'Researcher', createdAt: $time)); + $actionStorage->add(new Assignment(userId: 'jeff', itemName: 'Researcher', createdAt: $time)); + $count = count($actionStorage->getByItemNames(['Researcher'])); + + $testStorage->add(new Assignment(userId: 'jack', itemName: 'Researcher', createdAt: $time)); + $this->assertCount($count, $innerTestStorage->getByItemNames(['Researcher'])); + } + public function testHasItemWithConcurrency(): void { $this->assertFalse($this->getEmptyConcurrentAssignmentsStorage()->hasItem('Researcher')); } - public function removeByItemName(string $itemName): void + public function testRenameItemWithConcurrency(): void + { + $innerTestStorage = new AssignmentsStorage($this->getDataPath()); + $testStorage = new ConcurrentAssignmentsStorageDecorator($innerTestStorage); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->renameItem('Researcher', 'Researcher1'); + $actionStorage->renameItem('Accountant', 'Accountant1'); + + $testStorage->renameItem('Researcher', 'Researcher1'); + $this->assertTrue($innerTestStorage->hasItem('Accountant1')); + } + + public function testRemoveWithConcurrency(): void + { + $innerTestStorage = new AssignmentsStorage($this->getDataPath()); + $testStorage = new ConcurrentAssignmentsStorageDecorator($innerTestStorage); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->remove(itemName: 'Researcher', userId: 'john'); + $actionStorage->remove(itemName: 'Accountant', userId: 'john'); + $count = count($actionStorage->getByUserId('john')); + + $testStorage->remove(itemName: 'Researcher', userId: 'john'); + $this->assertCount($count, $innerTestStorage->getByUserId('john')); + } + + public function testRemoveByUserIdWithConcurrency(): void { + $innerTestStorage = new AssignmentsStorage($this->getDataPath()); + $testStorage = new ConcurrentAssignmentsStorageDecorator($innerTestStorage); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->removeByUserId('john'); + $actionStorage->removeByUserId('jack'); + + $testStorage->removeByUserId('john'); + $this->assertEmpty($innerTestStorage->getByUserId('jack')); + } + + public function testRemoveByItemNameWithConcurrency(): void + { + $innerTestStorage = new AssignmentsStorage($this->getDataPath()); + $testStorage = new ConcurrentAssignmentsStorageDecorator($innerTestStorage); + $actionStorage = $this->getAssignmentsStorage(); + + $actionStorage->removeByItemName('Researcher'); + $actionStorage->removeByItemName('Accountant'); + + $testStorage->removeByItemName('Researcher'); + $this->assertEmpty($innerTestStorage->getByItemNames(['Accountant'])); } protected function createItemsStorage(): ItemsStorageInterface