RED-6310: Moved code for multithreaded tests to a helper class

(cherry picked from commit 40d6961742436fd4f7c5e07616850d8b1eb31a43)
This commit is contained in:
Viktor Seifert 2023-03-07 11:36:44 +01:00
parent a0e0aadb61
commit 551840a46f
3 changed files with 96 additions and 92 deletions

View File

@ -2,14 +2,12 @@ package com.iqser.red.service.peristence.v1.server.integration.tests;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.peristence.v1.server.integration.utils.MultithreadedTestRunner;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPreferencesPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
@ -25,6 +23,9 @@ public class NotificationPreferencesServiceTest extends AbstractPersistenceServe
@Autowired
NotificationPreferencesPersistenceService notificationPreferencesPersistenceService;
final MultithreadedTestRunner multithreadedTestRunner = new MultithreadedTestRunner(2, 1000);
@BeforeEach
public void setup() {
@ -37,38 +38,15 @@ public class NotificationPreferencesServiceTest extends AbstractPersistenceServe
public void testNotificationPreferencesConcurrent() {
final String userId = "1";
Runnable test = () -> notificationPreferencesPersistenceService.getOrCreateNotificationPreferences(userId);
Runnable afterTest = () -> notificationPreferencesPersistenceService.deleteNotificationPreferences(userId);
var exceptions = multithreadedTestRunner.runMutlithreadedCollectingExceptions(test, afterTest);
for (int i = 0; i < 1000; i++) {
var exceptions = Collections.synchronizedList(new ArrayList<Exception>());
Thread t1 = new Thread(() -> {
try {
notificationPreferencesPersistenceService.getOrCreateNotificationPreferences(userId);
} catch (Exception e) {
exceptions.add(e);
}
});
Thread t2 = new Thread(() -> {
try {
notificationPreferencesPersistenceService.getOrCreateNotificationPreferences(userId);
} catch (Exception e) {
exceptions.add(e);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
notificationPreferencesPersistenceService.deleteNotificationPreferences(userId);
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
}
}

View File

@ -3,8 +3,6 @@ package com.iqser.red.service.peristence.v1.server.integration.tests;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import org.assertj.core.util.Lists;
@ -14,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.iqser.red.service.peristence.v1.server.integration.client.NotificationClient;
import com.iqser.red.service.peristence.v1.server.integration.client.NotificationPreferencesClient;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.peristence.v1.server.integration.utils.MultithreadedTestRunner;
import com.iqser.red.service.persistence.service.v1.api.model.audit.AddNotificationRequest;
import com.iqser.red.service.persistence.service.v1.api.model.common.JSONPrimitive;
import com.iqser.red.service.persistence.service.v1.api.model.notification.Notification;
@ -32,6 +31,8 @@ public class NotificationTest extends AbstractPersistenceServerServiceTest {
@Autowired
private NotificationPreferencesClient notificationPreferencesClient;
private final MultithreadedTestRunner multithreadedTestRunner = new MultithreadedTestRunner(2, 1000);
@Test
public void testNotificationPreferences() {
@ -119,38 +120,15 @@ public class NotificationTest extends AbstractPersistenceServerServiceTest {
public void testNotificationPreferencesConcurrent() {
final String userId = "1";
Runnable test = () -> notificationPreferencesClient.getNotificationPreferences(userId);
Runnable afterTest = () -> notificationPreferencesClient.deleteNotificationPreferences(userId);
var exceptions = multithreadedTestRunner.runMutlithreadedCollectingExceptions(test, afterTest);
for (int i = 0; i < 1000; i++) {
var exceptions = Collections.synchronizedList(new ArrayList<Exception>());
Thread t1 = new Thread(() -> {
try {
notificationPreferencesClient.getNotificationPreferences(userId);
} catch (Exception e) {
exceptions.add(e);
}
});
Thread t2 = new Thread(() -> {
try {
notificationPreferencesClient.getNotificationPreferences(userId);
} catch (Exception e) {
exceptions.add(e);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
notificationPreferencesClient.deleteNotificationPreferences(userId);
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
}
@ -159,38 +137,15 @@ public class NotificationTest extends AbstractPersistenceServerServiceTest {
public void testNotificationsConcurrent() {
final String userId = "1";
Runnable test = () -> notificationClient.getNotifications(userId, false);
Runnable afterTest = () -> notificationPreferencesClient.deleteNotificationPreferences(userId);
var exceptions = multithreadedTestRunner.runMutlithreadedCollectingExceptions(test, afterTest);
for (int i = 0; i < 1000; i++) {
var exceptions = Collections.synchronizedList(new ArrayList<Exception>());
Thread t1 = new Thread(() -> {
try {
notificationClient.getNotifications(userId, false);
} catch (Exception e) {
exceptions.add(e);
}
});
Thread t2 = new Thread(() -> {
try {
notificationClient.getNotifications(userId, false);
} catch (Exception e) {
exceptions.add(e);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
notificationPreferencesClient.deleteNotificationPreferences(userId);
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
for (Exception ex : exceptions) {
log.error("Exception during notification creation", ex);
}
assertThat(exceptions).isEmpty();
}
}

View File

@ -0,0 +1,71 @@
package com.iqser.red.service.peristence.v1.server.integration.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class MultithreadedTestRunner {
int numberOfThreads;
int numberOfExecutions;
public List<Exception> runMutlithreadedCollectingExceptions(boolean stopOnFirstRunWithExceptions, Runnable test, Runnable afterTest) {
List<Exception> allExceptions = new ArrayList<>();
for (int execution = 1; execution <= numberOfExecutions; execution++) {
var threads = new ArrayList<Thread>(numberOfThreads);
var exceptions = Collections.synchronizedList(new ArrayList<Exception>());
for (int threadNumber = 1; threadNumber <= numberOfThreads; threadNumber++) {
Thread t = new Thread(() -> {
try {
test.run();
} catch (Exception e) {
exceptions.add(e);
}
});
threads.add(t);
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
afterTest.run();
if (stopOnFirstRunWithExceptions) {
if (!exceptions.isEmpty()) {
return exceptions;
}
} else {
allExceptions.addAll(exceptions);
}
}
return allExceptions;
}
public List<Exception> runMutlithreadedCollectingExceptions(Runnable test, Runnable afterTest) {
return runMutlithreadedCollectingExceptions(true, test, afterTest);
}
}