From 9d2499e7fb17e4684578e18f288800c08144bed2 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:09:24 +0900 Subject: [PATCH 01/12] =?UTF-8?q?chore:=20ci=20=EC=8A=A4=ED=81=AC=EB=A6=BD?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..794b49827 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI with Gradle + +on: + pull_request: + branches: [ "develop", "release", "master" ] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Make Gradle wrapper executable + run: chmod +x ./gradlew + + - name: Build with Gradle Wrapper + run: ./gradlew build + + - name: Publish Test Report + uses: mikepenz/action-junit-report@v5 + if: success() || failure() + with: + report_paths: '**/build/test-results/test/TEST-*.xml' From 4a4beef8cd79d8c87c50f3b995f06f4070f5fe8d Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:10:36 +0900 Subject: [PATCH 02/12] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20application.yml=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/resources/application.yml | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/test/resources/application.yml diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml new file mode 100644 index 000000000..6b66ea613 --- /dev/null +++ b/src/test/resources/application.yml @@ -0,0 +1,72 @@ +spring: + +# db + data: + redis: + host: localhost + port: 6379 + jpa: + hibernate: + ddl-auto: create-drop + generate-ddl: true + show-sql: true + database: mysql + properties: + hibernate: + format_sql: true + flyway: + enabled: false + +# cloud +cloud: + aws: + credentials: + access-key: access-key + secret-key: access-key + region: + static: ap-northeast-2 + stack: + auto: false + s3: + bucket: solid-connection-uploaded + url: + default: default-url + uploaded: uploaded-url + cloudFront: + url: + default: default-url + uploaded: uploaded-url + +# variable +view: + count: + scheduling: + delay: 3000 +oauth: + apple: + token-url: "https://appleid.apple.com/auth/token" + client-secret-audience-url: "https://appleid.apple.com" + public-key-url: "https://appleid.apple.com/auth/keys" + client-id: client-id + team-id: team-id + key-id: key-id + redirect-url: "https://localhost:8080/auth/apple" + kakao: + redirect-url: "http://localhost:8080/auth/kakao" + client-id: client-id + token-url: "https://kauth.kakao.com/oauth/token" + user-info_url: "https://kapi.kakao.com/v2/user/me" +sentry: + environment: test + dsn: "https://test-public-key@sentry.test-domain.io/123456" + send-default-pii: true + traces-sample-rate: 1.0 + exception-resolver-order: -2147483647 +university: + term: 2024-1 +jwt: + secret: + 1234567-1234-1234-1234-12345678901 +cors: + allowed-origins: + - "http://localhost:8080" From 258afc3baa7770ee9cbd65fb6cbb7d135cf38cc1 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:11:25 +0900 Subject: [PATCH 03/12] =?UTF-8?q?test:=20test=20profile=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/database/DatabaseConnectionTest.java | 2 -- .../example/solidconnection/database/RedisConnectionTest.java | 2 -- .../com/example/solidconnection/support/DatabaseCleaner.java | 2 -- .../solidconnection/support/TestContainerDataJpaTest.java | 2 -- .../solidconnection/support/TestContainerSpringBootTest.java | 2 -- 5 files changed, 10 deletions(-) diff --git a/src/test/java/com/example/solidconnection/database/DatabaseConnectionTest.java b/src/test/java/com/example/solidconnection/database/DatabaseConnectionTest.java index d156cf485..ca3c64c7a 100644 --- a/src/test/java/com/example/solidconnection/database/DatabaseConnectionTest.java +++ b/src/test/java/com/example/solidconnection/database/DatabaseConnectionTest.java @@ -8,7 +8,6 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ActiveProfiles; import java.sql.DatabaseMetaData; import java.sql.SQLException; @@ -20,7 +19,6 @@ @Disabled @AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2, replace = AutoConfigureTestDatabase.Replace.ANY) -@ActiveProfiles("test") @DataJpaTest class DatabaseConnectionTest { diff --git a/src/test/java/com/example/solidconnection/database/RedisConnectionTest.java b/src/test/java/com/example/solidconnection/database/RedisConnectionTest.java index 69fcedaef..527ae7e07 100644 --- a/src/test/java/com/example/solidconnection/database/RedisConnectionTest.java +++ b/src/test/java/com/example/solidconnection/database/RedisConnectionTest.java @@ -6,12 +6,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.test.context.ActiveProfiles; import static org.assertj.core.api.Assertions.assertThat; @Disabled -@ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class RedisConnectionTest { diff --git a/src/test/java/com/example/solidconnection/support/DatabaseCleaner.java b/src/test/java/com/example/solidconnection/support/DatabaseCleaner.java index bb77f82f2..aee6a2bc6 100644 --- a/src/test/java/com/example/solidconnection/support/DatabaseCleaner.java +++ b/src/test/java/com/example/solidconnection/support/DatabaseCleaner.java @@ -5,13 +5,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Objects; -@ActiveProfiles("test") @Component public class DatabaseCleaner { diff --git a/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java b/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java index 339672e60..2f09151d6 100644 --- a/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java +++ b/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java @@ -3,7 +3,6 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; import org.testcontainers.junit.jupiter.Testcontainers; import java.lang.annotation.ElementType; @@ -13,7 +12,6 @@ @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ActiveProfiles("test") @Testcontainers @Import(MySQLTestContainer.class) @Target(ElementType.TYPE) diff --git a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java index fe9b74f60..50ab2e5ff 100644 --- a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java +++ b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java @@ -4,7 +4,6 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; import org.testcontainers.junit.jupiter.Testcontainers; import java.lang.annotation.ElementType; @@ -15,7 +14,6 @@ @ExtendWith({DatabaseClearExtension.class}) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) -@ActiveProfiles("test") @Testcontainers @Import({MySQLTestContainer.class, RedisTestContainer.class}) @Target(ElementType.TYPE) From 88d3d182aaa1e9170b92e9ff483ba0672b0e89f3 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:31:54 +0900 Subject: [PATCH 04/12] =?UTF-8?q?refactor:=20=EC=95=A0=ED=94=8C=20?= =?UTF-8?q?=EC=8B=9C=ED=81=AC=EB=A6=BF=ED=82=A4=EB=A5=BC=20yml=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/AppleOAuthClientSecretProvider.java | 16 +++++----------- .../client/AppleOAuthClientProperties.java | 3 ++- src/test/resources/application.yml | 3 ++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java index 2de0b7291..3ba2bbcb0 100644 --- a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java +++ b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java @@ -9,15 +9,12 @@ import org.apache.tomcat.util.codec.binary.Base64; import org.springframework.stereotype.Component; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Date; -import java.util.stream.Collectors; import static com.example.solidconnection.custom.exception.ErrorCode.FAILED_TO_READ_APPLE_PRIVATE_KEY; @@ -32,7 +29,6 @@ public class AppleOAuthClientSecretProvider { private static final String KEY_ID_HEADER = "kid"; private static final long TOKEN_DURATION = 1000 * 60 * 10; // 10min - private static final String SECRET_KEY_PATH = "secret/AppleOAuthKey.p8"; private final AppleOAuthClientProperties appleOAuthClientProperties; private PrivateKey privateKey; @@ -58,15 +54,13 @@ public String generateClientSecret() { } private PrivateKey readPrivateKey() { - try (InputStream is = getClass().getClassLoader().getResourceAsStream(SECRET_KEY_PATH); - BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - - String secretKey = reader.lines().collect(Collectors.joining("\n")); + try { + String secretKey = appleOAuthClientProperties.secretKey(); byte[] encoded = Base64.decodeBase64(secretKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); KeyFactory keyFactory = KeyFactory.getInstance("EC"); return keyFactory.generatePrivate(keySpec); - } catch (Exception e) { + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new CustomException(FAILED_TO_READ_APPLE_PRIVATE_KEY); } } diff --git a/src/main/java/com/example/solidconnection/config/client/AppleOAuthClientProperties.java b/src/main/java/com/example/solidconnection/config/client/AppleOAuthClientProperties.java index 609e9ee89..c04908583 100644 --- a/src/main/java/com/example/solidconnection/config/client/AppleOAuthClientProperties.java +++ b/src/main/java/com/example/solidconnection/config/client/AppleOAuthClientProperties.java @@ -10,6 +10,7 @@ public record AppleOAuthClientProperties( String publicKeyUrl, String clientId, String teamId, - String keyId + String keyId, + String secretKey ) { } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 6b66ea613..bbebc8002 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -51,7 +51,8 @@ oauth: team-id: team-id key-id: key-id redirect-url: "https://localhost:8080/auth/apple" - kakao: + secret-key: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAfGIQ3TtNYAZG7i3m72odmdhfymkM9wAFg2rEL2RKUEA== +kakao: redirect-url: "http://localhost:8080/auth/kakao" client-id: client-id token-url: "https://kauth.kakao.com/oauth/token" From bf221bb4a3c5e7e0f395b72e4bc8bc28fcf00b20 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:32:52 +0900 Subject: [PATCH 05/12] =?UTF-8?q?refactor:=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/client/AppleOAuthClientSecretProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java index 3ba2bbcb0..401a18b7b 100644 --- a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java +++ b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java @@ -35,7 +35,7 @@ public class AppleOAuthClientSecretProvider { @PostConstruct private void initPrivateKey() { - privateKey = readPrivateKey(); + privateKey = loadPrivateKey(); } public String generateClientSecret() { @@ -53,7 +53,7 @@ public String generateClientSecret() { .compact(); } - private PrivateKey readPrivateKey() { + private PrivateKey loadPrivateKey() { try { String secretKey = appleOAuthClientProperties.secretKey(); byte[] encoded = Base64.decodeBase64(secretKey); From ce48dd5d3cfb3c7a628062f67712429c245f4548 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:33:26 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/client/AppleOAuthClientSecretProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java index 401a18b7b..31228e5d3 100644 --- a/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java +++ b/src/main/java/com/example/solidconnection/auth/client/AppleOAuthClientSecretProvider.java @@ -19,7 +19,7 @@ import static com.example.solidconnection.custom.exception.ErrorCode.FAILED_TO_READ_APPLE_PRIVATE_KEY; /* - * 애플 OAuth 에 필요하 클라이언트 시크릿은 매번 동적으로 생성해야 한다. + * 애플 OAuth 에 필요한 클라이언트 시크릿은 매번 동적으로 생성해야 한다. * 클라이언트 시크릿은 애플 개발자 계정에서 발급받은 개인키(*.p8)를 사용하여 JWT 를 생성한다. * https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret * */ From bac8b4eda343d5c0cf89ccde28349a9d89fcce7d Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 26 Mar 2025 16:58:02 +0900 Subject: [PATCH 07/12] =?UTF-8?q?refactor:=20redis=20testcontainers=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/RedisTestContainer.java | 33 +++++++++---------- .../support/TestContainerSpringBootTest.java | 4 ++- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/example/solidconnection/support/RedisTestContainer.java b/src/test/java/com/example/solidconnection/support/RedisTestContainer.java index 39f35c2d5..212499361 100644 --- a/src/test/java/com/example/solidconnection/support/RedisTestContainer.java +++ b/src/test/java/com/example/solidconnection/support/RedisTestContainer.java @@ -1,28 +1,25 @@ package com.example.solidconnection.support; -import jakarta.annotation.PostConstruct; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.springframework.test.context.DynamicPropertySource; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; import org.testcontainers.containers.GenericContainer; -import org.testcontainers.junit.jupiter.Container; -@TestConfiguration -public class RedisTestContainer { +public class RedisTestContainer implements ApplicationContextInitializer { - @Container - private static final GenericContainer CONTAINER = new GenericContainer<>("redis:7.0"); + private static final int ORIGINAL_PORT = 6379; + private static final GenericContainer CONTAINER = new GenericContainer<>("redis:7.0") + .withExposedPorts(ORIGINAL_PORT); - @DynamicPropertySource - static void redisProperties(DynamicPropertyRegistry registry) { - registry.add("spring.redis.host", CONTAINER::getHost); - registry.add("spring.redis.port", CONTAINER::getFirstMappedPort); + static { + CONTAINER.start(); } - @PostConstruct - void startContainer() { - if (!CONTAINER.isRunning()) { - CONTAINER.start(); - } + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + TestPropertyValues.of( + "spring.data.redis.host=" + CONTAINER.getHost(), + "spring.data.redis.port=" + CONTAINER.getMappedPort(ORIGINAL_PORT) + ).applyTo(applicationContext.getEnvironment()); } } diff --git a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java index 50ab2e5ff..8d0d5d99a 100644 --- a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java +++ b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java @@ -4,6 +4,7 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; import org.testcontainers.junit.jupiter.Testcontainers; import java.lang.annotation.ElementType; @@ -12,10 +13,11 @@ import java.lang.annotation.Target; @ExtendWith({DatabaseClearExtension.class}) +@ContextConfiguration(initializers = RedisTestContainer.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers -@Import({MySQLTestContainer.class, RedisTestContainer.class}) +@Import({MySQLTestContainer.class}) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestContainerSpringBootTest { From 5009561ef2bbfc93998bd37ea2d4d09210f01778 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 27 Mar 2025 16:06:09 +0900 Subject: [PATCH 08/12] =?UTF-8?q?refactor:=20ddl-auto=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create-drop을 create로 변경 - 테스트 컨테이너를 실행해서 테스트하기 때문에, 테스트가 종료되면 당연히 테이블이 삭제된다. 따라서 create-drop을 하는것과 create를 하는 것이 동일하게 동작한다. 굳이 create로 바꾼 것은 삭제 시 FK 위반으로 WARN 로그가 불필요하게 백몇줄이 찍히는걸 막기 위해서. --- src/test/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index bbebc8002..e8db19044 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -7,7 +7,7 @@ spring: port: 6379 jpa: hibernate: - ddl-auto: create-drop + ddl-auto: create generate-ddl: true show-sql: true database: mysql From 2bc5313514ac0040a206e5f3cf345a224c0358fe Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Sun, 30 Mar 2025 05:56:30 +0900 Subject: [PATCH 09/12] =?UTF-8?q?test:=20e2e=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 깨지는 테스트 수정 - 비지니스 로직 변경으로 더 이상 해당되지 않는 테스트 삭제 --- .../e2e/ApplicantsQueryTest.java | 88 ++++--------------- 1 file changed, 18 insertions(+), 70 deletions(-) diff --git a/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java b/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java index 868eac179..03d130542 100644 --- a/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java +++ b/src/test/java/com/example/solidconnection/e2e/ApplicantsQueryTest.java @@ -105,7 +105,7 @@ public void setUpUserAndToken() { ApplicationsResponse response = RestAssured.given().log().all() .header("Authorization", "Bearer " + accessToken) .when().log().all() - .get("/applications") + .get("/applications/competitors") .then().log().all() .statusCode(200) .extract().as(ApplicationsResponse.class); @@ -119,30 +119,24 @@ public void setUpUserAndToken() { List.of(ApplicantResponse.of(사용자1_지원정보, false))), UniversityApplicantsResponse.of(괌대학_B_지원_정보, List.of(ApplicantResponse.of(나의_지원정보, true))), - UniversityApplicantsResponse.of(메이지대학_지원_정보, - List.of(ApplicantResponse.of(사용자2_지원정보, false))), - UniversityApplicantsResponse.of(네바다주립대학_라스베이거스_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false))) + UniversityApplicantsResponse.of(린츠_카톨릭대학_지원_정보, + List.of()) )); assertThat(secondChoiceApplicants).containsAnyElementsOf(List.of( UniversityApplicantsResponse.of(괌대학_A_지원_정보, - List.of(ApplicantResponse.of(나의_지원정보, true))), + List.of(ApplicantResponse.of(나의_지원정보, false))), UniversityApplicantsResponse.of(괌대학_B_지원_정보, - List.of(ApplicantResponse.of(사용자1_지원정보, false))), - UniversityApplicantsResponse.of(메이지대학_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false))), - UniversityApplicantsResponse.of(그라츠대학_지원_정보, - List.of(ApplicantResponse.of(사용자2_지원정보, false))) + List.of(ApplicantResponse.of(사용자1_지원정보, true))), + UniversityApplicantsResponse.of(린츠_카톨릭대학_지원_정보, + List.of()) )); assertThat(thirdChoiceApplicants).containsAnyElementsOf(List.of( + UniversityApplicantsResponse.of(괌대학_A_지원_정보, + List.of()), + UniversityApplicantsResponse.of(괌대학_B_지원_정보, + List.of()), UniversityApplicantsResponse.of(린츠_카톨릭대학_지원_정보, - List.of(ApplicantResponse.of(나의_지원정보, true))), - UniversityApplicantsResponse.of(서던덴마크대학교_지원_정보, - List.of(ApplicantResponse.of(사용자2_지원정보, false))), - UniversityApplicantsResponse.of(그라츠공과대학_지원_정보, - List.of(ApplicantResponse.of(사용자1_지원정보, false))), - UniversityApplicantsResponse.of(메이지대학_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false))) + List.of(ApplicantResponse.of(나의_지원정보, true))) )); } @@ -151,7 +145,7 @@ public void setUpUserAndToken() { ApplicationsResponse response = RestAssured.given().log().all() .header("Authorization", "Bearer " + accessToken) .when().log().all() - .get("/applications?region=" + 영미권.getCode()) + .get("/applications/competitors?region=" + 영미권.getCode()) .then().log().all() .statusCode(200) .extract().as(ApplicationsResponse.class); @@ -163,60 +157,14 @@ public void setUpUserAndToken() { UniversityApplicantsResponse.of(괌대학_A_지원_정보, List.of(ApplicantResponse.of(사용자1_지원정보, false))), UniversityApplicantsResponse.of(괌대학_B_지원_정보, - List.of(ApplicantResponse.of(나의_지원정보, true))), - UniversityApplicantsResponse.of(네바다주립대학_라스베이거스_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false))))); + List.of(ApplicantResponse.of(나의_지원정보, true))) + )); assertThat(secondChoiceApplicants).containsAnyElementsOf(List.of( UniversityApplicantsResponse.of(괌대학_A_지원_정보, List.of(ApplicantResponse.of(나의_지원정보, true))), UniversityApplicantsResponse.of(괌대학_B_지원_정보, - List.of(ApplicantResponse.of(사용자1_지원정보, false))))); - } - - @Test - void 대학_국문_이름으로_필터링해서_지원자를_조회한다() { - ApplicationsResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().log().all() - .get("/applications?keyword=라") - .then().log().all() - .statusCode(200) - .extract().as(ApplicationsResponse.class); - - List firstChoiceApplicants = response.firstChoice(); - List secondChoiceApplicants = response.secondChoice(); - - assertThat(firstChoiceApplicants).containsExactlyInAnyOrder( - UniversityApplicantsResponse.of(그라츠대학_지원_정보, List.of()), - UniversityApplicantsResponse.of(그라츠공과대학_지원_정보, List.of()), - UniversityApplicantsResponse.of(네바다주립대학_라스베이거스_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false)))); - assertThat(secondChoiceApplicants).containsAnyElementsOf(List.of( - UniversityApplicantsResponse.of(그라츠대학_지원_정보, - List.of(ApplicantResponse.of(사용자2_지원정보, false))), - UniversityApplicantsResponse.of(그라츠공과대학_지원_정보, - List.of(ApplicantResponse.of(사용자3_지원정보, false))), - UniversityApplicantsResponse.of(네바다주립대학_라스베이거스_지원_정보, List.of()))); - } - - @Test - void 국가_국문_이름으로_필터링해서_지원자를_조회한다() { - ApplicationsResponse response = RestAssured.given().log().all() - .header("Authorization", "Bearer " + accessToken) - .when().log().all() - .get("/applications?keyword=일본") - .then().log().all() - .statusCode(200) - .extract().as(ApplicationsResponse.class); - - List firstChoiceApplicants = response.firstChoice(); - List secondChoiceApplicants = response.secondChoice(); - - assertThat(firstChoiceApplicants).containsExactlyInAnyOrder( - UniversityApplicantsResponse.of(메이지대학_지원_정보, - List.of(ApplicantResponse.of(사용자2_지원정보, false)))); - assertThat(secondChoiceApplicants).containsExactlyInAnyOrder( - UniversityApplicantsResponse.of(메이지대학_지원_정보, List.of())); + List.of(ApplicantResponse.of(사용자1_지원정보, false))) + )); } @Test @@ -224,7 +172,7 @@ public void setUpUserAndToken() { ApplicationsResponse response = RestAssured.given().log().all() .header("Authorization", "Bearer " + accessToken) .when().log().all() - .get("/applications") + .get("/applications/competitors") .then().log().all() .statusCode(200) .extract().as(ApplicationsResponse.class); From ca3b3671b066a56cc4e3af5c825177f2ec2f105c Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Sun, 30 Mar 2025 06:08:22 +0900 Subject: [PATCH 10/12] =?UTF-8?q?chore:=20createAt=EA=B3=BC=20updateAt?= =?UTF-8?q?=EC=9D=98=20=EB=82=98=EB=85=B8=EC=B4=88=20=EA=B8=B8=EC=9D=B4=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/solidconnection/entity/common/BaseEntity.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/solidconnection/entity/common/BaseEntity.java b/src/main/java/com/example/solidconnection/entity/common/BaseEntity.java index 27493f1be..508953f88 100644 --- a/src/main/java/com/example/solidconnection/entity/common/BaseEntity.java +++ b/src/main/java/com/example/solidconnection/entity/common/BaseEntity.java @@ -9,9 +9,11 @@ import org.hibernate.annotations.DynamicUpdate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.time.ZoneId; import java.time.ZonedDateTime; +import static java.time.ZoneOffset.UTC; +import static java.time.temporal.ChronoUnit.MICROS; + @MappedSuperclass @EntityListeners(AuditingEntityListener.class) @Getter @@ -24,12 +26,12 @@ public abstract class BaseEntity { @PrePersist public void onPrePersist() { - this.createdAt = ZonedDateTime.now(ZoneId.of("UTC")); + this.createdAt = ZonedDateTime.now(UTC).truncatedTo(MICROS); // 나노초 6자리 까지만 저장 this.updatedAt = this.createdAt; } @PreUpdate public void onPreUpdate() { - this.updatedAt = ZonedDateTime.now(ZoneId.of("UTC")); + this.updatedAt = ZonedDateTime.now(UTC).truncatedTo(MICROS); } } From 3d203e8d521f5fad201cbc6c63a99e1c05528859 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Mon, 31 Mar 2025 04:51:28 +0900 Subject: [PATCH 11/12] =?UTF-8?q?style:=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index e8db19044..7c6f83171 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -51,7 +51,7 @@ oauth: team-id: team-id key-id: key-id redirect-url: "https://localhost:8080/auth/apple" - secret-key: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAfGIQ3TtNYAZG7i3m72odmdhfymkM9wAFg2rEL2RKUEA== + secret-key: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAfGIQ3TtNYAZG7i3m72odmdhfymkM9wAFg2rEL2RKUEA== # base64 encoded 된 임의의 값 kakao: redirect-url: "http://localhost:8080/auth/kakao" client-id: client-id From c364691b7e60d5940b0cc3752a73b15a1f2f9279 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 1 Apr 2025 04:01:26 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20MySQL=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - redis 테스트 컨테이너와 동일하게 설정하여 불필요한 인지 부하를 줄인다. --- .../support/MySQLTestContainer.java | 36 +++++++------------ .../support/TestContainerDataJpaTest.java | 4 +-- .../support/TestContainerSpringBootTest.java | 4 +-- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/test/java/com/example/solidconnection/support/MySQLTestContainer.java b/src/test/java/com/example/solidconnection/support/MySQLTestContainer.java index 0256fec13..d4e25ccde 100644 --- a/src/test/java/com/example/solidconnection/support/MySQLTestContainer.java +++ b/src/test/java/com/example/solidconnection/support/MySQLTestContainer.java @@ -1,34 +1,24 @@ package com.example.solidconnection.support; -import jakarta.annotation.PostConstruct; -import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.junit.jupiter.Container; -import javax.sql.DataSource; +public class MySQLTestContainer implements ApplicationContextInitializer { -@TestConfiguration -public class MySQLTestContainer { - - @Container private static final MySQLContainer CONTAINER = new MySQLContainer<>("mysql:8.0"); - @Bean - public DataSource dataSource() { - return DataSourceBuilder.create() - .url(CONTAINER.getJdbcUrl()) - .username(CONTAINER.getUsername()) - .password(CONTAINER.getPassword()) - .driverClassName(CONTAINER.getDriverClassName()) - .build(); + static { + CONTAINER.start(); } - @PostConstruct - void startContainer() { - if (!CONTAINER.isRunning()) { - CONTAINER.start(); - } + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + TestPropertyValues.of( + "spring.datasource.url=" + CONTAINER.getJdbcUrl(), + "spring.datasource.username=" + CONTAINER.getUsername(), + "spring.datasource.password=" + CONTAINER.getPassword() + ).applyTo(applicationContext.getEnvironment()); } } diff --git a/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java b/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java index 2f09151d6..415b21e78 100644 --- a/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java +++ b/src/test/java/com/example/solidconnection/support/TestContainerDataJpaTest.java @@ -2,7 +2,7 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; import org.testcontainers.junit.jupiter.Testcontainers; import java.lang.annotation.ElementType; @@ -13,7 +13,7 @@ @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers -@Import(MySQLTestContainer.class) +@ContextConfiguration(initializers = MySQLTestContainer.class) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestContainerDataJpaTest { diff --git a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java index 8d0d5d99a..5c5c93742 100644 --- a/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java +++ b/src/test/java/com/example/solidconnection/support/TestContainerSpringBootTest.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.testcontainers.junit.jupiter.Testcontainers; @@ -13,11 +12,10 @@ import java.lang.annotation.Target; @ExtendWith({DatabaseClearExtension.class}) -@ContextConfiguration(initializers = RedisTestContainer.class) +@ContextConfiguration(initializers = {RedisTestContainer.class, MySQLTestContainer.class}) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers -@Import({MySQLTestContainer.class}) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestContainerSpringBootTest {