diff --git a/src/main/java/earlybird/earlybird/email/address/check/CheckEmailAddressService.java b/src/main/java/earlybird/earlybird/email/address/check/CheckEmailAddressService.java new file mode 100644 index 0000000..f384e75 --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/check/CheckEmailAddressService.java @@ -0,0 +1,11 @@ +package earlybird.earlybird.email.address.check; + +import org.springframework.stereotype.Service; + +@Service +public class CheckEmailAddressService { + public Boolean checkEmailRegex(String email) { + String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; + return email.matches(emailRegex); + } +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressController.java b/src/main/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressController.java new file mode 100644 index 0000000..258fb6d --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressController.java @@ -0,0 +1,31 @@ +package earlybird.earlybird.email.address.save.controller; + +import earlybird.earlybird.email.address.save.controller.request.SaveEmailAddressRequest; +import earlybird.earlybird.email.address.save.service.SaveEmailAddressService; +import earlybird.earlybird.email.address.save.service.request.SaveEmailAddressServiceRequest; + +import jakarta.validation.Valid; + +import lombok.RequiredArgsConstructor; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/marketing/email/address") +@RestController +public class SaveEmailAddressController { + + private final SaveEmailAddressService saveEmailAddressService; + + @PostMapping + public ResponseEntity saveEmailAddress(@Valid @RequestBody SaveEmailAddressRequest request) { + SaveEmailAddressServiceRequest serviceRequest = + SaveEmailAddressServiceRequest.from(request); + saveEmailAddressService.save(serviceRequest); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/controller/request/SaveEmailAddressRequest.java b/src/main/java/earlybird/earlybird/email/address/save/controller/request/SaveEmailAddressRequest.java new file mode 100644 index 0000000..293a8e0 --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/controller/request/SaveEmailAddressRequest.java @@ -0,0 +1,22 @@ +package earlybird.earlybird.email.address.save.controller.request; + +import earlybird.earlybird.email.address.save.entity.MarketingEvent; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +public class SaveEmailAddressRequest { + + @NotBlank private String email; + + @NotNull private MarketingEvent sourceEvent; +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEmailAddress.java b/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEmailAddress.java new file mode 100644 index 0000000..6a9a4e8 --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEmailAddress.java @@ -0,0 +1,31 @@ +package earlybird.earlybird.email.address.save.entity; + +import earlybird.earlybird.common.BaseTimeEntity; + +import jakarta.persistence.*; + +import lombok.*; + +/** 마케팅을 통해 수집한 이메일 주소를 저장하는 엔티티 */ +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder +@Table(name = "email_address_for_marketing") +@Entity +public class MarketingEmailAddress extends BaseTimeEntity { + + @Column(name = "email_address_for_marketing_id", nullable = false) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + private Long id; + + // 이메일 주소 + @Column(name = "email_address_for_marketing_email", nullable = false) + private String email; + + // 이메일 수집 출처 이벤트 + @Enumerated(EnumType.STRING) + @Column(name = "email_address_for_marketing_source_event") + private MarketingEvent sourceEvent; +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEvent.java b/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEvent.java new file mode 100644 index 0000000..e9b1141 --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/entity/MarketingEvent.java @@ -0,0 +1,13 @@ +package earlybird.earlybird.email.address.save.entity; + +import lombok.Getter; + +public enum MarketingEvent { + WEB_MINI_GAME_1("홍보용 웹 미니 게임 - 1"); + + @Getter private final String description; + + MarketingEvent(String description) { + this.description = description; + } +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/repository/MarketingEmailAddressRepository.java b/src/main/java/earlybird/earlybird/email/address/save/repository/MarketingEmailAddressRepository.java new file mode 100644 index 0000000..b61990f --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/repository/MarketingEmailAddressRepository.java @@ -0,0 +1,8 @@ +package earlybird.earlybird.email.address.save.repository; + +import earlybird.earlybird.email.address.save.entity.MarketingEmailAddress; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MarketingEmailAddressRepository + extends JpaRepository {} diff --git a/src/main/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressService.java b/src/main/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressService.java new file mode 100644 index 0000000..f627a08 --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressService.java @@ -0,0 +1,40 @@ +package earlybird.earlybird.email.address.save.service; + +import earlybird.earlybird.email.address.check.CheckEmailAddressService; +import earlybird.earlybird.email.address.save.entity.MarketingEmailAddress; +import earlybird.earlybird.email.address.save.repository.MarketingEmailAddressRepository; +import earlybird.earlybird.email.address.save.service.request.SaveEmailAddressServiceRequest; + +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class SaveEmailAddressService { + + private final CheckEmailAddressService checkEmailAddressService; + private final MarketingEmailAddressRepository marketingEmailAddressRepository; + + @Transactional + public void save(SaveEmailAddressServiceRequest request) { + + Optional.ofNullable(request.email()) + .filter(checkEmailAddressService::checkEmailRegex) + .orElseThrow( + () -> + new IllegalArgumentException( + "Invalid email address: " + request.email())); + + MarketingEmailAddress emailAddress = + MarketingEmailAddress.builder() + .email(request.email()) + .sourceEvent(request.sourceEvent()) + .build(); + + marketingEmailAddressRepository.save(emailAddress); + } +} diff --git a/src/main/java/earlybird/earlybird/email/address/save/service/request/SaveEmailAddressServiceRequest.java b/src/main/java/earlybird/earlybird/email/address/save/service/request/SaveEmailAddressServiceRequest.java new file mode 100644 index 0000000..4378b7f --- /dev/null +++ b/src/main/java/earlybird/earlybird/email/address/save/service/request/SaveEmailAddressServiceRequest.java @@ -0,0 +1,17 @@ +package earlybird.earlybird.email.address.save.service.request; + +import earlybird.earlybird.email.address.save.controller.request.SaveEmailAddressRequest; +import earlybird.earlybird.email.address.save.entity.MarketingEvent; + +import lombok.*; + +@Builder +public record SaveEmailAddressServiceRequest(String email, MarketingEvent sourceEvent) { + + public static SaveEmailAddressServiceRequest from(SaveEmailAddressRequest request) { + return SaveEmailAddressServiceRequest.builder() + .email(request.getEmail()) + .sourceEvent(request.getSourceEvent()) + .build(); + } +} diff --git a/src/main/java/earlybird/earlybird/email/SendEmailService.java b/src/main/java/earlybird/earlybird/email/send/SendEmailService.java similarity index 98% rename from src/main/java/earlybird/earlybird/email/SendEmailService.java rename to src/main/java/earlybird/earlybird/email/send/SendEmailService.java index 894b2a1..cfa05b5 100644 --- a/src/main/java/earlybird/earlybird/email/SendEmailService.java +++ b/src/main/java/earlybird/earlybird/email/send/SendEmailService.java @@ -1,4 +1,4 @@ -package earlybird.earlybird.email; +package earlybird.earlybird.email.send; import static earlybird.earlybird.promotion.email.entity.PromotionEmailMessageType.BERKELEY_6_MONTH_FREE; diff --git a/src/main/java/earlybird/earlybird/promotion/controller/PromotionCampaignController.java b/src/main/java/earlybird/earlybird/promotion/controller/PromotionCampaignController.java index 4b343f7..24fd2f1 100644 --- a/src/main/java/earlybird/earlybird/promotion/controller/PromotionCampaignController.java +++ b/src/main/java/earlybird/earlybird/promotion/controller/PromotionCampaignController.java @@ -6,6 +6,8 @@ import earlybird.earlybird.promotion.service.request.CreatePromotionCampaignServiceRequest; import earlybird.earlybird.promotion.service.response.CreatePromotionCampaignServiceResponse; +import jakarta.validation.Valid; + import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -23,7 +25,7 @@ public class PromotionCampaignController { @PostMapping public ResponseEntity createPromotionCampaign( - @RequestBody CreatePromotionCampaignRequest request) { + @Valid @RequestBody CreatePromotionCampaignRequest request) { CreatePromotionCampaignServiceRequest serviceRequest = CreatePromotionCampaignServiceRequest.from(request); CreatePromotionCampaignServiceResponse serviceResponse = diff --git a/src/main/java/earlybird/earlybird/promotion/email/service/CheckEmailAddressService.java b/src/main/java/earlybird/earlybird/promotion/email/service/CheckPromotionEmailAddressService.java similarity index 89% rename from src/main/java/earlybird/earlybird/promotion/email/service/CheckEmailAddressService.java rename to src/main/java/earlybird/earlybird/promotion/email/service/CheckPromotionEmailAddressService.java index 0806f8f..9af7237 100644 --- a/src/main/java/earlybird/earlybird/promotion/email/service/CheckEmailAddressService.java +++ b/src/main/java/earlybird/earlybird/promotion/email/service/CheckPromotionEmailAddressService.java @@ -1,5 +1,6 @@ package earlybird.earlybird.promotion.email.service; +import earlybird.earlybird.email.address.check.CheckEmailAddressService; import earlybird.earlybird.promotion.email.entity.EmailPromotionAddressDomain; import earlybird.earlybird.promotion.email.repository.EmailPromotionAddressDomainRepository; import earlybird.earlybird.promotion.entity.PromotionCampaign; @@ -15,23 +16,19 @@ @RequiredArgsConstructor @Service -public class CheckEmailAddressService { +public class CheckPromotionEmailAddressService { private final EmailPromotionAddressDomainRepository promotionDomainRepository; private final PromotionCampaignRepository promotionCampaignRepository; + private final CheckEmailAddressService checkEmailAddressService; @Transactional public Boolean checkValidPromotionEmail(String email, Long promotionCampaignId) { - checkEmailRegex(email); - PromotionCampaign promotionCampaign = getPromotionCampaignById(promotionCampaignId); - return checkDomainName(email, promotionCampaign); - } - - private void checkEmailRegex(String email) { - String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"; - if (!email.matches(emailRegex)) { + if (!checkEmailAddressService.checkEmailRegex(email)) { throw new IllegalArgumentException("Invalid email address"); } + PromotionCampaign promotionCampaign = getPromotionCampaignById(promotionCampaignId); + return checkDomainName(email, promotionCampaign); } private PromotionCampaign getPromotionCampaignById(Long promotionCampaignId) { diff --git a/src/main/java/earlybird/earlybird/promotion/email/service/SendPromotionEmailService.java b/src/main/java/earlybird/earlybird/promotion/email/service/SendPromotionEmailService.java index 34f3010..7a0ac9e 100644 --- a/src/main/java/earlybird/earlybird/promotion/email/service/SendPromotionEmailService.java +++ b/src/main/java/earlybird/earlybird/promotion/email/service/SendPromotionEmailService.java @@ -1,6 +1,6 @@ package earlybird.earlybird.promotion.email.service; -import earlybird.earlybird.email.SendEmailService; +import earlybird.earlybird.email.send.SendEmailService; import earlybird.earlybird.error.exception.InvalidPromotionEmailException; import earlybird.earlybird.promotion.apple.service.GetApplePromotionUrlService; import earlybird.earlybird.promotion.email.entity.EmailPromotionCodeIssuance; @@ -23,7 +23,7 @@ public class SendPromotionEmailService { private final GetApplePromotionUrlService getApplePromotionUrlService; - private final CheckEmailAddressService checkEmailAddressService; + private final CheckPromotionEmailAddressService checkPromotionEmailAddressService; private final CreatePromotionUrlUuidService createPromotionUrlUuidService; private final GetPromotionCampaignService getPromotionCampaignService; private final SendEmailService sendEmailService; @@ -78,7 +78,7 @@ private void sendFirstEmail( private void checkEmailAddress(SendVerificationEmailServiceRequest request) { Boolean isValidDomain = - checkEmailAddressService.checkValidPromotionEmail( + checkPromotionEmailAddressService.checkValidPromotionEmail( request.getEmail(), request.getPromotionCampaignId()); if (!isValidDomain) { diff --git a/src/main/java/earlybird/earlybird/security/config/SecurityConfig.java b/src/main/java/earlybird/earlybird/security/config/SecurityConfig.java index 0152024..8f41192 100644 --- a/src/main/java/earlybird/earlybird/security/config/SecurityConfig.java +++ b/src/main/java/earlybird/earlybird/security/config/SecurityConfig.java @@ -60,10 +60,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests( auth -> - auth.requestMatchers("/api/v1/login/oauth2") - .permitAll() - .anyRequest() - .authenticated()); + // + // auth.requestMatchers("/api/v1/login/oauth2").permitAll() + // .anyRequest().authenticated()); + auth.anyRequest().permitAll()); OAuth2AuthenticationFilter oAuth2AuthenticationFilter = oAuth2AuthenticationFilter(); oAuth2AuthenticationFilter.setAuthenticationManager(authenticationManager); diff --git a/src/test/java/earlybird/earlybird/email/address/check/CheckEmailAddressServiceTest.java b/src/test/java/earlybird/earlybird/email/address/check/CheckEmailAddressServiceTest.java new file mode 100644 index 0000000..dcb4fce --- /dev/null +++ b/src/test/java/earlybird/earlybird/email/address/check/CheckEmailAddressServiceTest.java @@ -0,0 +1,47 @@ +package earlybird.earlybird.email.address.check; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +class CheckEmailAddressServiceTest { + + @DisplayName("올바른 이메일 형식이 주어지면 true를 반환한다.") + @Test + void checkValidEmail() { + // given + List validEmails = + List.of( + "test1@naver.com", + "124test@gmail.com", + "test@inha.edu", + "te4535st@hanmail.net"); + + CheckEmailAddressService service = new CheckEmailAddressService(); + + // when + List results = validEmails.stream().map(service::checkEmailRegex).toList(); + + // then + assertThat(results).containsOnly(true); + } + + @DisplayName("올바르지 않은 이메일 형식이 주어지면 false를 반환한다.") + @Test + void checkInvalidEmail() { + // given + List invalidEmails = + List.of("@naver.com", "testnaver.com", "test@gmail", "test@inha.e", "abcde"); + + CheckEmailAddressService service = new CheckEmailAddressService(); + + // when + List results = invalidEmails.stream().map(service::checkEmailRegex).toList(); + + // then + assertThat(results).containsOnly(false); + } +} diff --git a/src/test/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressControllerApiTest.java b/src/test/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressControllerApiTest.java new file mode 100644 index 0000000..bf06aff --- /dev/null +++ b/src/test/java/earlybird/earlybird/email/address/save/controller/SaveEmailAddressControllerApiTest.java @@ -0,0 +1,182 @@ +package earlybird.earlybird.email.address.save.controller; + +import static org.mockito.Mockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import earlybird.earlybird.email.address.save.controller.request.SaveEmailAddressRequest; +import earlybird.earlybird.email.address.save.entity.MarketingEvent; +import earlybird.earlybird.email.address.save.service.SaveEmailAddressService; +import earlybird.earlybird.email.address.save.service.request.SaveEmailAddressServiceRequest; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(controllers = SaveEmailAddressController.class) +class SaveEmailAddressControllerApiTest { + + @Autowired private MockMvc mockMvc; + @Autowired private ObjectMapper objectMapper; + + @MockBean private SaveEmailAddressService saveEmailAddressService; + + @DisplayName("정상 이메일 저장 요청이 들어오면 200 OK 응답이 반환된다") + @WithMockUser( + username = "mock-user", + roles = {"SUPER"}) + @Test + void return200WithValidRequest() throws Exception { + SaveEmailAddressRequest requestObject = + SaveEmailAddressRequest.builder() + .email("test@example.com") + .sourceEvent(MarketingEvent.WEB_MINI_GAME_1) + .build(); + String request = objectMapper.writeValueAsString(requestObject); + + doNothing().when(saveEmailAddressService).save(any(SaveEmailAddressServiceRequest.class)); + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(request) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isOk()); + } + + @DisplayName("요청의 이메일이 null, 빈 문자열, 공백이면 400 Bad Request 응답이 반환된다 (Not Blank)") + @WithMockUser( + username = "mock-user", + roles = {"SUPER"}) + @Test + void return400WhenEmailIsBlank() throws Exception { + String nullEmail = null; + String emptyEmail = ""; + String whitespaceEmail = " "; + + String requestWithNullEmail = + """ + { + "sourceEvent": MarketingEvent.WEB_MINI_GAME_1 + } + """; + String requestWithEmptyEmail = + """ + { + "email": "", + "sourceEvent": MarketingEvent.WEB_MINI_GAME_1 + } + """; + String requestWithWhitespaceEmail = + """ + { + "email": " ", + "sourceEvent": MarketingEvent.WEB_MINI_GAME_1 + } + """; + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(requestWithNullEmail) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(requestWithEmptyEmail) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(requestWithWhitespaceEmail) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + } + + @DisplayName("요청의 소스 이벤트가 null 이면 400 Bad Request 응답이 반환된다 (Not Null)") + @WithMockUser( + username = "mock-user", + roles = {"SUPER"}) + @Test + void return400WhenSourceEventIsNull() throws Exception { + String request = + """ + { + "email": "test@test.com" + } + """; + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(request) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + } + + @DisplayName("요청의 소스 이벤트가 존재하지 않는 값 이면 400 Bad Request 응답이 반환된다 (Not Null)") + @WithMockUser( + username = "mock-user", + roles = {"SUPER"}) + @Test + void return400WhenInvalidSourceEvent() throws Exception { + String request = + """ + { + "email": "test@test.com", + "sourceEvent": "INVALID" + } + """; + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(request) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + } + + @DisplayName("잘못된 이메일 형식이면 IllegalArgumentException으로 인해 400 Bad Request 응답이 반환된다") + @WithMockUser( + username = "mock-user", + roles = {"SUPER"}) + @Test + void return400WhenEmailFormatIsInvalid() throws Exception { + SaveEmailAddressRequest requestObject = + SaveEmailAddressRequest.builder() + .email("invalid-email") + .sourceEvent(MarketingEvent.WEB_MINI_GAME_1) + .build(); + String request = objectMapper.writeValueAsString(requestObject); + + doThrow(new IllegalArgumentException("Invalid email address: invalid-email")) + .when(saveEmailAddressService) + .save(any(SaveEmailAddressServiceRequest.class)); + + mockMvc.perform( + post("/api/v1/marketing/email/address") + .content(request) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf())) + .andExpect(status().isBadRequest()); + } +} diff --git a/src/test/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressServiceTest.java b/src/test/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressServiceTest.java new file mode 100644 index 0000000..85b32dd --- /dev/null +++ b/src/test/java/earlybird/earlybird/email/address/save/service/SaveEmailAddressServiceTest.java @@ -0,0 +1,81 @@ +package earlybird.earlybird.email.address.save.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import earlybird.earlybird.email.address.check.CheckEmailAddressService; +import earlybird.earlybird.email.address.save.entity.MarketingEmailAddress; +import earlybird.earlybird.email.address.save.entity.MarketingEvent; +import earlybird.earlybird.email.address.save.repository.MarketingEmailAddressRepository; +import earlybird.earlybird.email.address.save.service.request.SaveEmailAddressServiceRequest; + +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; + +@ExtendWith(MockitoExtension.class) +class SaveEmailAddressServiceTest { + + @InjectMocks private SaveEmailAddressService saveEmailAddressService; + + @Mock private CheckEmailAddressService checkEmailAddressService; + + @Mock private MarketingEmailAddressRepository marketingEmailAddressRepository; + + @DisplayName("이메일 주소와 수집 출처를 저장한다.") + @Test + void save() { + // given + SaveEmailAddressServiceRequest request = + SaveEmailAddressServiceRequest.builder() + .email("test@test.com") + .sourceEvent(MarketingEvent.WEB_MINI_GAME_1) + .build(); + + when(checkEmailAddressService.checkEmailRegex(request.email())).thenReturn(true); + + // when + saveEmailAddressService.save(request); + + // then + verify(checkEmailAddressService).checkEmailRegex(request.email()); + verify(marketingEmailAddressRepository).save(any(MarketingEmailAddress.class)); + } + + @DisplayName("올바르지 않은 이메일 주소 저장을 요청하면 예외가 발생한다.") + @Test + void throwExceptionWhenInvalidEmail() { + // given + SaveEmailAddressServiceRequest request = + SaveEmailAddressServiceRequest.builder() + .email("invalidAddress") + .sourceEvent(MarketingEvent.WEB_MINI_GAME_1) + .build(); + + when(checkEmailAddressService.checkEmailRegex(request.email())).thenReturn(false); + + // when // then + assertThatThrownBy(() -> saveEmailAddressService.save(request)) + .isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("이메일 주소가 NULL로 주어지면 예외가 발생한다.") + @Test + void throwExceptionWhenNullEmail() { + // given + SaveEmailAddressServiceRequest request = + SaveEmailAddressServiceRequest.builder() + .email(null) + .sourceEvent(MarketingEvent.WEB_MINI_GAME_1) + .build(); + + // when // then + assertThatThrownBy(() -> saveEmailAddressService.save(request)) + .isInstanceOf(IllegalArgumentException.class); + } +}