5 changed files with 141 additions and 40 deletions
@ -0,0 +1,111 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.sqlts.dictionary; |
||||
|
|
||||
|
import org.junit.Test; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.thingsboard.server.dao.dictionary.KeyDictionaryDao; |
||||
|
import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryCompositeKey; |
||||
|
import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryEntry; |
||||
|
import org.thingsboard.server.dao.service.AbstractServiceTest; |
||||
|
import org.thingsboard.server.dao.service.DaoSqlTest; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
import java.util.Optional; |
||||
|
import java.util.concurrent.CountDownLatch; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
|
||||
|
@DaoSqlTest |
||||
|
public class KeyDictionaryDaoTest extends AbstractServiceTest { |
||||
|
|
||||
|
@Autowired |
||||
|
private KeyDictionaryDao keyDictionaryDao; |
||||
|
|
||||
|
@Autowired |
||||
|
private KeyDictionaryRepository keyDictionaryRepository; |
||||
|
|
||||
|
private static final String KEY = "testKeyDictionaryDaoTestKey"; |
||||
|
|
||||
|
@Test |
||||
|
public void testGetOrSaveKeyId_concurrent() throws Exception { |
||||
|
int threads = 8; |
||||
|
ExecutorService executor = Executors.newFixedThreadPool(threads); |
||||
|
|
||||
|
CountDownLatch allReady = new CountDownLatch(threads); |
||||
|
CountDownLatch start = new CountDownLatch(1); |
||||
|
CountDownLatch allDone = new CountDownLatch(threads); |
||||
|
|
||||
|
Integer[] keyIds = new Integer[threads]; |
||||
|
|
||||
|
try { |
||||
|
for (int i = 0; i < threads; i++) { |
||||
|
final int idx = i; |
||||
|
executor.submit(() -> { |
||||
|
allReady.countDown(); |
||||
|
try { |
||||
|
// wait until all threads are ready
|
||||
|
start.await(); |
||||
|
// concurrent call
|
||||
|
Integer id = keyDictionaryDao.getOrSaveKeyId(KEY); |
||||
|
keyIds[idx] = id; |
||||
|
} catch (InterruptedException e) { |
||||
|
Thread.currentThread().interrupt(); |
||||
|
} finally { |
||||
|
allDone.countDown(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// ensure all threads are queued
|
||||
|
allReady.await(5, TimeUnit.SECONDS); |
||||
|
// fire the start gun
|
||||
|
start.countDown(); |
||||
|
// wait for all to finish
|
||||
|
allDone.await(10, TimeUnit.SECONDS); |
||||
|
} finally { |
||||
|
executor.shutdownNow(); |
||||
|
} |
||||
|
|
||||
|
// basic sanity
|
||||
|
for (int i = 0; i < threads; i++) { |
||||
|
assertThat(keyIds[i]) |
||||
|
.as("keyId[%s]", i) |
||||
|
.isNotNull() |
||||
|
.isGreaterThan(0); |
||||
|
} |
||||
|
|
||||
|
// all threads must see the same keyId
|
||||
|
int first = keyIds[0]; |
||||
|
assertThat(first).isGreaterThan(0); |
||||
|
assertThat(Arrays.stream(keyIds).distinct().count()) |
||||
|
.as("all threads should get the same keyId") |
||||
|
.isEqualTo(1); |
||||
|
|
||||
|
// DB must have exactly one row for this key and the same id
|
||||
|
KeyDictionaryCompositeKey id = new KeyDictionaryCompositeKey(KEY); |
||||
|
Optional<KeyDictionaryEntry> entry = keyDictionaryRepository.findById(id); |
||||
|
|
||||
|
assertThat(entry.isPresent()).isTrue(); |
||||
|
assertThat(entry.get().getKeyId()).isEqualTo(first); |
||||
|
|
||||
|
keyDictionaryRepository.deleteById(id); |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue