Skip to content

Commit

Permalink
fix: concurrency issue when save and delete a draft message in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
mebo4b committed Feb 24, 2021
1 parent d1dc024 commit 5780497
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 2 deletions.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@
<version>4.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vmlens</groupId>
<artifactId>concurrent-junit</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class DraftMessageService {
* @param rcGroupId the rocket chat group id
* @return a {@link SavedDraftType} for the created type
*/
public SavedDraftType saveDraftMessage(String message, String rcGroupId) {
public synchronized SavedDraftType saveDraftMessage(String message, String rcGroupId) {

Optional<DraftMessage> optionalDraftMessage = findDraftMessage(rcGroupId);

Expand Down Expand Up @@ -76,7 +76,7 @@ private void updateMessage(String message, String rcGroupId, DraftMessage draftM
*
* @param rcGroupId the rocket chat group id
*/
public void deleteDraftMessageIfExist(String rcGroupId) {
public synchronized void deleteDraftMessageIfExist(String rcGroupId) {
this.findDraftMessage(rcGroupId).ifPresent(this::deleteDraftMessage);
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/application-testing.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ csrf.cookie.property=CSRF-TOKEN
user.service.api.liveproxy.url=/liveproxy/send

# Liquibase
spring.jpa.open-in-view=false
spring.liquibase.enabled=false
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.schema=classpath*:database/MessageDatabase.sql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MessageServiceApplication.class)
@TestPropertySource(properties = "spring.profiles.active=testing")
@AutoConfigureTestDatabase(replace = Replace.ANY)
public class LiveProxyApiClientConfigIT {

@Autowired
Expand All @@ -32,3 +35,4 @@ public void configureLiveControllerApi_Should_setCorrectApiUrl() {
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package de.caritas.cob.messageservice.api.service;

import static com.anarsoft.vmlens.concurrent.junit.TestUtil.runMultithreaded;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import de.caritas.cob.messageservice.MessageServiceApplication;
import de.caritas.cob.messageservice.api.exception.CustomCryptoException;
import de.caritas.cob.messageservice.api.helper.AuthenticatedUser;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MessageServiceApplication.class)
@AutoConfigureTestDatabase(replace = Replace.ANY)
@TestPropertySource(properties = "spring.profiles.active=testing")
public class DraftMessageServiceIT {

@Autowired
private DraftMessageService draftMessageService;

@MockBean
private AuthenticatedUser authenticatedUser;

@MockBean
private EncryptionService encryptionService;

@Before
public void setup() throws CustomCryptoException {
when(this.encryptionService.encrypt(any(), any())).thenReturn("encrypted");
when(this.authenticatedUser.getUserId()).thenReturn("userId");
}

@Test
public void saveAndDeleteDraftMessage_Should_produceNoError_When_executionIsInParallel()
throws InterruptedException {
AtomicInteger errorCount = new AtomicInteger(0);
int threadCount = 10;
String rcGroupId = "rcGroupId";

runMultithreaded(() -> {
try {
draftMessageService.saveDraftMessage("message", rcGroupId);
draftMessageService.deleteDraftMessageIfExist(rcGroupId);
} catch (Exception e) {
errorCount.incrementAndGet();
}
}, threadCount);

assertThat(errorCount.get(), is(0));
}

}
13 changes: 13 additions & 0 deletions src/test/resources/database/MessageDatabase.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE DRAFTMESSAGE
(
ID bigint NOT NULL,
USER_ID varchar(36) NOT NULL,
RC_GROUP_ID varchar(255) NOT NULL,
DRAFT_MESSAGE varchar(255) NOT NULL,
CREATE_DATE timestamp,
UPDATE_DATE timestamp,
PRIMARY KEY (ID)
);
CREATE SEQUENCE SEQUENCE_DRAFTMESSAGE
START WITH 100000
INCREMENT BY 1;

0 comments on commit 5780497

Please sign in to comment.