|
15 | 15 | use Doctrine\DBAL\Platforms\MySQLPlatform; |
16 | 16 | use OC\DB\Adapter; |
17 | 17 | use OC\DB\Connection; |
| 18 | +use OC\DB\ConnectionAdapter; |
| 19 | +use OCP\IDBConnection; |
| 20 | +use OCP\Server; |
18 | 21 | use Test\TestCase; |
19 | 22 |
|
20 | 23 | /** |
@@ -98,4 +101,56 @@ public function testClusterConnectsToPrimaryAndReplica(): void { |
98 | 101 | $connection->ensureConnectedToReplica(); |
99 | 102 | } |
100 | 103 |
|
| 104 | + public function testSuccessfulQueryResetsConnectivityCheckTimer(): void { |
| 105 | + $inner = $this->getInnerConnection(); |
| 106 | + |
| 107 | + // Ensure the connection is established before touching the timer |
| 108 | + $qb = $inner->getQueryBuilder(); |
| 109 | + $qb->select('configvalue')->from('appconfig')->setMaxResults(1); |
| 110 | + $qb->executeQuery()->closeCursor(); |
| 111 | + |
| 112 | + $property = $this->backdateLastConnectionCheck($inner); |
| 113 | + $before = time(); |
| 114 | + |
| 115 | + $qb->executeQuery()->closeCursor(); |
| 116 | + |
| 117 | + // A connectivity probe firing between adjacent operations would reset |
| 118 | + // the driver level last insert id on MySQL |
| 119 | + self::assertGreaterThanOrEqual($before, max($property->getValue($inner))); |
| 120 | + } |
| 121 | + |
| 122 | + public function testPreparedStatementExecutionResetsConnectivityCheckTimer(): void { |
| 123 | + $inner = $this->getInnerConnection(); |
| 124 | + |
| 125 | + $statement = $inner->prepare('SELECT `configvalue` FROM `*PREFIX*appconfig`', 1); |
| 126 | + |
| 127 | + $property = $this->backdateLastConnectionCheck($inner); |
| 128 | + $before = time(); |
| 129 | + |
| 130 | + $statement->executeQuery()->free(); |
| 131 | + |
| 132 | + self::assertGreaterThanOrEqual($before, max($property->getValue($inner))); |
| 133 | + } |
| 134 | + |
| 135 | + private function getInnerConnection(): Connection { |
| 136 | + $connection = Server::get(IDBConnection::class); |
| 137 | + if (!$connection instanceof ConnectionAdapter) { |
| 138 | + self::markTestSkipped('Test requires the real database connection'); |
| 139 | + } |
| 140 | + |
| 141 | + return $connection->getInner(); |
| 142 | + } |
| 143 | + |
| 144 | + /** |
| 145 | + * Make the connectivity check timer stale, but by less than the check |
| 146 | + * interval: the probe must not fire, so only actual query activity can |
| 147 | + * refresh the timer. |
| 148 | + */ |
| 149 | + private function backdateLastConnectionCheck(Connection $connection): \ReflectionProperty { |
| 150 | + $property = new \ReflectionProperty(Connection::class, 'lastConnectionCheck'); |
| 151 | + $property->setValue($connection, ['primary' => time() - 20, 'replica' => time() - 20]); |
| 152 | + |
| 153 | + return $property; |
| 154 | + } |
| 155 | + |
101 | 156 | } |
0 commit comments