diff --git a/src/main/java/gdsc/konkuk/platformcore/application/email/EmailService.java b/src/main/java/gdsc/konkuk/platformcore/application/email/EmailService.java index 60d73ae7..22a26f71 100644 --- a/src/main/java/gdsc/konkuk/platformcore/application/email/EmailService.java +++ b/src/main/java/gdsc/konkuk/platformcore/application/email/EmailService.java @@ -5,11 +5,13 @@ import gdsc.konkuk.platformcore.application.email.exceptions.EmailAlreadyProcessedException; import gdsc.konkuk.platformcore.application.email.exceptions.EmailErrorCode; import gdsc.konkuk.platformcore.controller.email.dtos.EmailSendRequest; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.domain.email.repository.EmailTaskRepository; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -48,7 +50,8 @@ public EmailTask update(Long emailId, EmailSendRequest request) { task.changeEmailDetails(request.toEmailDetails()); task.changeSendAt(request.getSendAt()); - Set updatedReceivers = mergeReceivers(task, request.getReceivers()); + Set newReceivers = request.toEmailReceivers(); + Set updatedReceivers = mergeReceivers(task, newReceivers); task.changeEmailReceivers(updatedReceivers); return task; } @@ -71,10 +74,10 @@ private void validateEmailTaskAlreadySent(EmailTask emailTask) { } } - private Set mergeReceivers(EmailTask emailTask, Set updatedReceivers) { - List receiversInPrevSet = emailTask.filterReceiversInPrevSet(updatedReceivers); - List receiversInNewSet = emailTask.filterReceiversNotInPrevSet(updatedReceivers); - Set mergedReceiver = new HashSet<>(receiversInPrevSet); + private Set mergeReceivers(EmailTask emailTask, Set updatedReceivers) { + List receiversInPrevSet = emailTask.filterReceiversInPrevSet(updatedReceivers); + List receiversInNewSet = emailTask.filterReceiversNotInPrevSet(updatedReceivers); + Set mergedReceiver = new HashSet<>(receiversInPrevSet); mergedReceiver.addAll(receiversInNewSet); return mergedReceiver; } diff --git a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailReceiverInfo.java b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailReceiverInfo.java new file mode 100644 index 00000000..22c6ae59 --- /dev/null +++ b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailReceiverInfo.java @@ -0,0 +1,37 @@ +package gdsc.konkuk.platformcore.controller.email.dtos; + +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotEmpty; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class EmailReceiverInfo { + @NotEmpty @Email + private String email; + + @NotEmpty private String name; + + @Builder + public EmailReceiverInfo(String email, String name) { + this.email = email; + this.name = name; + } + + public static EmailReceiver toValueObject(EmailReceiverInfo info) { + return EmailReceiver.builder() + .email(info.getEmail()) + .name(info.getName()) + .build(); + } + + public static EmailReceiverInfo fromValueObject(EmailReceiver emailReceiver) { + return EmailReceiverInfo.builder() + .email(emailReceiver.getEmail()) + .name(emailReceiver.getName()) + .build(); + } +} diff --git a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailSendRequest.java b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailSendRequest.java index c7874f85..28d16eaa 100644 --- a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailSendRequest.java +++ b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailSendRequest.java @@ -1,13 +1,14 @@ package gdsc.konkuk.platformcore.controller.email.dtos; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; -import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Set; +import java.util.stream.Collectors; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -20,21 +21,21 @@ public class EmailSendRequest { @NotEmpty private String content; @NotNull - private Set<@Email String> receivers; + private Set receiverInfos; @NotNull private LocalDateTime sendAt; @Builder - public EmailSendRequest(String subject, String content, Set receivers, LocalDateTime sendAt) { + public EmailSendRequest(String subject, String content, Set receiverInfos, LocalDateTime sendAt) { this.subject = subject; this.content = content; - this.receivers = receivers; + this.receiverInfos = receiverInfos; this.sendAt = sendAt; } public static EmailTask toEntity(EmailSendRequest request) { EmailDetails details = new EmailDetails(request.getSubject(), request.getContent()); - EmailReceivers receivers = new EmailReceivers(request.getReceivers()); + EmailReceivers receivers = new EmailReceivers(request.toEmailReceivers()); return EmailTask.builder() .emailDetails(details) .receivers(receivers) @@ -46,7 +47,10 @@ public EmailDetails toEmailDetails() { return new EmailDetails(subject, content); } - public EmailReceivers toEmailReceivers() { - return new EmailReceivers(receivers); + public Set toEmailReceivers() { + return receiverInfos + .stream() + .map(EmailReceiverInfo::toValueObject) + .collect(Collectors.toSet()); } } diff --git a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailTaskDetailsResponse.java b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailTaskDetailsResponse.java index a0407ba9..36ab312d 100644 --- a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailTaskDetailsResponse.java +++ b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/EmailTaskDetailsResponse.java @@ -11,16 +11,17 @@ public class EmailTaskDetailsResponse { private final String subject; private final String content; - private final List receivers; + private final List receiverInfos; private final LocalDateTime sendAt; @Builder public EmailTaskDetailsResponse(EmailDetails emailDetails, EmailReceivers emailReceivers, LocalDateTime sendAt) { this.subject = emailDetails.getSubject(); this.content = emailDetails.getContent(); - this.receivers = emailReceivers + this.receiverInfos = emailReceivers .getReceivers() .stream() + .map(EmailReceiverInfo::fromValueObject) .toList(); this.sendAt = sendAt; } diff --git a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/SimpleEmailTaskResponse.java b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/SimpleEmailTaskResponse.java index 846fff4c..95786892 100644 --- a/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/SimpleEmailTaskResponse.java +++ b/src/main/java/gdsc/konkuk/platformcore/controller/email/dtos/SimpleEmailTaskResponse.java @@ -1,6 +1,7 @@ package gdsc.konkuk.platformcore.controller.email.dtos; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import java.time.LocalDateTime; import lombok.Builder; @@ -11,25 +12,26 @@ public class SimpleEmailTaskResponse { private final Long id; private final String subject; - private final String receiver; + private final EmailReceiverInfo receiverInfos; private final LocalDateTime sendAt; private final Boolean isSent; @Builder - public SimpleEmailTaskResponse(Long id, String subject, String receiver, LocalDateTime sendAt, boolean isSent) { + public SimpleEmailTaskResponse(Long id, String subject, EmailReceiverInfo receiverInfos, LocalDateTime sendAt, boolean isSent) { this.id = id; this.subject = subject; - this.receiver = receiver; + this.receiverInfos = receiverInfos; this.sendAt = sendAt; this.isSent = isSent; } - public static SimpleEmailTaskResponse of(EmailTask emailTask, String receiver) { + public static SimpleEmailTaskResponse of(EmailTask emailTask, EmailReceiver receiver) { EmailDetails emailDetails = emailTask.getEmailDetails(); + EmailReceiverInfo receiverInfo = EmailReceiverInfo.fromValueObject(receiver); return SimpleEmailTaskResponse.builder() .id(emailTask.getId()) .subject(emailDetails.getSubject()) - .receiver(receiver) + .receiverInfos(receiverInfo) .sendAt(emailTask.getSendAt()) .isSent(emailTask.isSent()) .build(); diff --git a/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceiver.java b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceiver.java new file mode 100644 index 00000000..7408b6db --- /dev/null +++ b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceiver.java @@ -0,0 +1,38 @@ +package gdsc.konkuk.platformcore.domain.email.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Embeddable +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EmailReceiver { + @Column(name = "receiver_email") + private String email; + + @Column(name = "receiver_name") + private String name; + + @Builder + public EmailReceiver(String email, String name) { + this.email = email; + this.name = name; + } + + @Override + public int hashCode() { + return (this.email + this.name).hashCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EmailReceiver that = (EmailReceiver) o; + return email.equals(that.email) && name.equals(that.name); + } +} diff --git a/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceivers.java b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceivers.java index eed10d1e..d317134e 100644 --- a/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceivers.java +++ b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailReceivers.java @@ -1,7 +1,6 @@ package gdsc.konkuk.platformcore.domain.email.entity; import jakarta.persistence.CollectionTable; -import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; import jakarta.persistence.JoinColumn; import java.util.HashSet; @@ -20,10 +19,9 @@ public class EmailReceivers { @ElementCollection @CollectionTable(name = "email_receivers", joinColumns = @JoinColumn(name = "task_id")) - @Column(name = "receiver_email") - Set receivers = new HashSet<>(); + Set receivers = new HashSet<>(); - public EmailReceivers(Set receivers) { + public EmailReceivers(Set receivers) { this.receivers.addAll(receivers); } @@ -44,7 +42,7 @@ public void removeAll() { this.receivers.clear(); } - public void insertAll(Set set) { + public void insertAll(Set set) { this.receivers.addAll(set); } } diff --git a/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTask.java b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTask.java index 7b45210a..326aba3b 100644 --- a/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTask.java +++ b/src/main/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTask.java @@ -50,7 +50,7 @@ public void changeEmailDetails(final EmailDetails newEmailDetails) { emailDetails = newEmailDetails; } - public void changeEmailReceivers(final Set set) { + public void changeEmailReceivers(final Set set) { emailReceivers.removeAll(); emailReceivers.insertAll(set); } @@ -63,17 +63,17 @@ public void markAsSent() { isSent = true; } - public List filterReceiversInPrevSet(Set set) { + public List filterReceiversInPrevSet(Set set) { return this.getEmailReceivers().getReceivers() .stream() .filter(set::contains) .toList(); } - public List filterReceiversNotInPrevSet(Set set) { + public List filterReceiversNotInPrevSet(Set set) { return set .stream() - .filter((e) -> !emailReceivers.getReceivers().contains(e)) + .filter((e) -> !this.emailReceivers.getReceivers().contains(e)) .toList(); } } diff --git a/src/main/java/gdsc/konkuk/platformcore/external/email/EmailClient.java b/src/main/java/gdsc/konkuk/platformcore/external/email/EmailClient.java index aeba2917..973deeed 100644 --- a/src/main/java/gdsc/konkuk/platformcore/external/email/EmailClient.java +++ b/src/main/java/gdsc/konkuk/platformcore/external/email/EmailClient.java @@ -1,5 +1,8 @@ package gdsc.konkuk.platformcore.external.email; +import static gdsc.konkuk.platformcore.global.consts.PlatformConstants.EMAIL_RECEIVER_NAME_REGEXP; + +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.springframework.mail.MailException; @@ -26,15 +29,27 @@ public class EmailClient { public void sendEmailToReceivers(EmailTask email) { EmailDetails emailDetails = email.getEmailDetails(); - Set receivers = email.getEmailReceivers().getReceivers(); + Set receivers = email.getEmailReceivers().getReceivers(); receivers.forEach(receiver -> sendEmail(receiver, emailDetails)); } - private void sendEmail(String to, EmailDetails emailDetails) { + public String replaceNameToken(String content, String name) { + return content.replaceAll(EMAIL_RECEIVER_NAME_REGEXP, name); + } + + private MimeMessage generateMimeMessage(EmailReceiver to, EmailDetails emailDetails) + throws MessagingException { + String emailContent = replaceNameToken(emailDetails.getContent(), to.getName()); + String emailDestination = to.getEmail(); + String emailSubject = emailDetails.getSubject(); + + return convertToHTMLMimeMessage(emailDestination, emailSubject, emailContent); + } + + private void sendEmail(EmailReceiver to, EmailDetails emailDetails) { try { log.info("Sending email to {}", to); - MimeMessage message = - convertToHTMLMimeMessage(to, emailDetails.getSubject(), emailDetails.getContent()); + MimeMessage message = generateMimeMessage(to, emailDetails); javaMailSender.send(message); } catch (MailParseException | MessagingException e) { throw EmailSendingException.of(EmailClientErrorCode.MAIL_PARSING_ERROR, e.getMessage()); @@ -47,9 +62,11 @@ private MimeMessage convertToHTMLMimeMessage(String to, String subject, String t throws MessagingException { MimeMessage message = javaMailSender.createMimeMessage(); message.setSubject(subject); + MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setTo(to); helper.setText(text, true); + return message; } } diff --git a/src/main/java/gdsc/konkuk/platformcore/global/consts/PlatformConstants.java b/src/main/java/gdsc/konkuk/platformcore/global/consts/PlatformConstants.java index 6816265b..0f65e07d 100644 --- a/src/main/java/gdsc/konkuk/platformcore/global/consts/PlatformConstants.java +++ b/src/main/java/gdsc/konkuk/platformcore/global/consts/PlatformConstants.java @@ -11,6 +11,8 @@ public class PlatformConstants { public static final String LOGIN_NAME = "id"; public static final String API_PREFIX = "/api/v1"; + public static final String EMAIL_RECEIVER_NAME_REGEXP = "\\{이름}"; + public static final String DISCORD_ERROR_TITLE = "\uD83E\uDDE8 치명적인 서버 에러 발생!"; public static final String DISCORD_ERROR_DESCRIPTION = "\uD83C\uDD98 서버에서 치명적인 에러가 발생했습니다. 빠르게 확인해주세요. \uD83C\uDD98"; diff --git a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailIntegrationTest.java b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailIntegrationTest.java index 1dce1d67..687019de 100644 --- a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailIntegrationTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailIntegrationTest.java @@ -9,7 +9,10 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; import static org.springframework.test.util.AssertionErrors.assertNotNull; +import static org.springframework.test.util.AssertionErrors.fail; +import gdsc.konkuk.platformcore.application.email.exceptions.EmailAlreadyProcessedException; +import gdsc.konkuk.platformcore.controller.email.dtos.EmailReceiverInfo; import gdsc.konkuk.platformcore.controller.email.dtos.EmailSendRequest; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.domain.email.repository.EmailTaskRepository; @@ -72,11 +75,15 @@ void should_save_task_at_InMemoryTaskRepository() { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusHours(1)) .build(); + // when EmailTask emailTask = emailTaskFacade.register(emailRequest); + // then assertNotNull("Task should not be null", emailTask); assertNotNull( @@ -92,15 +99,18 @@ void should_send_task_when_time_is_up() throws InterruptedException { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1@gmail.com", "example2@gmail.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1@gmail.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2@gmail.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusSeconds(5L)) .build(); + // when emailTaskFacade.register(emailRequest); sleep(10000); + // then verify(emailClient).sendEmailToReceivers(any(EmailTask.class)); - assertEquals(0, executor.getQueue().size()); assertEquals(0, taskInMemoryRepository.size()); } @@ -111,7 +121,6 @@ void should_send_task_when_time_is_up() throws InterruptedException { * 2. 작업 수정 요청 * 3. 기존의 작업 취소, 새로운 작업 예약 * */ - @Test @DisplayName("작업 수정 시 스케줄된 작업 취소 후 다시 스케줄") void should_cancel_and_schedule_new_when_update() { @@ -120,21 +129,29 @@ void should_cancel_and_schedule_new_when_update() { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusHours(1)) .build(); EmailTask emailTask = emailTaskFacade.register(emailRequest); + assertEquals(1, executor.getQueue().size()); assertEquals(1, taskInMemoryRepository.size()); + EmailSendRequest updatedRequest = EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusHours(2)) .build(); + // when emailTaskFacade.update(emailTask.getId(), updatedRequest); + // then assertEquals(1, executor.getQueue().size()); assertNotNull( @@ -156,7 +173,9 @@ void should_cancel_task() { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusHours(1)) .build(); EmailTask emailTask = emailTaskFacade.register(emailRequest); @@ -165,7 +184,6 @@ void should_cancel_task() { // when emailTaskFacade.cancel(emailTask.getId()); - // then assertEquals(0, executor.getQueue().size()); assertTrue(emailTaskRepository.findById(emailTask.getId()).isEmpty()); @@ -182,17 +200,23 @@ void should_fail_when_cancel_already_processed_task() throws Exception { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusSeconds(1L)) .build(); + //when EmailTask scheduledTask = emailTaskFacade.register(emailRequest); - sleep(2000); + //then - assertThrows( - TaskNotFoundException.class, - () -> emailTaskFacade.cancel(scheduledTask.getId())); + try{ + emailTaskFacade.cancel(scheduledTask.getId()); + fail("`TaskNotFoundException` or `EmailAlreadyProcessedException` should be thrown"); + }catch(TaskNotFoundException | EmailAlreadyProcessedException e){ + // pass + } } @Test @@ -202,11 +226,14 @@ void should_send_discord_message_when_email_sending_error() throws InterruptedEx EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.now().plusSeconds(1L)) .build(); doThrow(EmailSendingException.of(GlobalErrorCode.INTERNAL_SERVER_ERROR)) .when(emailClient).sendEmailToReceivers(any()); + //when EmailTask scheduledTask = emailTaskFacade.register(emailRequest); sleep(2000); diff --git a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceHelperTest.java b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceHelperTest.java index cf3f7210..7419eaad 100644 --- a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceHelperTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceHelperTest.java @@ -6,6 +6,7 @@ import gdsc.konkuk.platformcore.application.email.exceptions.EmailNotFoundException; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.domain.email.repository.EmailTaskRepository; @@ -25,7 +26,10 @@ class EmailServiceHelperTest { EmailTask.builder() .id(1L) .emailDetails(new EmailDetails("subject", "content")) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); diff --git a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceTest.java b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceTest.java index 3d04b124..908ac57b 100644 --- a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailServiceTest.java @@ -6,8 +6,10 @@ import gdsc.konkuk.platformcore.application.email.exceptions.EmailAlreadyProcessedException; import gdsc.konkuk.platformcore.application.email.exceptions.EmailNotFoundException; +import gdsc.konkuk.platformcore.controller.email.dtos.EmailReceiverInfo; import gdsc.konkuk.platformcore.controller.email.dtos.EmailSendRequest; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.domain.email.repository.EmailTaskRepository; @@ -30,7 +32,10 @@ class EmailServiceTest { EmailTask.builder() .id(1L) .emailDetails(new EmailDetails("subject", "content")) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); @@ -38,15 +43,23 @@ class EmailServiceTest { EmailTask.builder() .id(2L) .emailDetails(new EmailDetails("subject2", "content2")) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.now()) .build(); + List mockEmailTaskList = List.of(mock1, mock2); + private final EmailTask mockAlreadySent = EmailTask.builder() .id(3L) .emailDetails(new EmailDetails("subject3", "content3")) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.now()) .build(); @@ -65,6 +78,7 @@ void should_success_when_getAllTaskAsList() { // when List actual = subject.getAllTaskAsList(); + // then assertEquals(mockEmailTaskList.size(), actual.size()); assertEquals(mockEmailTaskList.get(0).getId(), actual.get(0).getId()); @@ -76,8 +90,10 @@ void should_success_when_getAllTaskAsList() { void should_success_when_getTaskDetails() { // given given(emailTaskRepository.findById(1L)).willReturn(java.util.Optional.of(mock1)); + // when EmailTask actual = subject.getTaskDetails(1L); + // then assertEquals(mock1.getId(), actual.getId()); assertEquals(mock1.getEmailDetails().getSubject(), actual.getEmailDetails().getSubject()); @@ -89,15 +105,18 @@ void should_success_when_getTaskDetails() { @DisplayName("registerTask : 이메일 전송 작업 등록 성공") void should_success_when_register_task() { // given - EmailSendRequest emailRequest = EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos( + Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); given(emailTaskRepository.save(any(EmailTask.class))).willReturn(mock1); + // when EmailTask expected = EmailSendRequest.toEntity(emailRequest); EmailTask actual = subject.registerTask(EmailSendRequest.toEntity(emailRequest)); @@ -115,13 +134,18 @@ void should_success_when_update_task() { EmailSendRequest.builder() .subject("subject2") .content("content2") - .receivers(Set.of("example2.com", "example4.com")) + .receiverInfos( + Set.of( + EmailReceiverInfo.builder().email("example2.com").name("guest2").build(), + EmailReceiverInfo.builder().email("example4.com").name("guest4").build())) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); given(emailTaskRepository.findById(1L)).willReturn(java.util.Optional.of(mock1)); + // when EmailTask expected = EmailSendRequest.toEntity(emailRequest); EmailTask actual = subject.update(1L, emailRequest); + // then assertEquals(expected.getEmailDetails(), actual.getEmailDetails()); assertEquals(expected.getEmailReceivers(), actual.getEmailReceivers()); @@ -135,11 +159,16 @@ void should_fail_when_update_task_already_sent() { EmailSendRequest.builder() .subject("subject2") .content("content2") - .receivers(Set.of("example2.com", "example4.com")) + .receiverInfos( + Set.of( + EmailReceiverInfo.builder().email("example2.com").name("guest2").build(), + EmailReceiverInfo.builder().email("example4.com").name("guest4").build())) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); + // when when(emailTaskRepository.findById(1L)).thenReturn(Optional.of(mockAlreadySent)); + // then assertThrows(EmailAlreadyProcessedException.class, () -> subject.update(1L, emailRequest)); } @@ -152,11 +181,16 @@ void should_fail_when_update_task_not_found() { EmailSendRequest.builder() .subject("subject2") .content("content2") - .receivers(Set.of("example2.com", "example4.com")) + .receiverInfos( + Set.of( + EmailReceiverInfo.builder().email("example2.com").name("guest2").build(), + EmailReceiverInfo.builder().email("example4.com").name("guest4").build())) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); + // when when(emailTaskRepository.findById(1L)).thenReturn(Optional.empty()); + // then assertThrows(EmailNotFoundException.class, () -> subject.update(1L, emailRequest)); } @@ -166,9 +200,11 @@ void should_fail_when_update_task_not_found() { void should_success_when_delete_task() { // given given(emailTaskRepository.findById(1L)).willReturn(Optional.of(mock1)); + // when doNothing().when(emailTaskRepository).delete(mock1); subject.delete(1L); + // then verify(emailTaskRepository).delete(mock1); } diff --git a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailTaskFacadeTest.java b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailTaskFacadeTest.java index 4ec528d4..afb617f4 100644 --- a/src/test/java/gdsc/konkuk/platformcore/application/email/EmailTaskFacadeTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/application/email/EmailTaskFacadeTest.java @@ -4,8 +4,10 @@ import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.openMocks; +import gdsc.konkuk.platformcore.controller.email.dtos.EmailReceiverInfo; import gdsc.konkuk.platformcore.controller.email.dtos.EmailSendRequest; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.global.scheduler.TaskScheduler; @@ -31,7 +33,10 @@ class EmailTaskFacadeTest { EmailTask.builder() .id(1L) .emailDetails(new EmailDetails("subject", "content")) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); @@ -49,11 +54,16 @@ void should_success_when_reschedule_task() { EmailSendRequest.builder() .subject("subject") .content("content") - .receivers(Set.of("example1.com", "example2.com")) + .receiverInfos( + Set.of( + EmailReceiverInfo.builder().email("example1.com").name("guest1").build(), + EmailReceiverInfo.builder().email("example2.com").name("guest2").build())) .sendAt(LocalDateTime.of(2021, 1, 1, 1, 1)) .build(); + //when when(emailService.update(1L, emailRequest)).thenReturn(mock1); + //then subject.update(1L, emailRequest); verify(emailTaskScheduler).cancelTask("1"); @@ -64,6 +74,7 @@ void should_success_when_reschedule_task() { void should_success_when_cancel_task() { //given Long emailId = 1L; + //when subject.cancel(1L); diff --git a/src/test/java/gdsc/konkuk/platformcore/controller/email/EmailControllerTest.java b/src/test/java/gdsc/konkuk/platformcore/controller/email/EmailControllerTest.java index e1edb37b..3cd4589f 100644 --- a/src/test/java/gdsc/konkuk/platformcore/controller/email/EmailControllerTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/controller/email/EmailControllerTest.java @@ -17,8 +17,10 @@ import gdsc.konkuk.platformcore.annotation.RestDocsTest; import gdsc.konkuk.platformcore.application.email.EmailService; import gdsc.konkuk.platformcore.application.email.EmailTaskFacade; +import gdsc.konkuk.platformcore.controller.email.dtos.EmailReceiverInfo; import gdsc.konkuk.platformcore.controller.email.dtos.EmailSendRequest; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import java.time.LocalDateTime; @@ -72,11 +74,13 @@ void should_success_when_send_email() throws Exception { EmailSendRequest request = EmailSendRequest.builder() .subject("예시 이메일 제목") .content("Html 문자열") - .receivers(Set.of("ex1@gmail.com", "ex2@naver.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("ex1@gmail.com").name("guest1").build(), + EmailReceiverInfo.builder().email("ex2@naver.com").name("guest2").build())) .sendAt(LocalDateTime.of(2024, 7, 20, 12, 30)) .build(); EmailDetails emailDetails = request.toEmailDetails(); - EmailReceivers emailReceivers = request.toEmailReceivers(); + EmailReceivers emailReceivers = new EmailReceivers(request.toEmailReceivers()); EmailTask mockTask = new EmailTask(1L, emailDetails, emailReceivers, request.getSendAt()); //when @@ -103,7 +107,8 @@ void should_success_when_send_email() throws Exception { .requestFields( fieldWithPath("subject").type(JsonFieldType.STRING).description("이메일 제목"), fieldWithPath("content").type(JsonFieldType.STRING).description("이메일 내용"), - fieldWithPath("receivers").type(JsonFieldType.ARRAY).description("수신자 이메일 목록"), + fieldWithPath("receiverInfos[].email").type(JsonFieldType.STRING).description("수신자 email"), + fieldWithPath("receiverInfos[].name").type(JsonFieldType.STRING).description("수신자 이름"), fieldWithPath("sendAt").type(JsonFieldType.STRING).description("수정할 이메일 발송 시간") ) .build())) @@ -118,13 +123,16 @@ void should_success_when_update_emailTask() throws Exception { EmailSendRequest request = EmailSendRequest.builder() .subject("예시 이메일 제목 수정") .content("Html 문자열") - .receivers(Set.of("update@gmail.com", "update2@gmail.com", "update3@gmail.com")) + .receiverInfos(Set.of( + EmailReceiverInfo.builder().email("update@gmail.com").name("guest1").build(), + EmailReceiverInfo.builder().email("update2@gmail.com").name("guest2").build(), + EmailReceiverInfo.builder().email("update3@gmail.com").name("guest3").build())) .sendAt(LocalDateTime.of(2024,7,20,12,30)) .build(); //when ResultActions result = mockMvc.perform( - RestDocumentationRequestBuilders.patch("/api/v1/emails/1") + RestDocumentationRequestBuilders.patch("/api/v1/emails/{emailId}", 1L) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .with(csrf())); @@ -134,7 +142,7 @@ void should_success_when_update_emailTask() throws Exception { .andDo(print()); result.andDo( - document("emails", + document("update email task", preprocessRequest(prettyPrint()), resource(ResourceSnippetParameters.builder() .tag("email") @@ -142,7 +150,8 @@ void should_success_when_update_emailTask() throws Exception { .requestFields( fieldWithPath("subject").type(JsonFieldType.STRING).description("수정할 이메일 제목"), fieldWithPath("content").type(JsonFieldType.STRING).description("수정할 이메일 내용"), - fieldWithPath("receivers").type(JsonFieldType.ARRAY).description("수정할 수신자 이메일 목록"), + fieldWithPath("receiverInfos[].email").type(JsonFieldType.STRING).description("수신자 email"), + fieldWithPath("receiverInfos[].name").type(JsonFieldType.STRING).description("수신자 이름"), fieldWithPath("sendAt").type(JsonFieldType.STRING).description("수정할 이메일 발송 시간") ).build())) ); @@ -154,7 +163,11 @@ void should_success_when_update_emailTask() throws Exception { void should_success_when_get_all_task() throws Exception { //given EmailDetails emailDetails = new EmailDetails("예시 이메일 제목", "Html 문자열"); - EmailReceivers emailReceivers = new EmailReceivers(Set.of("example1@gmail.com", "example2@gmail.com", "example3@gmail.com")); + EmailReceivers emailReceivers = new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1@gmail.com").name("guest1").build(), + EmailReceiver.builder().email("example2@gmail.com").name("guest2").build(), + EmailReceiver.builder().email("example3@gmail.com").name("guest3").build())); EmailTask emailTask = new EmailTask(1L, emailDetails, emailReceivers, LocalDateTime.of(2024, 7, 20, 12, 30)); //when @@ -169,7 +182,7 @@ void should_success_when_get_all_task() throws Exception { .andDo(print()); result.andDo( - document("emails/", + document("get all email", preprocessRequest(prettyPrint()), resource(ResourceSnippetParameters.builder() .tag("email") @@ -181,7 +194,8 @@ void should_success_when_get_all_task() throws Exception { fieldWithPath("data.emailTasks").description("이메일 작업 목록"), fieldWithPath("data.emailTasks[].id").description("이메일 작업의 ID (Mock객체에 대해 null일 수 있음.)"), fieldWithPath("data.emailTasks[].subject").description("이메일 제목"), - fieldWithPath("data.emailTasks[].receiver").description("이메일 수신자"), + fieldWithPath("data.emailTasks[].receiverInfos.email").description("수신자 email"), + fieldWithPath("data.emailTasks[].receiverInfos.name").description("수신자 이름"), fieldWithPath("data.emailTasks[].sendAt").description("이메일 발송 예정 시간 (ISO 8601 형식)"), fieldWithPath("data.emailTasks[].isSent").description("이메일 발송 여부") ).build())) @@ -194,7 +208,10 @@ void should_success_when_get_all_task() throws Exception { void should_success_when_get_specific_task() throws Exception { //given EmailDetails emailDetails = new EmailDetails("예시 이메일 제목", "Html 문자열"); - EmailReceivers emailReceivers = new EmailReceivers(Set.of("example@gmail.com", "example@naver.com")); + EmailReceivers emailReceivers = new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example@gmail.com").name("guest1").build(), + EmailReceiver.builder().email("example@naver.com").name("guest2").build())); EmailTask emailTask = new EmailTask(1L, emailDetails, emailReceivers, LocalDateTime.of(2024, 7, 20, 12, 30)); //when @@ -209,7 +226,7 @@ void should_success_when_get_specific_task() throws Exception { .andDo(print()); result.andDo( - document("emails/{emailId}", + document("get email detail", preprocessRequest(prettyPrint()), resource(ResourceSnippetParameters.builder() .tag("email") @@ -220,7 +237,8 @@ void should_success_when_get_specific_task() throws Exception { fieldWithPath("data").description("이메일 전송 작업 내용"), fieldWithPath("data.subject").description("이메일 제목"), fieldWithPath("data.content").description("이메일 내용"), - fieldWithPath("data.receivers").description("이메일 수신자"), + fieldWithPath("data.receiverInfos[].email").description("수신자 email"), + fieldWithPath("data.receiverInfos[].name").description("수신자 이름"), fieldWithPath("data.sendAt").description("이메일 발송 예정 시간 (ISO 8601 형식)") ) .pathParameters( diff --git a/src/test/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTaskTest.java b/src/test/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTaskTest.java index a7d88c2f..175f647b 100644 --- a/src/test/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTaskTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/domain/email/entity/EmailTaskTest.java @@ -20,13 +20,19 @@ void should_success_when_change_email_receivers() { .subject("예시 이메일 제목") .content("Html 문자열") .build()) - .receivers(new EmailReceivers(Set.of("example@gmail.com", "example3@gmail.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example@gmail.com").name("guest1").build(), + EmailReceiver.builder().email("example3@gmail.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 10, 10, 10, 10)) .build(); EmailReceivers newReceivers = new EmailReceivers( - Set.of("aaa@gmail.com", "bbb@gmail.com", "ccc@gmail.com")); - //when + Set.of( + EmailReceiver.builder().email("aaa@gmail.com").name("guest a").build(), + EmailReceiver.builder().email("bbb@gmail.com").name("guest b").build(), + EmailReceiver.builder().email("ccc@gmail.com").name("guest c").build())); + //when emailTask.changeEmailReceivers(newReceivers.getReceivers()); //then @@ -79,13 +85,20 @@ void should_success_when_get_overlapping_receivers() { EmailTask emailTask = EmailTask.builder() .emailDetails(EmailDetails.builder().subject("예시 이메일 제목").content("Html 문자열").build()) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 10, 10, 10, 10)) .build(); - Set newEmailReceivers = Set.of("example2.com", "example3.com"); + Set newEmailReceivers = Set.of( + EmailReceiver.builder().email("example2.com").name("guest2").build(), + EmailReceiver.builder().email("example3.com").name("guest3").build()); + // when - List expected = List.of("example2.com"); - List actual = emailTask.filterReceiversInPrevSet(newEmailReceivers); + List expected = List.of(EmailReceiver.builder().email("example2.com").name("guest2").build()); + List actual = emailTask.filterReceiversInPrevSet(newEmailReceivers); + // then assertEquals(actual, expected); } @@ -97,14 +110,22 @@ void should_success_when_get_receivers_not_in_prev_set() { EmailTask emailTask = EmailTask.builder() .emailDetails(EmailDetails.builder().subject("예시 이메일 제목").content("Html 문자열").build()) - .receivers(new EmailReceivers(Set.of("example1.com", "example2.com"))) + .receivers(new EmailReceivers( + Set.of( + EmailReceiver.builder().email("example1.com").name("guest1").build(), + EmailReceiver.builder().email("example2.com").name("guest2").build()))) .sendAt(LocalDateTime.of(2021, 10, 10, 10, 10)) .build(); - Set newEmailReceivers = Set.of("example2.com", "example3.com"); + Set newEmailReceivers = Set.of( + EmailReceiver.builder().email("example2.com").name("guest2").build(), + EmailReceiver.builder().email("example3.com").name("guest3").build()); + // when - List expected = List.of("example3.com"); - List actual = emailTask.filterReceiversNotInPrevSet(newEmailReceivers); + List expected = List.of( + EmailReceiver.builder().email("example3.com").name("guest3").build()); + List actual = emailTask.filterReceiversNotInPrevSet(newEmailReceivers); + // then assertEquals(actual, expected); } -} \ No newline at end of file +} diff --git a/src/test/java/gdsc/konkuk/platformcore/external/email/EmailClientTest.java b/src/test/java/gdsc/konkuk/platformcore/external/email/EmailClientTest.java index 3748723a..8ab74f35 100644 --- a/src/test/java/gdsc/konkuk/platformcore/external/email/EmailClientTest.java +++ b/src/test/java/gdsc/konkuk/platformcore/external/email/EmailClientTest.java @@ -1,13 +1,16 @@ package gdsc.konkuk.platformcore.external.email; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.*; import gdsc.konkuk.platformcore.domain.email.entity.EmailDetails; +import gdsc.konkuk.platformcore.domain.email.entity.EmailReceiver; import gdsc.konkuk.platformcore.domain.email.entity.EmailReceivers; import gdsc.konkuk.platformcore.domain.email.entity.EmailTask; import gdsc.konkuk.platformcore.external.email.exceptions.EmailSendingException; +import jakarta.mail.internet.MimeMessage; import java.time.LocalDateTime; import java.util.Set; import org.junit.jupiter.api.BeforeEach; @@ -28,24 +31,67 @@ class EmailClientTest { @BeforeEach void setUp() { openMocks(this); - emailClient = new EmailClient(javaMailSender); + emailClient = spy(new EmailClient(javaMailSender)); } @Test @DisplayName("이메일의 내용 및 제목 형식 오류 발생") void should_fail_when_email_parsing() { - //given + // given EmailTask emailTask = EmailTask.builder() .emailDetails(EmailDetails.builder().subject("예시 이메일 제목").content("Html 문자열").build()) - .receivers(new EmailReceivers(Set.of("aaa@gmail.com"))) + .receivers(new EmailReceivers( + Set.of(EmailReceiver.builder().email("aaa@gmail.com").name("guest1").build()))) .sendAt(LocalDateTime.of(2021, 10, 10, 10, 10)) .build(); - //when + + // when when(javaMailSender.createMimeMessage()).thenThrow(new MailParseException("error")); Executable result = () -> emailClient.sendEmailToReceivers(emailTask); - //then + // then assertThrowsExactly(EmailSendingException.class, result); } -} \ No newline at end of file + + @Test + @DisplayName("이메일 내용 중 {이름}은 수신자의 이름으로 치환되어야 함") + void should_replace_to_receiver_name_when_name_token() { + // given + EmailTask emailTask = + EmailTask.builder() + .emailDetails(EmailDetails.builder() + .subject("예시 이메일 제목") + .content("안녕하세요, {이름}님 합격을 축하드립니다!. {이름}님과 함께할 수 있어 기쁩니다.") + .build()) + .receivers(new EmailReceivers( + Set.of(EmailReceiver.builder().email("ex@ex.com").name("guest1").build()))) + .sendAt(LocalDateTime.of(2024, 10, 10, 10, 10)) + .build(); + MimeMessage mockMimeMessage = mock(MimeMessage.class); + given(javaMailSender.createMimeMessage()).willReturn(mockMimeMessage); + given(emailClient.replaceNameToken(anyString(),anyString())).willReturn(""); + + // when + emailClient.sendEmailToReceivers(emailTask); + + // then + verify(emailClient).replaceNameToken( + eq("안녕하세요, {이름}님 합격을 축하드립니다!. {이름}님과 함께할 수 있어 기쁩니다."), + eq("guest1")); + } + + @Test + @DisplayName("이메일 이름 토큰({이름}) 치환 테스트") + void should_success_when_replace_name_token() { + // given + String content = "안녕하세요, {이름}님 합격을 축하드립니다!. {이름}님과 함께할 수 있어 기쁩니다."; + String name = "guest1"; + + // when + String result = emailClient.replaceNameToken(content, name); + + // then + assertEquals("안녕하세요, guest1님 합격을 축하드립니다!. guest1님과 함께할 수 있어 기쁩니다.", result); + } +}