Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] Truncate 를 위한 DatabaseCleanup 구현 #118

Merged
merged 11 commits into from
Aug 1, 2023
Merged
92 changes: 92 additions & 0 deletions backend/src/test/java/com/mapbefine/mapbefine/DatabaseCleanup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.mapbefine.mapbefine;

import jakarta.persistence.Entity;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.metamodel.EntityType;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class DatabaseCleanup implements InitializingBean {

private static final String SET_REFERENTIAL_INTEGRITY_SQL_MESSAGE = "SET REFERENTIAL_INTEGRITY %s";
private static final String TRUNCATE_SQL_MESSAGE = "TRUNCATE TABLE %s";
private static final String ID_RESET_SQL_MESSAGE = "ALTER TABLE %s ALTER COLUMN ID RESTART WITH 1";
private static final String UNDERSCORE = "_";

@PersistenceContext
private EntityManager entityManager;

private List<String> tableNames;

@Override
public void afterPropertiesSet() {
Set<EntityType<?>> entities = entityManager.getMetamodel()
.getEntities();

tableNames = entities.stream()
.filter(this::isEntity)
.map(this::convertTableNameFromCamelCaseToSnakeCase)
.toList();
}

private boolean isEntity(final EntityType<?> entityType) {
return entityType.getJavaType()
.getAnnotation(Entity.class) != null;
}

private String convertTableNameFromCamelCaseToSnakeCase(EntityType<?> entityType) {
StringBuilder tableNameSnake = new StringBuilder();
String classNameOfEntity = entityType.getName();

for (char letter : classNameOfEntity.toCharArray()) {
addUnderScoreForCapitalLetter(tableNameSnake, letter);
tableNameSnake.append(letter);
}

return tableNameSnake.substring(1).toLowerCase();
}

private void addUnderScoreForCapitalLetter(StringBuilder tableNameSnake, char letter) {
if (Character.isUpperCase(letter)) {
tableNameSnake.append(UNDERSCORE);
}
}

@Transactional
public void execute() {
executeSqlWithReferentialIntegrityDisabled(this::executeTruncate);
}

private void executeSqlWithReferentialIntegrityDisabled(Runnable sqlExecutor) {
disableReferentialIntegrity();
sqlExecutor.run();
enableReferentialIntegrity();
}

private void disableReferentialIntegrity() {
entityManager.flush();

entityManager.createNativeQuery(String.format(SET_REFERENTIAL_INTEGRITY_SQL_MESSAGE, false))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.format도 변수 처리해주면 어떨까요

.executeUpdate();
}

private void enableReferentialIntegrity() {
entityManager.createNativeQuery(String.format(SET_REFERENTIAL_INTEGRITY_SQL_MESSAGE, true))
.executeUpdate();
}

private void executeTruncate() {
for (String tableName : tableNames) {
entityManager.createNativeQuery(String.format(TRUNCATE_SQL_MESSAGE, tableName))
.executeUpdate();
entityManager.createNativeQuery(String.format(ID_RESET_SQL_MESSAGE, tableName))
.executeUpdate();
}
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
package com.mapbefine.mapbefine.integration;

import com.mapbefine.mapbefine.DatabaseCleanup;
import io.restassured.RestAssured;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.jdbc.Sql;

@Sql("/initialization.sql")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class IntegrationTest {

@LocalServerPort
int port;
private int port;

@Autowired
private DatabaseCleanup databaseCleanup;

@BeforeEach
public void setUp() {
RestAssured.port = port;
}

@AfterEach
public void tearDown() {
databaseCleanup.execute();
}

}