|
25 | 25 | import static org.junit.Assert.assertNull; |
26 | 26 | import static org.junit.Assert.assertTrue; |
27 | 27 | import static org.junit.Assert.fail; |
| 28 | +import static org.mockito.Mockito.when; |
28 | 29 |
|
29 | 30 | import com.google.cloud.bigtable.admin.v2.BigtableTableAdminClient; |
30 | 31 | import com.google.cloud.bigtable.admin.v2.BigtableTableAdminSettings; |
|
57 | 58 | import org.junit.Test; |
58 | 59 | import org.junit.runner.RunWith; |
59 | 60 | import org.junit.runners.JUnit4; |
| 61 | +import org.mockito.Mockito; |
| 62 | +import org.mockito.stubbing.Answer; |
60 | 63 | import org.slf4j.Logger; |
61 | 64 | import org.slf4j.LoggerFactory; |
62 | 65 |
|
@@ -141,7 +144,7 @@ public void testNewPartitionConversionWithWithIllegalUtf8() |
141 | 144 | } |
142 | 145 |
|
143 | 146 | @Test |
144 | | - public void testLockPartitionRace() throws InterruptedException { |
| 147 | + public void testLockPartitionRaceUniqueIds() throws InterruptedException { |
145 | 148 | ByteStringRange partition = ByteStringRange.create("", ""); |
146 | 149 | ByteString rowKey = metadataTableDao.convertPartitionToStreamPartitionRowKey(partition); |
147 | 150 | // Class to try to lock the partition in a separate thread. |
@@ -223,6 +226,54 @@ public void run() { |
223 | 226 | dataClient.mutateRow(rowMutation); |
224 | 227 | } |
225 | 228 |
|
| 229 | + @Test |
| 230 | + public void testLockPartitionRaceDuplicateIds() throws InterruptedException { |
| 231 | + ByteStringRange partition = ByteStringRange.create("", ""); |
| 232 | + String uid = "a"; |
| 233 | + MetadataTableDao spy = Mockito.spy(metadataTableDao); |
| 234 | + // First call we sleep for ten seconds to ensure the duplicate acquires the |
| 235 | + // lock before we return. |
| 236 | + when(spy.doHoldLock(partition, uid)) |
| 237 | + .then( |
| 238 | + (Answer<Boolean>) |
| 239 | + invocation -> { |
| 240 | + Thread.sleep(10000); |
| 241 | + return false; |
| 242 | + }) |
| 243 | + .thenCallRealMethod() |
| 244 | + .thenCallRealMethod(); |
| 245 | + |
| 246 | + class LockPartition implements Runnable { |
| 247 | + final PartitionRecord partitionRecord = |
| 248 | + new PartitionRecord( |
| 249 | + partition, |
| 250 | + Collections.emptyList(), |
| 251 | + uid, |
| 252 | + Instant.now(), |
| 253 | + Collections.emptyList(), |
| 254 | + Instant.now().plus(Duration.standardMinutes(10))); |
| 255 | + boolean locked = false; |
| 256 | + |
| 257 | + @Override |
| 258 | + public void run() { |
| 259 | + locked = spy.lockAndRecordPartition(partitionRecord); |
| 260 | + } |
| 261 | + } |
| 262 | + |
| 263 | + LockPartition dup1 = new LockPartition(); |
| 264 | + Thread dup1Thread = new Thread(dup1); |
| 265 | + LockPartition dup2 = new LockPartition(); |
| 266 | + Thread dup2Thread = new Thread(dup2); |
| 267 | + |
| 268 | + dup1Thread.start(); |
| 269 | + dup2Thread.start(); |
| 270 | + dup1Thread.join(); |
| 271 | + dup2Thread.join(); |
| 272 | + |
| 273 | + assertTrue(dup2.locked); |
| 274 | + assertTrue(dup1.locked); |
| 275 | + } |
| 276 | + |
226 | 277 | @Test |
227 | 278 | public void testReadStreamPartitionsWithWatermark() throws InvalidProtocolBufferException { |
228 | 279 | ByteStringRange lockedPartition = ByteStringRange.create("", "a"); |
|
0 commit comments