Skip to content

Commit

Permalink
Merge pull request #58 from team-crews/test/#43-add-test-data
Browse files Browse the repository at this point in the history
개발 디버깅용 테스트 데이터 추가 및 모집 공고 마감기한 검증 로직 수정
  • Loading branch information
jongmee authored Sep 1, 2024
2 parents 3579342 + 7b5099b commit 7dee6f0
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.server.crews.global.config;

import com.server.crews.applicant.domain.Application;
import com.server.crews.applicant.domain.NarrativeAnswer;
import com.server.crews.applicant.domain.SelectiveAnswer;
import com.server.crews.applicant.repository.ApplicationRepository;
import com.server.crews.auth.domain.Administrator;
import com.server.crews.auth.domain.Applicant;
import com.server.crews.auth.repository.AdministratorRepository;
import com.server.crews.auth.repository.ApplicantRepository;
import com.server.crews.recruitment.domain.Choice;
import com.server.crews.recruitment.domain.NarrativeQuestion;
import com.server.crews.recruitment.domain.Recruitment;
import com.server.crews.recruitment.domain.Section;
import com.server.crews.recruitment.domain.SelectiveQuestion;
import com.server.crews.recruitment.repository.RecruitmentRepository;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Profile(value = "!prod")
@Component
@Transactional
@RequiredArgsConstructor
public class DatabaseInitializer implements ApplicationRunner {
private final PasswordEncoder passwordEncoder;
private final AdministratorRepository administratorRepository;
private final RecruitmentRepository recruitmentRepository;
private final ApplicantRepository applicantRepository;
private final ApplicationRepository applicationRepository;

@Override
public void run(ApplicationArguments args) {
Administrator administrator = new Administrator("admin", passwordEncoder.encode("12341234!"));
administratorRepository.save(administrator);

NarrativeQuestion introductionQuestion = new NarrativeQuestion(null, "자기소개해주세요", true, 1, 500);
List<Choice> personalityChoices = List.of(new Choice(null, "성실함"), new Choice(null, "밝음"),
new Choice(null, "꼼꼼함"));
SelectiveQuestion personalityQuestion = new SelectiveQuestion(null, personalityChoices, "장점을 골라주세요", true, 2, 1,
1);
Section commonSection = new Section(null, "공통", "웹 어플리케이션 서버 개발 파트", List.of(introductionQuestion),
List.of(personalityQuestion));

NarrativeQuestion backendNarrativeQuestion = new NarrativeQuestion(null, "백엔드 파트와 관련된 활동 하나를 서술해주세요.", true, 1,
600);
List<Choice> backendStackChoices = List.of(new Choice(null, "Django, Python"),
new Choice(null, "Springboot, Java"));
SelectiveQuestion backendStackQuestion = new SelectiveQuestion(null, backendStackChoices,
"멋사 프로젝트에서 사용하고 싶은 스택을 골라주세요", true, 2, 1, 2);
Section backendSection = new Section(null, "백엔드", "웹 어플리케이션 서버 개발 파트", List.of(backendNarrativeQuestion),
List.of(backendStackQuestion));

NarrativeQuestion frontendNarrativeQuestion = new NarrativeQuestion(null, "프론트엔드 파트와 관련된 활동 하나를 서술해주세요.", true,
1, 600);
Section frontendSection = new Section(null, "프론트엔드", "웹 클라이언트 사이드 개발 파트", List.of(frontendNarrativeQuestion),
List.of());

Recruitment recruitment = new Recruitment(null, "test-code", "멋쟁이 사자처럼 99기 아기사자 모집",
"멋쟁이 사자처럼 서강대에서 99기 아기사자를 모집합니다!", LocalDateTime.of(2024, 9, 1, 2, 0), administrator,
List.of(commonSection, backendSection, frontendSection));
recruitment.close();
recruitmentRepository.save(recruitment);

Applicant kh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
Applicant lkh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
applicantRepository.saveAll(List.of(kh, lkh));

NarrativeAnswer skhIntroductionAnswer = new NarrativeAnswer(null, introductionQuestion, "안녕하세요");
SelectiveAnswer skhPersonalityAnswer = new SelectiveAnswer(null, personalityChoices.get(0),
personalityQuestion);
NarrativeAnswer skhBackendNarrativeAnswer = new NarrativeAnswer(null, backendNarrativeQuestion,
"크루즈 프로젝트 서버 개발을 맡았습니다.");
SelectiveAnswer skhBackendStackAnswer = new SelectiveAnswer(null, backendStackChoices.get(1),
backendStackQuestion);
Application skhApplication = new Application(null, recruitment, kh, "202011414", "컴퓨터공학", "송경호",
List.of(skhIntroductionAnswer, skhBackendNarrativeAnswer),
List.of(skhPersonalityAnswer, skhBackendStackAnswer));
applicationRepository.save(skhApplication);

NarrativeAnswer lkhIntroductionAnswer = new NarrativeAnswer(null, introductionQuestion, "반갑습니다");
SelectiveAnswer lkhPersonalityAnswer = new SelectiveAnswer(null, personalityChoices.get(1),
personalityQuestion);
NarrativeAnswer lkhFrontendNarrativeAnswer = new NarrativeAnswer(null, frontendNarrativeQuestion,
"크루즈 프로젝트 프론트 개발을 맡았습니다.");
Application lkhApplication = new Application(null, recruitment, lkh, "202013232", "컴퓨터공학", "이규호",
List.of(lkhIntroductionAnswer, lkhFrontendNarrativeAnswer), List.of(lkhPersonalityAnswer));
applicationRepository.save(lkhApplication);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum ErrorCode {
ALREADY_ANNOUNCED(HttpStatus.BAD_REQUEST, "모집 공고 결과 발표가 이미 완료되었습니다."),
RECRUITMENT_ALREADY_STARTED(HttpStatus.BAD_REQUEST, "모집이 이미 시작되었습니다."),
RECRUITMENT_NOT_STARTED(HttpStatus.BAD_REQUEST, "모집이 시작되지 않았습니다."),
INVALID_MODIFIED_DEADLINE(HttpStatus.BAD_REQUEST, "수정된 모집 마감 기한은 기존 기한 이후이며 모집 진행 중에만 수정할 수 있습니다."),

NO_TOKEN(HttpStatus.UNAUTHORIZED, "토큰이 존재하지 않습니다."),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "토큰 형식이 잘못 되었습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.server.crews.recruitment.repository.SelectiveQuestionRepository;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -55,11 +56,22 @@ public RecruitmentDetailsResponse saveRecruitment(Long publisherId, RecruitmentS
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
String code = UUID.randomUUID().toString();
Recruitment recruitment = RecruitmentMapper.recruitmentSaveRequestToRecruitment(request, code, publisher);
validateDeadline(recruitment.getDeadline());
Recruitment savedRecruitment = recruitmentRepository.save(recruitment);
savedRecruitment.sortQuestions();
return RecruitmentMapper.recruitmentToRecruitmentDetailsResponse(savedRecruitment);
}

private void validateDeadline(LocalDateTime deadline) {
LocalDateTime now = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Seoul")));
if (deadline.isBefore(now)) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
if (deadline.getMinute() != 0 || deadline.getSecond() != 0 || deadline.getNano() != 0) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
}

@Transactional
public void startRecruiting(Long publisherId) {
Recruitment recruitment = recruitmentRepository.findByPublisher(publisherId)
Expand Down Expand Up @@ -120,8 +132,12 @@ public RecruitmentProgressResponse findRecruitmentProgress(Long publisherId) {
public void updateDeadline(Long publisherId, DeadlineUpdateRequest request) {
Recruitment recruitment = recruitmentRepository.findByPublisher(publisherId)
.orElseThrow(() -> new CrewsException(ErrorCode.RECRUITMENT_NOT_FOUND));
LocalDateTime deadline = LocalDateTime.parse(request.deadline());
recruitment.updateDeadline(deadline);

LocalDateTime modifiedDeadline = LocalDateTime.parse(request.deadline());
if (!recruitment.hasOnOrAfterDeadline(modifiedDeadline) || !recruitment.isInProgress()) {
throw new CrewsException(ErrorCode.INVALID_MODIFIED_DEADLINE);
}
recruitment.updateDeadline(modifiedDeadline);
}

@Transactional
Expand All @@ -130,7 +146,7 @@ public void closeRecruitments() {
LocalDateTime now = LocalDateTime.now(clock);
List<Recruitment> recruitments = recruitmentRepository.findAll();
recruitments.stream()
.filter(recruitment -> recruitment.hasPassedDeadline(now))
.filter(recruitment -> recruitment.hasOnOrAfterDeadline(now))
.forEach(Recruitment::close);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,4 @@ public NarrativeQuestion(Long id, String content, Boolean necessity, Integer ord
public void updateSection(final Section section) {
this.section = section;
}

public void setByExistingId(Long id) {
this.id = id;
}
}
24 changes: 6 additions & 18 deletions src/main/java/com/server/crews/recruitment/domain/Recruitment.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.server.crews.recruitment.domain;

import com.server.crews.auth.domain.Administrator;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.ConstraintMode;
Expand All @@ -20,9 +18,7 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
Expand Down Expand Up @@ -77,7 +73,6 @@ public class Recruitment {

public Recruitment(Long id, String code, String title, String description, LocalDateTime deadline,
Administrator publisher, List<Section> sections) {
validateDeadline(deadline);
this.id = id;
this.code = code;
this.title = title;
Expand All @@ -89,20 +84,9 @@ public Recruitment(Long id, String code, String title, String description, Local
}

public void updateDeadline(LocalDateTime deadline) {
validateDeadline(deadline);
this.deadline = deadline;
}

private void validateDeadline(LocalDateTime deadline) {
LocalDateTime now = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Seoul")));
if (deadline.isBefore(now)) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
if (deadline.getMinute() != 0 || deadline.getSecond() != 0 || deadline.getNano() != 0) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
}

public void addSections(List<Section> sections) {
sections.forEach(section -> section.updateRecruitment(this));
this.sections.addAll(sections);
Expand All @@ -128,8 +112,12 @@ public boolean isStarted() {
return this.progress != RecruitmentProgress.READY;
}

public boolean hasPassedDeadline(LocalDateTime now) {
return now.isAfter(deadline) || now.equals(deadline);
public boolean isInProgress() {
return this.progress == RecruitmentProgress.IN_PROGRESS;
}

public boolean hasOnOrAfterDeadline(LocalDateTime other) {
return other.isAfter(deadline) || other.equals(deadline);
}

public void sortQuestions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,4 @@ public SelectiveQuestion(Long id, List<Choice> choices, String content, Boolean
public void updateSection(final Section section) {
this.section = section;
}

public void setByExistingId(Long id) {
this.id = id;
}
}
4 changes: 4 additions & 0 deletions src/test/java/com/server/crews/api/ApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.server.crews.auth.presentation.AuthorizationExtractor;
import com.server.crews.environ.DatabaseCleaner;
import com.server.crews.external.application.EmailService;
import com.server.crews.global.config.DatabaseInitializer;
import com.server.crews.recruitment.dto.request.QuestionType;
import com.server.crews.recruitment.dto.request.RecruitmentSaveRequest;
import com.server.crews.recruitment.dto.response.RecruitmentDetailsResponse;
Expand Down Expand Up @@ -51,6 +52,9 @@ public abstract class ApiTest {
@MockBean
private EmailService emailService;

@MockBean
private DatabaseInitializer databaseInitializer;

protected RequestSpecification spec;

@BeforeEach
Expand Down
10 changes: 7 additions & 3 deletions src/test/java/com/server/crews/api/RecruitmentApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -316,10 +315,15 @@ void updateDeadline() {
// given
AdminLoginResponse adminTokenResponse = signUpAdmin(TEST_CLUB_NAME, TEST_PASSWORD);
String adminAccessToken = adminTokenResponse.accessToken();
createRecruitment(adminAccessToken);
RecruitmentDetailsResponse recruitmentDetailsResponse = createRecruitment(adminAccessToken);

RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.AUTHORIZATION, AuthorizationExtractor.BEARER_TYPE + adminAccessToken)
.when().patch("/recruitments/in-progress");

DeadlineUpdateRequest deadlineUpdateRequest = new DeadlineUpdateRequest(
LocalDateTime.of(2030, 8, 5, 18, 0).toString());
recruitmentDetailsResponse.deadline().plusDays(1).toString());

// when
ExtractableResponse<Response> response = RestAssured.given(spec).log().all()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.server.crews.environ.DatabaseCleaner;
import com.server.crews.environ.repository.TestRepository;
import com.server.crews.external.application.EmailService;
import com.server.crews.global.config.DatabaseInitializer;
import com.server.crews.recruitment.domain.Recruitment;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -34,6 +35,9 @@ public abstract class ServiceTest {
@MockBean
private EmailService emailService;

@MockBean
private DatabaseInitializer databaseInitializer;

@BeforeEach
void setUp() {
databaseCleaner.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ private List<Choice> choicesInSelectiveQuestions(List<SelectiveQuestion> selecti
.toList();
}

public TestRecruitment start() {
this.recruitment.start();
environ.recruitmentRepository().save(this.recruitment);
return this;
}

public TestRecruitment announce() {
this.recruitment.announce();
environ.recruitmentRepository().save(this.recruitment);
Expand Down
Loading

0 comments on commit 7dee6f0

Please sign in to comment.