Skip to content

Commit

Permalink
Refactor : test 환경 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
this-is-spear committed Jan 17, 2024
1 parent 4323b43 commit 01833f7
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,61 +26,79 @@ public class ConcurrencyManagerWithNamedLock implements ConcurrencyManager {
private static final String EMPTY_RESULT_MESSAGE = "USER LEVEL LOCK 쿼리 결과 값이 NULL 입니다. type = [{}], userLockName : [{}]";
private static final String INVALID_RESULT_MESSAGE = "USER LEVEL LOCK 쿼리 결과 값이 0 입니다. type = [{}], result : [{}] userLockName : [{}]";
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final DataSource dataSource;
private final DataSource userLoackDataSource;

@Override
public void executeWithLock(String lockName1, String lockName2, Runnable runnable) {
try(var connection = dataSource.getConnection()) {
getLock(connection, getMultiLockName(lockName1, lockName2));
getLock(connection, lockName1);
getLock(connection, lockName2);
runnable.run();
releaseLock(connection, lockName2);
releaseLock(connection, lockName1);
releaseLock(connection, getMultiLockName(lockName1, lockName2));
try (var connection = userLoackDataSource.getConnection()) {
try {
log.debug("start getLock=[{}], timeoutSeconds : [{}], connection=[{}]", getMultiLockName(lockName1, lockName2), TIMEOUT_SECONDS, connection);
getLock(connection, getMultiLockName(lockName1, lockName2));
try {
log.debug("start getLock=[{}], timeoutSeconds : [{}], connection=[{}]", lockName1, TIMEOUT_SECONDS, connection);
getLock(connection, lockName1);
try {
log.debug("start getLock=[{}], timeoutSeconds : [{}], connection=[{}]", lockName2, TIMEOUT_SECONDS, connection);
getLock(connection, lockName2);
runnable.run();
} finally {
log.debug("start releaseLock=[{}], connection=[{}]", lockName2, connection);
releaseLock(connection, lockName2);
}
}finally {
log.debug("start releaseLock=[{}], connection=[{}]", lockName1, connection);
releaseLock(connection, lockName1);
}
} finally {
log.debug("start releaseLock=[{}], connection=[{}]", getMultiLockName(lockName1, lockName2), connection);
releaseLock(connection, getMultiLockName(lockName1, lockName2));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
releaseSessionLocks();
}
}

@Override
public void executeWithLock(String lockName, Runnable runnable) {
try(var connection = dataSource.getConnection()) {
try (var connection = userLoackDataSource.getConnection()) {
log.info("start getLock=[{}], timeoutSeconds : [{}], connection=[{}]", lockName, TIMEOUT_SECONDS, connection);
getLock(connection, lockName);
runnable.run();
releaseLock(connection, lockName);
try {
runnable.run();
} finally {
log.info("start releaseLock, connection=[{}]", connection);
releaseLock(connection, lockName);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
releaseSessionLocks();
}
}

private void releaseLock(Connection connection, String lockName) {
try (var preparedStatement = connection.prepareStatement(RELEASE_LOCK)) {
preparedStatement.setString(1, lockName);
private void getLock(Connection connection, String userLockName) {
try (var preparedStatement = connection.prepareStatement(GET_LOCK)) {
preparedStatement.setString(1, userLockName);
preparedStatement.setInt(2, TIMEOUT_SECONDS);
var resultSet = preparedStatement.executeQuery();
validateResult(resultSet, lockName, "ReleaseLock");
validateResult(resultSet, userLockName, "GetLock");
} catch (SQLException e) {
log.error("ReleaseLock_{} : {}", lockName, e.getMessage());
log.error("GetLock_{} : {}", userLockName, e.getMessage());
throw new IllegalStateException("SQL Exception");
}
}

private void getLock(Connection connection, String userLockName) {
try (var preparedStatement = connection.prepareStatement(GET_LOCK)) {
private void releaseLock(Connection connection, String userLockName) {
try (var preparedStatement = connection.prepareStatement(RELEASE_LOCK)) {
preparedStatement.setString(1, userLockName);
preparedStatement.setInt(2, TIMEOUT_SECONDS);

synchronized (this) {
var resultSet = preparedStatement.executeQuery();
validateResult(resultSet, userLockName, "GetLock");
}

preparedStatement.executeQuery();
} catch (SQLException e) {
log.error("GetLock_{} : {}", userLockName, e.getMessage());
log.error("Release Lock : {}", e.getMessage());
throw new IllegalStateException("SQL Exception");
}
}
private void releaseSessionLocks(Connection connection) {
try (var preparedStatement = connection.prepareStatement(RELEASE_SESSION_LOCKS)) {
preparedStatement.executeQuery();
} catch (SQLException e) {
log.error("ReleaseSessionLocks : {}", e.getMessage());
throw new IllegalStateException("SQL Exception");
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/bankingapi/util/config/DatasourceConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package bankingapi.util.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

@Configuration
public class DatasourceConfiguration {
@Primary
@Bean
@ConfigurationProperties("spring.datasource.hikari")
public DataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}

@Bean
@ConfigurationProperties("userlock.datasource.hikari")
public DataSource userLockDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}
12 changes: 0 additions & 12 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
@@ -1,12 +0,0 @@
spring:
datasource:
url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/money_transfer_service?characterEncoding=UTF-8&serverTimezone=Asia/Seoul}
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${SPRING_DATASOURCE_USERNAME:root}
password: ${SPRING_DATASOURCE_PASSWORD:password!}
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: true
hibernate:
ddl-auto: create
43 changes: 43 additions & 0 deletions src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
spring:
datasource:
hikari:
maximum-pool-size: 20
max-lifetime: 60000
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
jdbc-url: jdbc:tc:mysql:8.0.24://localhost:3306/test
connection-timeout: 5000
pool-name: Spring-HikariPool
dbcp2:
driver-class-name: com.mysql.cj.jdbc.Driver
test-on-borrow: true
validation-query: SELECT 1
jpa:
show-sql: true
hibernate:
ddl-auto: create
generate-ddl: true
jdbc:
template:
query-timeout: 2

userlock:
datasource:
hikari:
maximum-pool-size: 20
max-lifetime: 60000
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
jdbc-url: jdbc:tc:mysql:8.0.24://localhost:3306/test
connection-timeout: 5000
pool-name: UserLock-HikariPool

logging:
level:
org.hibernate:
SQL: debug
tool.hbm2ddl: debug
type: trace
stat: debug
type.BasicTypeRegistry: warn
org.springframework.jdbc: debug
org.springframework.transaction: debug
bankingapi.concurrency: debug
31 changes: 29 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
spring:
profiles:
active: local
datasource:
hikari:
maximum-pool-size: 20
max-lifetime: 60000
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/money_transfer_service?characterEncoding=UTF-8&serverTimezone=Asia/Seoul}
username: ${SPRING_DATASOURCE_USERNAME:root}
password: ${SPRING_DATASOURCE_PASSWORD:password!}
connection-timeout: 5000
pool-name: Spring-HikariPool

jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQLDialect
show-sql: true
hibernate:
ddl-auto: create

userlock:
datasource:
hikari:
maximum-pool-size: 20
max-lifetime: 60000
jdbc-url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/money_transfer_service?characterEncoding=UTF-8&serverTimezone=Asia/Seoul}
username: ${SPRING_DATASOURCE_USERNAME:root}
password: ${SPRING_DATASOURCE_PASSWORD:password!}
driver-class-name: com.mysql.cj.jdbc.Driver
connection-timeout: 5000
pool-name: UserLock-HikariPool
2 changes: 2 additions & 0 deletions src/test/java/bankingapi/BankingApiApplicationTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@SpringBootTest
class BankingApiApplicationTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import static org.assertj.core.api.Assertions.*;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.random.RandomGenerator;

import bankingapi.concurrency.ConcurrencyManager;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -15,11 +17,15 @@
import bankingapi.banking.domain.Account;
import bankingapi.banking.domain.Money;
import bankingapi.util.generator.AccountNumberGenerator;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@SpringBootTest
class ConcurrencyManagerWithNamedLockTest {
private static final int NUMBER_OF_THREADS = 10;
private static final int POLL_SIZE = 10;
private static final Money ONE = new Money(1);
@Autowired
private ConcurrencyManager concurrencyManager;
private CountDownLatch latch;
Expand Down Expand Up @@ -63,11 +69,11 @@ void calculateAtSameTime_controllingConcurrency() throws InterruptedException {
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
service.execute(() -> {
try {
concurrencyManager.executeWithLock("lock1", "lock2", () -> {
account.deposit(new Money(1));
}
);
}finally {
Thread.sleep(RandomGenerator.getDefault().nextInt(0, 50));
concurrencyManager.executeWithLock("lock1", "lock2", () -> account.deposit(ONE));
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
latch.countDown();
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@SpringBootTest
class IdempotentRequestHistoryServiceTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import bankingapi.member.domain.Member;
import bankingapi.member.domain.MemberRepository;
import bankingapi.member.exception.NotExistMemberException;

@ActiveProfiles("test")
@Transactional
@SpringBootTest
class CustomUserDetailServiceTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import bankingapi.member.domain.Member;
import bankingapi.member.domain.MemberRepository;
import bankingapi.member.dto.RegisterCommand;
import bankingapi.member.exception.NotExistMemberException;

@ActiveProfiles("test")
@Transactional
@SpringBootTest
class MemberApplicationServiceTest {
Expand Down
2 changes: 2 additions & 0 deletions src/test/java/bankingapi/social/domain/FriendServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

@ActiveProfiles("test")
@Transactional
@SpringBootTest
class FriendServiceTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import bankingapi.member.domain.Member;
import bankingapi.member.domain.MemberRepository;

@ActiveProfiles("test")
@Transactional
@SpringBootTest
class SocialNetworkServiceTest {
Expand Down
16 changes: 0 additions & 16 deletions src/test/resources/application.yml

This file was deleted.

0 comments on commit 01833f7

Please sign in to comment.