Merge remote-tracking branch 'origin/master'
This commit is contained in:
50
.github/workflows/autoTest.yml
vendored
50
.github/workflows/autoTest.yml
vendored
@@ -33,4 +33,52 @@ jobs:
|
||||
if: always()
|
||||
with:
|
||||
junit_files: "build/test-results/test/**/*.xml"
|
||||
|
||||
|
||||
# 전송할 파일을 담을 디렉토리 생성
|
||||
- name: Make Directory for deliver
|
||||
run: mkdir deploy
|
||||
|
||||
# Jar 파일 Copy
|
||||
- name: Copy Jar
|
||||
run: cp ./build/libs/*.jar ./deploy/
|
||||
|
||||
# appspec.yml 파일 복사
|
||||
- name: Copy appspec.yml
|
||||
run: cp appspec.yml ./deploy
|
||||
|
||||
# deploy.sh 파일 복사
|
||||
- name: Copy deploy.sh
|
||||
run: cp deploy.sh ./deploy
|
||||
|
||||
# test 파일 넘기기
|
||||
- name: Copy doc
|
||||
run: cp -r doc/ ./deploy
|
||||
working-directory: ${{env.working-directory}}
|
||||
|
||||
# 압축파일 형태로 전달
|
||||
- name: Make zip file
|
||||
run: zip -r -qq -j ./realworld.zip ./deploy
|
||||
working-directory: ${{env.working-directory}}
|
||||
|
||||
# S3 Bucket으로 copy
|
||||
- name: Deliver to AWS S3
|
||||
env:
|
||||
AWS_S3_BUCKET: ${{secrets.AWS_PRODUCTION_BUCKET_NAME}}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_IAM_MANAGER_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_IAM_MANAGER_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: ap-northeast-2
|
||||
run: |
|
||||
aws s3 cp --region ap-northeast-2 --acl private ./realworld.zip s3://$AWS_S3_BUCKET
|
||||
|
||||
# 배포
|
||||
- name: CodeDeploy
|
||||
env:
|
||||
AWS_S3_BUCKET: ${{secrets.AWS_PRODUCTION_BUCKET_NAME}}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_IAM_MANAGER_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_IAM_MANAGER_SECRET_ACCESS_KEY }}
|
||||
run: |
|
||||
aws deploy create-deployment \
|
||||
--application-name real-world \
|
||||
--deployment-group-name real-world-group \
|
||||
--s3-location bucket=$AWS_S3_BUCKET,key=realworld.zip,bundleType=zip \
|
||||
--region ap-northeast-2
|
||||
|
||||
13
README.md
13
README.md
@@ -10,3 +10,16 @@ This codebase was created to demonstrate a fully fledged fullstack application b
|
||||
We've gone to great lengths to adhere to the **[Spring Boot]** community styleguides & best practices.
|
||||
|
||||
For more information on how to this works with other frontends/backends, head over to the [RealWorld](https://github.com/gothinkster/realworld) repo.
|
||||
|
||||
## Enter
|
||||
|
||||
```text
|
||||
<http://3.35.44.58:8080/> //temp
|
||||
```
|
||||
|
||||
## BackEnd - Spring
|
||||
|
||||
### Test Scripts
|
||||
|
||||
<img width="464" alt="image" src="https://user-images.githubusercontent.com/30401054/201084053-60be024d-0615-40e1-9234-ceb926f402e5.png">
|
||||
|
||||
|
||||
18
appspec.yml
Normal file
18
appspec.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
version: 0.0
|
||||
os: linux
|
||||
files:
|
||||
- source: /
|
||||
destination: /home/linux/app
|
||||
overwrite: yes
|
||||
|
||||
permissions:
|
||||
- object: /
|
||||
pattern: "**"
|
||||
owner: ec2-user
|
||||
group: ec2-user
|
||||
|
||||
hooks:
|
||||
ApplicationStart:
|
||||
- location: deploy.sh
|
||||
timeout: 60
|
||||
runas: ec2-user
|
||||
31
deploy.sh
Normal file
31
deploy.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
REPOSITORY=/home/ubuntu/app
|
||||
|
||||
echo "> 현재 구동 중인 애플리케이션 pid 확인"
|
||||
|
||||
CURRENT_PID=$(pgrep -fl action | grep java | awk '{print $1}')
|
||||
|
||||
echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"
|
||||
|
||||
if [ -z "$CURRENT_PID" ]; then
|
||||
echo "현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
|
||||
else
|
||||
echo "> kill -15 $CURRENT_PID"
|
||||
kill -15 $CURRENT_PID
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
echo "> 새 애플리케이션 배포"
|
||||
|
||||
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1)
|
||||
|
||||
echo "> JAR NAME: $JAR_NAME"
|
||||
|
||||
echo "> $JAR_NAME 에 실행권한 추가"
|
||||
|
||||
chmod +x $JAR_NAME
|
||||
|
||||
echo "> $JAR_NAME 실행"
|
||||
|
||||
nohup java -jar $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
|
||||
@@ -52,13 +52,9 @@ public class ArticleServiceImpl implements ArticleService {
|
||||
|
||||
if (articleParam.getTag() != null) {
|
||||
articles = articleRepository.findByTag(articleParam.getTag(), pageable);
|
||||
}
|
||||
|
||||
if(articleParam.getAuthor() != null){
|
||||
}else if(articleParam.getAuthor() != null){
|
||||
articles = articleRepository.findByAuthorName(articleParam.getAuthor(), pageable);
|
||||
}
|
||||
|
||||
if(articleParam.getFavorited() != null){
|
||||
}else if(articleParam.getFavorited() != null){
|
||||
articles = articleRepository.findByFavoritedUser(articleParam.getFavorited(), pageable);
|
||||
}
|
||||
|
||||
@@ -76,10 +72,14 @@ public class ArticleServiceImpl implements ArticleService {
|
||||
Pageable pageable = PageRequest.of(offset,limit);
|
||||
|
||||
List<Follow> follows = profileRepository.findByFollowerId(userAuth.getId());
|
||||
System.out.println(follows.size());
|
||||
follows.stream().forEach(follow -> System.out.println(follow.getFollower().getUsername()));
|
||||
follows.stream().forEach(follow -> {
|
||||
String followerName = follow.getFollower().getUsername();
|
||||
articles.addAll(articleRepository.findByAuthorName(followerName,pageable));
|
||||
});
|
||||
|
||||
return List.of();
|
||||
return articles.stream().map(article -> {
|
||||
return convertDtoWithUser(article,userAuth);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// token을 받을수도 안 받을수도 있음.
|
||||
|
||||
@@ -5,18 +5,12 @@ import com.io.realworld.config.WithAuthUser;
|
||||
import com.io.realworld.domain.aggregate.article.dto.*;
|
||||
import com.io.realworld.domain.aggregate.article.service.ArticleService;
|
||||
import com.io.realworld.domain.aggregate.article.service.CommentService;
|
||||
import com.io.realworld.domain.aggregate.profile.dto.ProfileResponse;
|
||||
import com.io.realworld.domain.aggregate.user.dto.UserAuth;
|
||||
import com.io.realworld.domain.aggregate.user.dto.UserUpdate;
|
||||
import com.io.realworld.domain.service.JwtService;
|
||||
import lombok.With;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
@@ -28,7 +22,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@@ -70,6 +63,7 @@ class ArticleControllerTest {
|
||||
slug = title.toLowerCase().replace(' ','-');
|
||||
articleResponse = ArticleResponse.builder()
|
||||
.author(ArticleResponse.Author.builder().bio("bio")
|
||||
.username("kms")
|
||||
.following(false)
|
||||
.username("madeArticle")
|
||||
.image("image")
|
||||
@@ -89,6 +83,40 @@ class ArticleControllerTest {
|
||||
.build();
|
||||
}
|
||||
|
||||
@WithAuthUser
|
||||
@Test
|
||||
@DisplayName("게시글들 가져오기 컨트롤러 테스트")
|
||||
void getArticles() throws Exception{
|
||||
List<ArticleResponse> articleResponses = List.of(articleResponse);
|
||||
when(articleService.getArticles(any(UserAuth.class), any(ArticleParam.class))).thenReturn(articleResponses);
|
||||
|
||||
mockMvc.perform(get("/api/articles" + "?author=kms"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.articles[0]", Matchers.notNullValue(ArticleResponse.class)))
|
||||
.andExpect(jsonPath("$.articles[0].title",Matchers.equalTo(articleResponses.get(0).getTitle())))
|
||||
.andExpect(jsonPath("$.articles[0].description",Matchers.equalTo(articleResponses.get(0).getDescription())))
|
||||
.andExpect(jsonPath("$.articles[0].body",Matchers.equalTo(articleResponses.get(0).getBody())))
|
||||
.andExpect(jsonPath("$.articles[0].slug",Matchers.equalTo(articleResponses.get(0).getSlug())))
|
||||
.andExpect(jsonPath("$.articles[0].tagList",Matchers.equalTo(articleResponses.get(0).getTagList())));
|
||||
}
|
||||
|
||||
@WithAuthUser
|
||||
@Test
|
||||
@DisplayName("팔로우한 유저 게시글 가져오기 컨트롤러 테스트")
|
||||
void getFeed() throws Exception{
|
||||
List<ArticleResponse> articleResponses = List.of(articleResponse);
|
||||
when(articleService.getFeed(any(UserAuth.class), any(FeedParam.class))).thenReturn(articleResponses);
|
||||
|
||||
mockMvc.perform(get("/api/articles/feed"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.articles[0]", Matchers.notNullValue(ArticleResponse.class)))
|
||||
.andExpect(jsonPath("$.articles[0].title",Matchers.equalTo(articleResponses.get(0).getTitle())))
|
||||
.andExpect(jsonPath("$.articles[0].description",Matchers.equalTo(articleResponses.get(0).getDescription())))
|
||||
.andExpect(jsonPath("$.articles[0].body",Matchers.equalTo(articleResponses.get(0).getBody())))
|
||||
.andExpect(jsonPath("$.articles[0].slug",Matchers.equalTo(articleResponses.get(0).getSlug())))
|
||||
.andExpect(jsonPath("$.articles[0].tagList",Matchers.equalTo(articleResponses.get(0).getTagList())));
|
||||
}
|
||||
|
||||
@WithAuthUser(email = "test@gmail.com", username = "kms", id = 1L)
|
||||
@Test
|
||||
@DisplayName("게시글 만들기 컨트롤러 테스트")
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
package com.io.realworld.domain.aggregate.article.service;
|
||||
|
||||
import com.io.realworld.domain.aggregate.article.dto.ArticleResponse;
|
||||
import com.io.realworld.domain.aggregate.article.dto.ArticleUpdate;
|
||||
import com.io.realworld.domain.aggregate.article.dto.Articledto;
|
||||
import com.io.realworld.domain.aggregate.article.dto.*;
|
||||
import com.io.realworld.domain.aggregate.article.entity.Article;
|
||||
import com.io.realworld.domain.aggregate.article.entity.Favorite;
|
||||
import com.io.realworld.domain.aggregate.article.repository.ArticleRepository;
|
||||
import com.io.realworld.domain.aggregate.article.repository.FavoriteRepository;
|
||||
import com.io.realworld.domain.aggregate.profile.dto.ProfileResponse;
|
||||
import com.io.realworld.domain.aggregate.profile.entity.Follow;
|
||||
import com.io.realworld.domain.aggregate.profile.repository.ProfileRepository;
|
||||
import com.io.realworld.domain.aggregate.profile.service.ProfileService;
|
||||
import com.io.realworld.domain.aggregate.tag.entity.Tag;
|
||||
import com.io.realworld.domain.aggregate.tag.service.TagService;
|
||||
import com.io.realworld.domain.aggregate.user.dto.UserAuth;
|
||||
import com.io.realworld.domain.aggregate.user.entity.User;
|
||||
import com.io.realworld.domain.aggregate.user.repository.UserRepository;
|
||||
import com.io.realworld.exception.CustomException;
|
||||
import com.io.realworld.exception.Error;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
@@ -36,6 +40,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ArticleServiceImplTest {
|
||||
|
||||
@@ -57,6 +62,72 @@ class ArticleServiceImplTest {
|
||||
@Mock
|
||||
ProfileService profileService;
|
||||
|
||||
@Mock
|
||||
ProfileRepository profileRepository;
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("sv: 게시글들 가져오기 - tag가 일치")
|
||||
void getArticlesTag(){
|
||||
UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
|
||||
List<Article> articles = new ArrayList<Article>(){{
|
||||
add(articlesListGet().get(0));
|
||||
}};
|
||||
ArticleParam articleParam = new ArticleParam();
|
||||
articleParam.setTag("blogTag");
|
||||
|
||||
when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
|
||||
when(articleRepository.findByTag(eq(articleParam.getTag()),any(Pageable.class))).thenReturn(articles);
|
||||
List<ArticleResponse> articleResponses = articleService.getArticles(userAuth, articleParam);
|
||||
|
||||
assertThat(articleResponses.get(0).getTagList().get(0)).isEqualTo(articleParam.getTag());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("sv: 게시글들 가져오기 - author가 일치")
|
||||
void getArticlesAuthor(){
|
||||
UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
|
||||
|
||||
ArticleParam articleParam = new ArticleParam();
|
||||
articleParam.setAuthor("jyb");
|
||||
|
||||
List<Article> articles = articlesListGet().stream().filter(article -> {
|
||||
return article.getAuthor().getUsername().equals(articleParam.getAuthor());
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
|
||||
when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
|
||||
when(articleRepository.findByAuthorName(eq(articleParam.getAuthor()),any(Pageable.class))).thenReturn(articles);
|
||||
List<ArticleResponse> articleResponses = articleService.getArticles(userAuth, articleParam);
|
||||
|
||||
assertThat(articleResponses.get(0).getAuthor().getUsername()).isEqualTo(articleParam.getAuthor());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("sv: 피드 게시글 가져오기 ")
|
||||
void getFeed(){
|
||||
UserAuth userAuth = UserAuth.builder().id(1L).username("kms").build();
|
||||
|
||||
FeedParam feedParam = new FeedParam();
|
||||
|
||||
Article article = articlesListGet().get(2);
|
||||
List<Article> articles = new ArrayList<>(){{
|
||||
add(article);
|
||||
}};
|
||||
|
||||
List<Follow> follows = new ArrayList<Follow>(){{
|
||||
add(Follow.builder().followee(User.builder().username("kms").build()).follower(User.builder().username("eden").build()).build());
|
||||
}};
|
||||
|
||||
when(profileService.getProfile(eq(userAuth), any(String.class))).thenReturn(ProfileResponse.builder().username(articles.get(0).getAuthor().getUsername()).build());
|
||||
when(profileRepository.findByFollowerId(any(Long.class))).thenReturn(follows);
|
||||
when(articleRepository.findByAuthorName(any(String.class),any(Pageable.class))).thenReturn(articles);
|
||||
List<ArticleResponse> articleResponses = articleService.getFeed(userAuth, feedParam);
|
||||
|
||||
assertThat(articleResponses.get(0).getAuthor().getUsername()).isEqualTo(follows.get(0).getFollower().getUsername());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("sv: 게시글 만들기 성공")
|
||||
void createArticle() {
|
||||
@@ -397,6 +468,65 @@ class ArticleServiceImplTest {
|
||||
|
||||
}
|
||||
|
||||
List<Article> articlesListGet(){
|
||||
List<Tag> blogTags = new ArrayList<Tag>(){{
|
||||
add(Tag.builder().tagName("blogTag").build());
|
||||
add(Tag.builder().tagName("tutorial").build());
|
||||
}};
|
||||
List<Tag> dietTags = new ArrayList<Tag>(){{
|
||||
add(Tag.builder().tagName("dietTag").build());
|
||||
add(Tag.builder().tagName("tutorial").build());
|
||||
}};
|
||||
Article blogPost = Article.builder()
|
||||
.id(1L)
|
||||
.slug("post-my-blog")
|
||||
.author(User.builder()
|
||||
.username("kms")
|
||||
.image("blog image")
|
||||
.bio("blog bio")
|
||||
.email("kms@naver.com").build())
|
||||
.body("blog Post very ez")
|
||||
.tagList(blogTags)
|
||||
.description("blog create")
|
||||
.title("Post My Blog")
|
||||
.build();
|
||||
|
||||
Article dietPost = Article.builder()
|
||||
.id(2L)
|
||||
.slug("post-week-diet")
|
||||
.author(User.builder()
|
||||
.username("jyb")
|
||||
.image("diet image")
|
||||
.bio("diet bio")
|
||||
.email("jyb@naver.com").build())
|
||||
.body("diet very hard")
|
||||
.tagList(dietTags)
|
||||
.description("blog create")
|
||||
.title("Post week diet")
|
||||
.build();
|
||||
|
||||
Article codePost = Article.builder()
|
||||
.id(3L)
|
||||
.slug("post-coding-test")
|
||||
.author(User.builder()
|
||||
.username("eden")
|
||||
.image("programmer")
|
||||
.bio("s")
|
||||
.email("tesla@google.com").build())
|
||||
.body("Tesla very nice")
|
||||
.tagList(dietTags)
|
||||
.description("realworldApp")
|
||||
.title("post Coding Test")
|
||||
.build();
|
||||
|
||||
List<Article> articles = new ArrayList<Article>(){{
|
||||
add(blogPost);
|
||||
add(dietPost);
|
||||
add(codePost);
|
||||
}};
|
||||
return articles;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.io.realworld.repository;
|
||||
package com.io.realworld.domain.aggregate.user.repository;
|
||||
|
||||
import com.io.realworld.domain.aggregate.user.entity.User;
|
||||
import com.io.realworld.domain.aggregate.user.repository.UserRepository;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.io.realworld.service;
|
||||
package com.io.realworld.domain.aggregate.user.service;
|
||||
|
||||
import com.io.realworld.domain.aggregate.user.dto.*;
|
||||
import com.io.realworld.domain.aggregate.user.entity.User;
|
||||
Reference in New Issue
Block a user