@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 227 lines 6.1 kB view raw
1<?php 2 3final class PhabricatorGlobalLockTestCase 4 extends PhabricatorTestCase { 5 6 protected function getPhabricatorTestCaseConfiguration() { 7 return array( 8 self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, 9 ); 10 } 11 12 public function testConnectionPoolWithDefaultConnection() { 13 PhabricatorGlobalLock::clearConnectionPool(); 14 15 $this->assertEqual( 16 0, 17 PhabricatorGlobalLock::getConnectionPoolSize(), 18 pht('Clear Connection Pool')); 19 20 $lock_name = $this->newLockName(); 21 $lock = PhabricatorGlobalLock::newLock($lock_name); 22 $lock->lock(); 23 24 $this->assertEqual( 25 0, 26 PhabricatorGlobalLock::getConnectionPoolSize(), 27 pht('Connection Pool With Lock')); 28 29 $lock->unlock(); 30 31 $this->assertEqual( 32 1, 33 PhabricatorGlobalLock::getConnectionPoolSize(), 34 pht('Connection Pool With Lock Released')); 35 36 PhabricatorGlobalLock::clearConnectionPool(); 37 } 38 39 public function testConnectionPoolWithSpecificConnection() { 40 $conn = PhabricatorGlobalLock::newConnection(); 41 42 PhabricatorGlobalLock::clearConnectionPool(); 43 44 $this->assertEqual( 45 0, 46 PhabricatorGlobalLock::getConnectionPoolSize(), 47 pht('Clear Connection Pool')); 48 49 $this->assertEqual( 50 false, 51 $conn->isHoldingAnyLock(), 52 pht('Specific Connection, No Lock')); 53 54 $lock_name = $this->newLockName(); 55 $lock = PhabricatorGlobalLock::newLock($lock_name); 56 $lock->setExternalConnection($conn); 57 $lock->lock(); 58 59 $this->assertEqual( 60 0, 61 PhabricatorGlobalLock::getConnectionPoolSize(), 62 pht('Connection Pool + Specific, With Lock')); 63 64 $this->assertEqual( 65 true, 66 $conn->isHoldingAnyLock(), 67 pht('Specific Connection, Holding Lock')); 68 69 $lock->unlock(); 70 71 // The specific connection provided should NOT be returned to the 72 // connection pool. 73 74 $this->assertEqual( 75 0, 76 PhabricatorGlobalLock::getConnectionPoolSize(), 77 pht('Connection Pool + Specific, With Lock Released')); 78 79 $this->assertEqual( 80 false, 81 $conn->isHoldingAnyLock(), 82 pht('Specific Connection, No Lock')); 83 84 PhabricatorGlobalLock::clearConnectionPool(); 85 } 86 87 public function testExternalConnectionMutationScope() { 88 $conn = PhabricatorGlobalLock::newConnection(); 89 90 $lock_name = $this->newLockName(); 91 $lock = PhabricatorGlobalLock::newLock($lock_name); 92 $lock->lock(); 93 94 $caught = null; 95 try { 96 $lock->setExternalConnection($conn); 97 } catch (Exception $ex) { 98 $caught = $ex; 99 } catch (Throwable $ex) { 100 $caught = $ex; 101 } 102 103 $lock->unlock(); 104 105 $this->assertTrue( 106 ($caught instanceof Exception), 107 pht('Changing connection while locked is forbidden.')); 108 } 109 110 public function testMultipleLocks() { 111 $conn = PhabricatorGlobalLock::newConnection(); 112 113 PhabricatorGlobalLock::clearConnectionPool(); 114 115 $lock_name_a = $this->newLockName(); 116 $lock_name_b = $this->newLockName(); 117 118 $lock_a = PhabricatorGlobalLock::newLock($lock_name_a); 119 $lock_a->setExternalConnection($conn); 120 121 $lock_b = PhabricatorGlobalLock::newLock($lock_name_b); 122 $lock_b->setExternalConnection($conn); 123 124 $lock_a->lock(); 125 126 $caught = null; 127 try { 128 $lock_b->lock(); 129 } catch (Exception $ex) { 130 $caught = $ex; 131 } catch (Throwable $ex) { 132 $caught = $ex; 133 } 134 135 // See T13627. The lock infrastructure must forbid this because it does 136 // not work in versions of MySQL older than 5.7. 137 138 $this->assertTrue( 139 ($caught instanceof Exception), 140 pht('Expect multiple locks on the same connection to fail.')); 141 } 142 143 public function testPoolReleaseOnFailure() { 144 $conn = PhabricatorGlobalLock::newConnection(); 145 $lock_name = $this->newLockName(); 146 147 PhabricatorGlobalLock::clearConnectionPool(); 148 149 $this->assertEqual( 150 0, 151 PhabricatorGlobalLock::getConnectionPoolSize(), 152 pht('Clear Connection Pool')); 153 154 $lock = PhabricatorGlobalLock::newLock($lock_name); 155 156 // NOTE: We're cheating here, since there's a global registry of locks 157 // for the process that we have to bypass. In the real world, this lock 158 // would have to be held by some external process. To simplify this 159 // test case, just use a raw "GET_LOCK()" call to hold the lock. 160 161 $raw_conn = PhabricatorGlobalLock::newConnection(); 162 $raw_name = $lock->getName(); 163 164 $row = queryfx_one( 165 $raw_conn, 166 'SELECT GET_LOCK(%s, %f)', 167 $raw_name, 168 0); 169 $this->assertTrue((bool)head($row), pht('Establish Raw Lock')); 170 171 $this->assertEqual( 172 0, 173 PhabricatorGlobalLock::getConnectionPoolSize(), 174 pht('Connection Pool with Held Lock')); 175 176 // We expect this sequence to establish a new connection, fail to acquire 177 // the lock, then put the connection in the connection pool. After the 178 // first cycle, the connection should be reused. 179 180 for ($ii = 0; $ii < 3; $ii++) { 181 $this->tryHeldLock($lock_name); 182 $this->assertEqual( 183 1, 184 PhabricatorGlobalLock::getConnectionPoolSize(), 185 pht('Connection Pool After Lock Failure')); 186 } 187 188 PhabricatorGlobalLock::clearConnectionPool(); 189 190 // Now, do the same thing with an external connection. This connection 191 // should not be put into the pool! See T13627. 192 193 for ($ii = 0; $ii < 3; $ii++) { 194 $this->tryHeldLock($lock_name, $conn); 195 $this->assertEqual( 196 0, 197 PhabricatorGlobalLock::getConnectionPoolSize(), 198 pht('Connection Pool After External Lock Failure')); 199 } 200 } 201 202 private function newLockName() { 203 return 'testlock-'.Filesystem::readRandomCharacters(16); 204 } 205 206 private function tryHeldLock( 207 $lock_name, 208 ?AphrontDatabaseConnection $conn = null) { 209 210 $lock = PhabricatorGlobalLock::newLock($lock_name); 211 212 if ($conn) { 213 $lock->setExternalConnection($conn); 214 } 215 216 $caught = null; 217 try { 218 $lock->lock(0); 219 } catch (PhutilLockException $ex) { 220 $caught = $ex; 221 } 222 223 $this->assertTrue($caught instanceof PhutilLockException); 224 } 225 226 227}