LockingProvider.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. /**
  3. * @author Robin Appelman <icewind@owncloud.com>
  4. *
  5. * @copyright Copyright (c) 2015, ownCloud, Inc.
  6. * @license AGPL-3.0
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. namespace Test\Lock;
  22. use OCP\Lock\ILockingProvider;
  23. use OCP\Lock\LockedException;
  24. use Test\TestCase;
  25. abstract class LockingProvider extends TestCase {
  26. /**
  27. * @var \OCP\Lock\ILockingProvider
  28. */
  29. protected $instance;
  30. /**
  31. * @return \OCP\Lock\ILockingProvider
  32. */
  33. abstract protected function getInstance();
  34. protected function setUp(): void {
  35. parent::setUp();
  36. $this->instance = $this->getInstance();
  37. }
  38. public function testExclusiveLock() {
  39. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  40. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  41. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  42. }
  43. public function testSharedLock() {
  44. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  45. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  46. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  47. }
  48. public function testDoubleSharedLock() {
  49. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  50. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  51. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  52. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  53. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  54. }
  55. public function testReleaseSharedLock() {
  56. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  57. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  58. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  59. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  60. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  61. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  62. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  63. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  64. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  65. }
  66. public function testDoubleExclusiveLock() {
  67. $this->expectException(\OCP\Lock\LockedException::class);
  68. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  69. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  70. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  71. }
  72. public function testReleaseExclusiveLock() {
  73. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  74. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  75. $this->instance->releaseLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  76. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  77. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  78. }
  79. public function testExclusiveLockAfterShared() {
  80. $this->expectException(\OCP\Lock\LockedException::class);
  81. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  82. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  83. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  84. }
  85. public function testExclusiveLockAfterSharedReleased() {
  86. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  87. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  88. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  89. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  90. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  91. }
  92. public function testReleaseAll() {
  93. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  94. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  95. $this->instance->acquireLock('bar', ILockingProvider::LOCK_SHARED);
  96. $this->instance->acquireLock('asd', ILockingProvider::LOCK_EXCLUSIVE);
  97. $this->instance->acquireLock('fizz#A=23', ILockingProvider::LOCK_EXCLUSIVE);
  98. $this->instance->releaseAll();
  99. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  100. $this->assertFalse($this->instance->isLocked('bar', ILockingProvider::LOCK_SHARED));
  101. $this->assertFalse($this->instance->isLocked('asd', ILockingProvider::LOCK_EXCLUSIVE));
  102. $this->assertFalse($this->instance->isLocked('fizz#A=23', ILockingProvider::LOCK_EXCLUSIVE));
  103. }
  104. public function testReleaseAllAfterChange() {
  105. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  106. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  107. $this->instance->acquireLock('bar', ILockingProvider::LOCK_SHARED);
  108. $this->instance->acquireLock('asd', ILockingProvider::LOCK_EXCLUSIVE);
  109. $this->instance->changeLock('bar', ILockingProvider::LOCK_EXCLUSIVE);
  110. $this->instance->releaseAll();
  111. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  112. $this->assertFalse($this->instance->isLocked('bar', ILockingProvider::LOCK_SHARED));
  113. $this->assertFalse($this->instance->isLocked('bar', ILockingProvider::LOCK_EXCLUSIVE));
  114. $this->assertFalse($this->instance->isLocked('asd', ILockingProvider::LOCK_EXCLUSIVE));
  115. }
  116. public function testReleaseAllAfterUnlock() {
  117. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  118. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  119. $this->instance->acquireLock('bar', ILockingProvider::LOCK_SHARED);
  120. $this->instance->acquireLock('asd', ILockingProvider::LOCK_EXCLUSIVE);
  121. $this->instance->releaseLock('bar', ILockingProvider::LOCK_SHARED);
  122. $this->instance->releaseAll();
  123. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  124. $this->assertFalse($this->instance->isLocked('asd', ILockingProvider::LOCK_EXCLUSIVE));
  125. }
  126. public function testReleaseAfterReleaseAll() {
  127. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  128. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  129. $this->instance->releaseAll();
  130. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  131. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  132. }
  133. public function testSharedLockAfterExclusive() {
  134. $this->expectException(\OCP\Lock\LockedException::class);
  135. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  136. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  137. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  138. }
  139. public function testLockedExceptionHasPathForShared() {
  140. try {
  141. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  142. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  143. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  144. $this->fail('Expected locked exception');
  145. } catch (LockedException $e) {
  146. $this->assertEquals('foo', $e->getPath());
  147. }
  148. }
  149. public function testLockedExceptionHasPathForExclusive() {
  150. try {
  151. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  152. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  153. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  154. $this->fail('Expected locked exception');
  155. } catch (LockedException $e) {
  156. $this->assertEquals('foo', $e->getPath());
  157. }
  158. }
  159. public function testChangeLockToExclusive() {
  160. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  161. $this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  162. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  163. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  164. }
  165. public function testChangeLockToShared() {
  166. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  167. $this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
  168. $this->assertFalse($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  169. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_SHARED));
  170. }
  171. public function testChangeLockToExclusiveDoubleShared() {
  172. $this->expectException(\OCP\Lock\LockedException::class);
  173. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  174. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  175. $this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  176. }
  177. public function testChangeLockToExclusiveNoShared() {
  178. $this->expectException(\OCP\Lock\LockedException::class);
  179. $this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  180. }
  181. public function testChangeLockToExclusiveFromExclusive() {
  182. $this->expectException(\OCP\Lock\LockedException::class);
  183. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  184. $this->instance->changeLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  185. }
  186. public function testChangeLockToSharedNoExclusive() {
  187. $this->expectException(\OCP\Lock\LockedException::class);
  188. $this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
  189. }
  190. public function testChangeLockToSharedFromShared() {
  191. $this->expectException(\OCP\Lock\LockedException::class);
  192. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  193. $this->instance->changeLock('foo', ILockingProvider::LOCK_SHARED);
  194. }
  195. public function testReleaseNonExistingShared() {
  196. $this->instance->acquireLock('foo', ILockingProvider::LOCK_SHARED);
  197. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  198. // releasing a lock once to many should not result in a locked state
  199. $this->instance->releaseLock('foo', ILockingProvider::LOCK_SHARED);
  200. $this->instance->acquireLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  201. $this->assertTrue($this->instance->isLocked('foo', ILockingProvider::LOCK_EXCLUSIVE));
  202. $this->instance->releaseLock('foo', ILockingProvider::LOCK_EXCLUSIVE);
  203. }
  204. }