#29 pass: add passes job
This commit is contained in:
@@ -21,15 +21,20 @@ repositories {
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-batch'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
|
||||
// hibernate-types
|
||||
implementation 'com.vladmihalcea:hibernate-types-52:2.19.2'
|
||||
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
runtimeOnly 'com.mysql:mysql-connector-j'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
|
||||
// mapstruct
|
||||
implementation 'org.mapstruct:mapstruct:1.5.2.Final'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.2.Final'
|
||||
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
runtimeOnly 'com.mysql:mysql-connector-j'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.batch:spring-batch-test'
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.passbatch.job.pass;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class AddPassesJobConfig {
|
||||
|
||||
private final JobBuilderFactory jobBuilderFactory;
|
||||
private final StepBuilderFactory stepBuilderFactory;
|
||||
private final AddPassesTasklet addPassesTasklet;
|
||||
|
||||
@Bean
|
||||
public Job addPassesJob() {
|
||||
return jobBuilderFactory.get("addPassesJob")
|
||||
.start(addPassesStep())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step addPassesStep() {
|
||||
return stepBuilderFactory.get("addPassesStep")
|
||||
.tasklet(addPassesTasklet)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.example.passbatch.job.pass;
|
||||
|
||||
import com.example.passbatch.repository.pass.*;
|
||||
import com.example.passbatch.repository.user.UserGroupMappingEntity;
|
||||
import com.example.passbatch.repository.user.UserGroupMappingRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AddPassesTasklet implements Tasklet {
|
||||
|
||||
private final PassRepository passRepository;
|
||||
private final BulkPassRepository bulkPassRepository;
|
||||
private final UserGroupMappingRepository userGroupMappingRepository;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
// 이용권 시작 일시 1일 전 user group 내 각 사용자에게 이용권 추가
|
||||
final LocalDateTime startedAt = LocalDateTime.now().minusDays(1);
|
||||
final List<BulkPassEntity> bulkPassEntities =
|
||||
bulkPassRepository.findByStatusAndStartedAtGreaterThan(BulkPassStatus.READY, startedAt);
|
||||
|
||||
int count = 0;
|
||||
|
||||
// 대량 이용권 정보를 돌면서 user group 에 속한 userId 를 조회하고 해당 userId로 이용권을 추가
|
||||
for (BulkPassEntity bulkPassEntity : bulkPassEntities) {
|
||||
final List<String> userIds = userGroupMappingRepository.findByUserGroupId(bulkPassEntity.getUserGroupId())
|
||||
.stream()
|
||||
.map(UserGroupMappingEntity::getUserId).collect(Collectors.toList());
|
||||
|
||||
count += addPasses(bulkPassEntity, userIds);
|
||||
|
||||
bulkPassEntity.setStatus(BulkPassStatus.COMPLETED);
|
||||
}
|
||||
|
||||
log.info("AddPassesTasklet - execute: 이용권 {}건 추가 완료, startedAt={}", count, startedAt);
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
private int addPasses(BulkPassEntity bulkPassEntity, List<String> userIds) {
|
||||
List<PassEntity> passEntities = new ArrayList<>();
|
||||
for (String userId : userIds) {
|
||||
|
||||
PassEntity passEntity = PassModelMapper.INSTANCE.toPassEntity(bulkPassEntity, userId);
|
||||
passEntities.add(passEntity);
|
||||
}
|
||||
return passRepository.saveAll(passEntities).size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.passbatch.repository.pass;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
// ReportingPolicy.IGNORE: 일치하지 않은 필드를 무시
|
||||
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface PassModelMapper {
|
||||
PassModelMapper INSTANCE = Mappers.getMapper(PassModelMapper.class);
|
||||
|
||||
// 필드명이 같지 않거나 custom하게 매핑해주기 위해서는 @Mapping을 추가
|
||||
@Mapping(target = "status", qualifiedByName = "defaultStatus")
|
||||
@Mapping(target = "remainingCount", source = "bulkPassEntity.count")
|
||||
PassEntity toPassEntity(BulkPassEntity bulkPassEntity, String userId);
|
||||
|
||||
// BulkPassStatus와 관계 없이 PassStatus값을 설정
|
||||
@Named("defaultStatus")
|
||||
default PassStatus status(BulkPassStatus status) {
|
||||
return PassStatus.READY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.example.passbatch.job.pass;
|
||||
|
||||
import com.example.passbatch.repository.pass.*;
|
||||
import com.example.passbatch.repository.user.UserGroupMappingEntity;
|
||||
import com.example.passbatch.repository.user.UserGroupMappingRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class AddPassesTaskletTest {
|
||||
@Mock
|
||||
private StepContribution stepContribution;
|
||||
|
||||
@Mock
|
||||
private ChunkContext chunkContext;
|
||||
|
||||
@Mock
|
||||
private PassRepository passRepository;
|
||||
|
||||
@Mock
|
||||
private BulkPassRepository bulkPassRepository;
|
||||
|
||||
@Mock
|
||||
private UserGroupMappingRepository userGroupMappingRepository;
|
||||
|
||||
// @InjectMocks 클래스의 인스턴스를 생성하고 @Mock으로 생성된 객체를 주입
|
||||
@InjectMocks
|
||||
private AddPassesTasklet addPassesTasklet;
|
||||
|
||||
@Test
|
||||
public void test_execute() throws Exception {
|
||||
// given
|
||||
final String userGroupId = "GROUP";
|
||||
final String userId = "A1000000";
|
||||
final Integer packageSeq = 1;
|
||||
final Integer count = 10;
|
||||
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final BulkPassEntity bulkPassEntity = new BulkPassEntity();
|
||||
bulkPassEntity.setPackageSeq(packageSeq);
|
||||
bulkPassEntity.setUserGroupId(userGroupId);
|
||||
bulkPassEntity.setStatus(BulkPassStatus.READY);
|
||||
bulkPassEntity.setCount(count);
|
||||
bulkPassEntity.setStartedAt(now);
|
||||
bulkPassEntity.setEndedAt(now.plusDays(60));
|
||||
|
||||
final UserGroupMappingEntity userGroupMappingEntity = new UserGroupMappingEntity();
|
||||
userGroupMappingEntity.setUserGroupId(userGroupId);
|
||||
userGroupMappingEntity.setUserId(userId);
|
||||
|
||||
// when
|
||||
when(bulkPassRepository.findByStatusAndStartedAtGreaterThan(eq(BulkPassStatus.READY), any()))
|
||||
.thenReturn(List.of(bulkPassEntity));
|
||||
when(userGroupMappingRepository.findByUserGroupId(eq("GROUP")))
|
||||
.thenReturn(List.of(userGroupMappingEntity));
|
||||
|
||||
RepeatStatus repeatStatus = addPassesTasklet.execute(stepContribution, chunkContext);
|
||||
|
||||
// then
|
||||
// execute의 return 값인 RepeatStatus 값을 확인
|
||||
assertEquals(RepeatStatus.FINISHED, repeatStatus);
|
||||
|
||||
// 추가된 PassEntity 값을 확인
|
||||
ArgumentCaptor<List> passEntitiesCaptor = ArgumentCaptor.forClass(List.class);
|
||||
verify(passRepository, times(1)).saveAll(passEntitiesCaptor.capture());
|
||||
final List<PassEntity> passEntities = passEntitiesCaptor.getValue();
|
||||
|
||||
assertEquals(1, passEntities.size());
|
||||
final PassEntity passEntity = passEntities.get(0);
|
||||
assertEquals(packageSeq, passEntity.getPackageSeq());
|
||||
assertEquals(userId, passEntity.getUserId());
|
||||
assertEquals(PassStatus.READY, passEntity.getStatus());
|
||||
assertEquals(count, passEntity.getRemainingCount());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.example.passbatch.repository.pass;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PassModelMapperTest {
|
||||
|
||||
@Test
|
||||
void test_toPassEntity() {
|
||||
// given
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
final String userId = "A1000000";
|
||||
|
||||
BulkPassEntity bulkPassEntity = new BulkPassEntity();
|
||||
bulkPassEntity.setPackageSeq(1);
|
||||
bulkPassEntity.setUserGroupId("GROUP");
|
||||
bulkPassEntity.setStatus(BulkPassStatus.COMPLETED);
|
||||
bulkPassEntity.setCount(10);
|
||||
bulkPassEntity.setStartedAt(now.minusDays(60));
|
||||
bulkPassEntity.setEndedAt(now);
|
||||
|
||||
// when
|
||||
final PassEntity passEntity = PassModelMapper.INSTANCE.toPassEntity(bulkPassEntity, userId);
|
||||
|
||||
// then
|
||||
assertEquals(1, passEntity.getPackageSeq());
|
||||
assertEquals(PassStatus.READY, passEntity.getStatus());
|
||||
assertEquals(10, passEntity.getRemainingCount());
|
||||
assertEquals(now.minusDays(60), passEntity.getStartedAt());
|
||||
assertEquals(now, passEntity.getEndedAt());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user