상황 설명
1. 우리 프로젝트는 PR 올리면 자동으로 테스트를 실행시키기 위해(CI 빌더로써) github action 을 활용한다.
2. 네이버망에 있는 서버와 API 통신을 할 때 Proxy 서버를 거쳐서 가도록 수정이 필요하다(보안 요구사항).
WebClient 는 아래 코드와 같이 isSecurityProxyEnabled 가 true 인 경우(Proxy 서버를 거쳐가야 하는 경우), proxy 메서드를 통해 Proxy 서버 주소와 포트를 알려준다.
@Value("${security-proxy.enabled:false}")
private boolean isSecurityProxyEnabled; // true 이면, proxy서버를 거쳐야 한다
HttpClient httpClient = HttpClient.create(connectionProvider);
return isSecurityProxyEnabled
? httpClient
.proxy(it ->
it.type(ProxyProvider.Proxy.HTTP)
.host(proxy서버 도메인)
.port(443))
: httpClient;
문제 상황
deploay phase 에 따라 isSecurityProxyEnabled 값이 달라져야 한다. 먼저 로컬에서 실행시킬때와 로컬에서 테스트를 돌릴 때는 Proxy 를 거치지 않도록 설정한다. 다시말해 deploy phase local 과 test 는 false 여야 한다.
하지만 PR 올리면 trigger 로 동작하는 CI 빌더에서는 deploy phase test 도 true 로 동작해야한다. 그래서 github action workflows yml 파일에 true 를 주입하게 해서 해결했다.
- name: test
run: |
SECURITYPROXY_ENABLED=true \
그런데 또다른 문제가 생겼다. 테스트코드 중에서도 wire mock 으로 진행하는 internal 테스트와 실제 api 를 호출하는 external 테스트가 있는데, internal 테스트에서 에러가 나는것이다. 그래서 internal 일때와 external 일때를 구분지어 CI 빌더가 동작할 필요가 있고 github action matrix strategy 를 활용했다.
해결 방법
아래와 같이 github action yml 을 설정하면 step 이 external 일때 한번, internal 일때 한번 총 두번 병렬로 동작한다.
jobs:
test-api:
strategy:
matrix:
module: [ 'external', 'internal' ]
steps:
- name: api external test
if: ${{ matrix.module }} == 'external'
run: |
SECURITYPROXY_ENABLED=true \
-Dtest=external
... 생략
- name: api internal test
if: ${{ matrix.module }} == 'internal'
run: |
SECURITYPROXY_ENABLED=false \
-Dtest=internal
... 생략
추가 설명
위 github action yml 설정에 -Dtest=external 과 -Dtest=internal 도 있다. java 옵션 명령어 인 -D<name>=<value> 는 system property 를 추가한다. 그리고 각 모듈 build.gradle 에서 "test" 시스템 변수를 가져와서 external 이면 includeTags 에 external 을 넣고 failFast 를 false 로 한다.
test {
useJUnitPlatform {
def testScope = System.getProperty("test")
if (testScope == "external") {
includeTags "external"
failFast false
} else if (testScope == "internal") {
excludeTags "external"
failFast true
} else {
failFast true
}
...
}
includeTags 에 external 을 넣음으로써 아래 @ExternalTest 애노테이션이 붙은 테스트들이 동작하게 된다.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@ActiveProfiles("external")
@Tag("external")
annotation class ExternalTest
failFast 는 첫 번째 테스트에 실패한 후 테스트 실행을 중지할지 여부이다. external test 는 연동된 수많은 서버들을 mocking 없이 실제로 호출한다. 문제는 연동된 서버가 개발 서버이기 때문에 쉽게 죽거나 순단이 발생할 수 있다(개발서버 배포로 인해). 워낙 자주 깨지는 테스트다 보니 false 로 설정했다.
package org.gradle.api.tasks.testing;
public class Test extends AbstractTestTask implements JavaForkOptions, PatternFilterable {
@Option(
option = "fail-fast",
description = "Stops test execution after the first failed test."
)
public void setFailFast(boolean failFast) {
super.setFailFast(failFast);
}
'Computer Engineering' 카테고리의 다른 글
DB 장애로 인한 EDA 기반 이벤트 보정처리 (0) | 2023.01.15 |
---|---|
주문 동시성 이슈 정리 (0) | 2022.11.14 |
주문서 테스트코드 작성 이슈정리 (0) | 2022.05.07 |
nslookup 과 dig 명령어 결과 차이 (0) | 2022.01.12 |
자주 쓰는 쉘스크립트 모음 (0) | 2021.01.17 |