Skip to content

Commit

Permalink
Merge branch 'feat/test' into dev-check
Browse files Browse the repository at this point in the history
  • Loading branch information
versatile0010 committed Mar 27, 2024
2 parents 1e2d20d + 90bd052 commit 05096d3
Show file tree
Hide file tree
Showing 36 changed files with 595 additions and 55 deletions.
9 changes: 0 additions & 9 deletions .github/workflows/jib-build-depoly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,6 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: 🐧 create application.yml
run: |
mkdir -p ./daepiro-app/src/main/resources
cd ./daepiro-app/src/main/resources
touch ./application.yml
echo "${{ secrets.PROPERTIES_PROD }}" | base64 --decode > ./application.yml
ls -la
shell: bash

- name: 🐧 create service-account.json
run: |
mkdir -p ./daepiro-api/src/main/resources
Expand Down
10 changes: 7 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ out/

**/src/main/resources/service-account.json

*.yml
application.yml
application.properties
### test properties
!daepiro-api/src/test/resources/application.yml
!daepiro-auth/src/testFixtures/resources/application-auth-test.yml
!daepiro-common/src/testFixtures/resources/application-common-test.yml
!daepiro-core/src/testFixtures/resources/application-core-test.yml
!daepiro-crawler/src/testFixtures/resources/application-crawler-test.yml
!daepiro-redis/src/testFixtures/resources/application-redis-test.yml

### NetBeans ###
/nbproject/private/
Expand Down
22 changes: 22 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.3'
id 'com.google.cloud.tools.jib' version '3.4.0'
id 'java-test-fixtures'
}

group = 'com.numberone.backend'
Expand All @@ -27,6 +28,8 @@ subprojects {
apply plugin: 'java-library'
apply plugin: 'org.springframework.boot'
apply plugin: 'jacoco'
apply plugin: 'java-test-fixtures'
apply plugin: 'java'

configurations {
compileOnly {
Expand Down Expand Up @@ -60,6 +63,25 @@ subprojects {
// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

// aws secret manager
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap:3.1.3'
implementation 'org.springframework.cloud:spring-cloud-starter-aws-secrets-manager-config:2.2.6.RELEASE'
implementation 'com.amazonaws.secretsmanager:aws-secretsmanager-jdbc:1.0.8'

// test container
testImplementation 'org.testcontainers:testcontainers:1.19.3'
testImplementation 'org.testcontainers:junit-jupiter:1.19.3' // junit5
testImplementation 'org.testcontainers:mysql' // mysql

// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'

testFixturesImplementation 'org.springframework.boot:spring-boot-starter-test'

testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

}
4 changes: 4 additions & 0 deletions daepiro-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ dependencies {
implementation project(':daepiro-core')
implementation project(':daepiro-common')
implementation project(':daepiro-redis')

testImplementation(testFixtures(project(':daepiro-core')))
testImplementation(testFixtures(project(':daepiro-common')))
testImplementation(testFixtures(project(':daepiro-redis')))
}

bootJar {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public ResponseEntity<GetArticleDetailResponse> getArticleDetails(@PathVariable(
tag 가 null 이면, tag 상관 없이 전체 조회를 수행합니다.
tag 가 null 이 아니면, 해당 tag 에 해당하는 게시글만 조회합니다.
lastArticleId 는 직전에 조회한 게시글 중 가장 먀지막(작은) articleId 를 의미합니다.
lastArticleId 는 직전에 조회한 게시글 중 가장 마지막(작은) articleId 를 의미합니다.
- 첫 페이지를 요청할 경우에는 lastArticleId 를 null 로 보내야합니다.
- 첫 페이지 이후에 대한 요청은, 직전 페이지 요청에서 얻어온 lastArticleId 를 넣어서 보내면 그 다음 페이지를 호출합니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.numberone.backend.domain.notification.entity.NotificationTag;
import com.numberone.backend.domain.notification.repository.NotificationRepository;
import com.numberone.backend.domain.notificationregion.entity.NotificationRegion;
import com.numberone.backend.domain.notificationregion.repository.NotificationRegionRepository;
import com.numberone.backend.exception.conflict.UnauthorizedLocationException;
import com.numberone.backend.exception.notfound.NotFoundArticleException;
import com.numberone.backend.exception.notfound.NotFoundMemberException;
Expand Down Expand Up @@ -51,20 +50,24 @@
@Service
public class ArticleService {

// todo: 리팩토링 (db 정리하고, 불필요한 쿼리 + 비효율적인 코드 모두 제거 )


private final ArticleRepository articleRepository;
private final MemberRepository memberRepository;
private final ArticleParticipantRepository articleParticipantRepository;
private final ArticleImageRepository articleImageRepository;
private final CommentRepository commentRepository;
private final ArticleLikeRepository articleLikeRepository;
private final NotificationRegionRepository notificationRegionRepository;

private final NotificationRepository notificationRepository;
private final S3Provider s3Provider;
private final LocationProvider locationProvider;
private final FcmMessageProvider fcmMessageProvider;

@Transactional
public UploadArticleResponse uploadArticle(UploadArticleRequest request) {
// todo: 리팩토링
long id = SecurityContextProvider.getAuthenticatedUserId();
Member owner = memberRepository.findById(id)
.orElseThrow(NotFoundMemberException::new);
Expand All @@ -82,7 +85,7 @@ public UploadArticleResponse uploadArticle(UploadArticleRequest request) {
new ArticleParticipant(article, owner)
);

// 2. 이미지 업로드
// 2. 이미지 업로드 todo: 비동기 업로드
List<ArticleImage> articleImages = new ArrayList<>();
List<String> imageUrls = new ArrayList<>();
String thumbNailImageUrl = "";
Expand Down Expand Up @@ -185,16 +188,19 @@ public Slice<GetArticleListResponse> getArticleListPaging(ArticleSearchParameter
List<Long> memberLikedArticleIdList = articleLikeRepository.findByMember(member)
.stream().map(ArticleLike::getArticleId)
.toList();
return new SliceImpl<>(
articleRepository.getArticlesNoOffSetPaging(param, pageable)
.stream()
.peek(article -> {
updateArticleInfo(article, memberLikedArticleIdList);
})
.toList());

Slice<GetArticleListResponse> slices = articleRepository.getArticlesNoOffSetPaging(param, pageable);
List<GetArticleListResponse> content = slices.getContent().stream()
.peek(article -> {
updateArticleInfo(article, memberLikedArticleIdList);
})
.toList();

// todo: 리팩토링 ( slices 크기가 n 일 때, n * (3) 개의 쿼리가 발생하고 있음.)
return new SliceImpl<>(content, pageable, slices.hasNext());
}

public void updateArticleInfo(GetArticleListResponse articleInfo, List<Long> memberLikedArticleIdList) {
private void updateArticleInfo(GetArticleListResponse articleInfo, List<Long> memberLikedArticleIdList) {
Long ownerId = articleInfo.getOwnerId();
Long thumbNailImageUrlId = articleInfo.getThumbNailImageId();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.numberone.backend.domain.shelter.service;

import com.numberone.backend.domain.shelter.ShelterType;
import com.numberone.backend.domain.shelter.dto.ShelterMapper;
import com.numberone.backend.domain.shelter.dto.request.NearbyShelterRequest;
import com.numberone.backend.domain.shelter.dto.response.*;
import com.numberone.backend.domain.shelter.dto.response.GetShelterDatabaseUrlResponse;
import com.numberone.backend.domain.shelter.dto.response.NearbyShelterListResponse;
import com.numberone.backend.domain.shelter.dto.response.NearestShelterResponse;
import com.numberone.backend.domain.shelter.repository.ShelterRepository;
import com.numberone.backend.domain.shelter.ShelterType;
import com.numberone.backend.exception.notfound.NotFoundShelterException;
import com.numberone.backend.provider.s3.S3Provider;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -65,7 +67,7 @@ public NearbyShelterListResponse getNearbyShelterList(NearbyShelterRequest reque
return NearbyShelterListResponse.of(result);
}

public GetShelterDatabaseUrlResponse getShelterDatabaseInitUrl(){
public GetShelterDatabaseUrlResponse getShelterDatabaseInitUrl() {
return GetShelterDatabaseUrlResponse.of(s3Provider.getS3FileUrl(databaseUploadPath));
}
}
47 changes: 47 additions & 0 deletions daepiro-api/src/main/resources/application-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
spring:
config:
activate:
on-profile: local

kakao:
api-url: ${KAKAO_API_URL}
token-info-url: ${KAKAO_TOKEN_INFO_URL}
client-id: ${KAKAO_CLIENT_ID}
redirect-uri: ${KAKAO_REDIRECT_URL}
token-api-url: ${KAKAO_TOKEN_API_URL}
user-api-url: ${KAKAO_USER_API_URL}
map-api-url: ${KAKAO_MAP_API_URL}

naver:
client-id: ${NAVER_CLIENT_ID}
client-secret: ${NAVER_CLIENT_SECRET}
state: ${NAVER_STATE}
token-api-url: ${NAVER_TOKEN_API_URL}
user-api-url: ${NAVER_USER_API_URL}

storage-path:
shelter-database-init-path: ${SHELTER_DATABASE_INIT_PATH}

---

spring:
config:
activate:
on-profile: dev

kakao:
client-id: ${KAKAO_CLIENT_ID}
redirect-uri: ${KAKAO_REDIRECT_URL}
token-api-url: ${KAKAO_TOKEN_API_URL}
user-api-url: ${KAKAO_USER_API_URL}
map-api-url: ${KAKAO_MAP_API_URL}

naver:
client-id: ${NAVER_CLIENT_ID}
client-secret: ${NAVER_CLIENT_SECRET}
state: ${NAVER_STATE}
token-api-url: ${NAVER_TOKEN_API_URL}
user-api-url: ${NAVER_USER_API_URL}

storage-path:
shelter-database-init-path: ${SHELTER_DATABASE_INIT_PATH}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.numberone.backend;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;


@Slf4j
@SpringBootTest(classes = ServiceIntegrationTestConfiguration.class)
@Import({CoreTestConfiguration.class})
public abstract class ServiceIntegrationTestBase {

private static final String REDIS_DOCKER_IMAGE = "redis:5.0.3-alpine";
private static final String MYSQL_DOCKER_IMAGE = "mysql:8.0";
private static final String MYSQL_ROOT = "root";
private static final String MYSQL_PASSWORD = "1234";

private static final int REDIS_PORT = 6379;

@Container
protected static MySQLContainer mySQLContainer;

@Container
protected static GenericContainer redisContainer;

@DynamicPropertySource
static void configureProperties(final DynamicPropertyRegistry registry) {
// mysql env init
log.info("""
\n
✅ mysql property 를 주입합니다.
""");
registry.add("spring.datasource.url", mySQLContainer::getJdbcUrl);
registry.add("spring.datasource.username", () -> MYSQL_ROOT);
registry.add("spring.datasource.password", () -> MYSQL_PASSWORD);

// redis env init
log.info("""
\n
✅ redis property 를 주입합니다.
""");
registry.add("spring.redis.host", redisContainer::getHost);
registry.add("spring.redis.port", () -> "" + redisContainer.getMappedPort(REDIS_PORT));
}

static {
// mysql test container init
mySQLContainer = (MySQLContainer) new MySQLContainer(MYSQL_DOCKER_IMAGE)
.withUsername(MYSQL_ROOT)
.withPassword(MYSQL_PASSWORD)
.withDatabaseName("test")
.withEnv("MYSQL_ROOT_PASSWORD", MYSQL_PASSWORD);

log.info("""
\n
🐳 MYSQL 테스트 컨테이너를 시작합니다.
- base image: {}
""", MYSQL_DOCKER_IMAGE);
mySQLContainer.start();

// redis test container init
redisContainer = new GenericContainer<>(REDIS_DOCKER_IMAGE)
.withExposedPorts(REDIS_PORT)
.withReuse(true);
log.info("""
\n
🐳 Redis 테스트 컨테이너를 시작합니다.
- base image: {}
""", REDIS_DOCKER_IMAGE);
redisContainer.start();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.numberone.backend;

import com.numberone.backend.config.FirebaseConfig;
import com.numberone.backend.config.S3Config;
import com.numberone.backend.provider.s3.S3Provider;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@TestConfiguration
@SpringBootApplication
public class ServiceIntegrationTestConfiguration {

@MockBean
private S3Config s3Config;

@MockBean
private S3Provider s3Provider;

@MockBean
private FirebaseConfig firebaseConfig;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.numberone.backend.domain.shelter;

import com.numberone.backend.ServiceIntegrationTestBase;
import com.numberone.backend.domain.shelter.dto.request.NearbyShelterRequest;
import com.numberone.backend.domain.shelter.dto.response.NearbyShelterListResponse;
import com.numberone.backend.domain.shelter.entity.Shelter;
import com.numberone.backend.domain.shelter.repository.ShelterRepository;
import com.numberone.backend.domain.shelter.service.ShelterService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

public class ServiceServiceTest extends ServiceIntegrationTestBase {

@Autowired
private ShelterService shelterService;

@Autowired
private ShelterRepository shelterRepository;

@DisplayName("1000 m 이내에 위치한 주변 대피소 리스트를 조회할 수 있습니다.")
@Test
void getNearestShelterTest() {
// given
shelterRepository.save(Shelter.of(ShelterType.CIVIL_DEFENCE, "1000m 이내의 대피소 민방위대피소", 35.504, 35.5));
shelterRepository.save(Shelter.of(ShelterType.CIVIL_DEFENCE, "1000m 보다 먼 대피소", 36.504, 36.5));

// when
NearbyShelterListResponse response = shelterService.getNearbyShelterList(NearbyShelterRequest.of(35.5, 35.5, "민방위"));

// then
Assertions.assertThat(response.getCount()).isEqualTo(1);
}

}
Loading

0 comments on commit 05096d3

Please sign in to comment.