diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bff7a3b8..9d197bac 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -162,4 +162,4 @@ media: coupang: partners: # 제휴 링크에 lptag로 노출되는 공개 식별자다. 소재 등록 시 남의 링크가 아닌지 대조하는 데 쓴다. - id: ${COUPANG_PARTNERS_ID} + id: ${COUPANG_PARTNERS_ID:} diff --git a/src/test/java/com/swyp/picke/global/config/AdPropertyDefaultTest.java b/src/test/java/com/swyp/picke/global/config/AdPropertyDefaultTest.java new file mode 100644 index 00000000..6d43f335 --- /dev/null +++ b/src/test/java/com/swyp/picke/global/config/AdPropertyDefaultTest.java @@ -0,0 +1,46 @@ +package com.swyp.picke.global.config; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * 광고 환경변수에 기본값이 없으면 값이 빠진 서버에서 앱 전체가 뜨지 않는다. + * 광고와 무관한 API까지 같이 죽는다. 실제로 COUPANG_PARTNERS_ID 때문에 dev가 502로 내려간 적이 있다. + * + *

테스트 설정(application-test.yml)이 값을 박아 두기 때문에 컨텍스트를 띄우는 것만으로는 + * 이 경우를 재현할 수 없다. 그래서 설정 파일의 플레이스홀더 자체를 검사한다. + */ +class AdPropertyDefaultTest { + + private static final Pattern PLACEHOLDER = Pattern.compile("\\$\\{(COUPANG_[A-Z0-9_]+|ADPICK_[A-Z0-9_]+)(:[^}]*)?}"); + + @Test + @DisplayName("광고 환경변수는 모두 기본값을 갖는다. 값이 없어도 앱은 떠야 한다") + void adPlaceholders_haveDefaults() throws IOException { + String yml = new String(new ClassPathResource("application.yml").getInputStream().readAllBytes(), + StandardCharsets.UTF_8); + + Matcher matcher = PLACEHOLDER.matcher(yml); + List missingDefaults = new ArrayList<>(); + int found = 0; + while (matcher.find()) { + found++; + if (matcher.group(2) == null) { + missingDefaults.add(matcher.group(1)); + } + } + + assertThat(found).isPositive(); + assertThat(missingDefaults).isEmpty(); + } +} diff --git a/src/test/java/com/swyp/picke/global/config/SwaggerAdGroupTest.java b/src/test/java/com/swyp/picke/global/config/SwaggerAdGroupTest.java new file mode 100644 index 00000000..4767b884 --- /dev/null +++ b/src/test/java/com/swyp/picke/global/config/SwaggerAdGroupTest.java @@ -0,0 +1,48 @@ +package com.swyp.picke.global.config; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * 사용자 그룹은 FE_USED_OPERATIONS 화이트리스트로, 관리자 그룹은 pathsToExclude 로 광고를 걷어낸다. + * 둘 중 하나만 손대도 광고 탭이 조용히 비어 버리므로 그룹 구성 자체를 고정해 둔다. + */ +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class SwaggerAdGroupTest { + + private static final String AD_GROUP = "3. 광고 API"; + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("광고 API는 스웨거 그룹 선택 목록에 별도 탭으로 나온다") + void swaggerConfig_exposesAdGroup() throws Exception { + mockMvc.perform(get("/v3/api-docs/swagger-config")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.urls[?(@.name == '" + AD_GROUP + "')]").exists()); + } + + @Test + @DisplayName("광고 탭에는 앱용 조회·집계와 관리자용 소재 관리가 함께 묶인다") + void adGroup_containsAppAndAdminOperations() throws Exception { + mockMvc.perform(get("/v3/api-docs/" + AD_GROUP)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.paths['/api/v1/ads'].get").exists()) + .andExpect(jsonPath("$.paths['/api/v1/ads/impressions'].post").exists()) + .andExpect(jsonPath("$.paths['/api/v1/admin/ads'].get").exists()) + .andExpect(jsonPath("$.paths['/api/v1/admin/ads/stats'].get").exists()) + .andExpect(jsonPath("$.paths['/api/v1/admin/ads/clicks'].get").exists()); + } +}