diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 00000000..57d31821 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,53 @@ +name: Java CI/CD with Gradle + +on: + push: + branches: + - 'develop' + - 'main' # main 브랜치에 병합될 때 트리거 + +jobs: + ci-pipeline: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'adopt' + java-version: '21' + + - name: Grant execute permission for Gradle Wrapper + run: chmod +x ./gradlew + + - name: Lint and format code + run: ./gradlew editorconfigFormat + + - name: Build with Gradle + run: ./gradlew build + + - name: Test with Gradle + run: ./gradlew test + + cd-pipeline: + if: github.ref == 'refs/heads/main' # main 브랜치에만 배포 실행 + runs-on: ubuntu-latest + steps: + - name: SSH로 NCP 접속하기 + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.NCP_HOST }} + username: ${{ secrets.NCP_USERNAME }} + password: ${{ secrets.NCP_SSH_PASSWORD }} + port: ${{ secrets.NCP_SSH_PORT }} + script_stop: true + script: | + cd auction + git pull knuk ttest + chmod 777 ./gradlew + ./gradlew build + kill -9 $(lsof -t -i:8080) || echo "No process on 8080" + nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 & diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index ca2080cb..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Java CI with Gradle - -on: - push: - branches: - - 'main' - - 'develop' - -jobs: - ci-pipeline: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - distribution: 'adopt' - java-version: '21' - - - name: Grant execute permission for Gradle Wrapper - run: chmod +x ./gradlew - - - name: Lint and format code - run: ./gradlew editorconfigFormat - - - name: Build with Gradle - run: ./gradlew build - - - name: Test with Gradle - run: ./gradlew test diff --git a/src/main/java/com/tasksprints/auction/api/auction/AuctionController.java b/src/main/java/com/tasksprints/auction/api/auction/AuctionController.java index 1f9de796..2136a4f8 100644 --- a/src/main/java/com/tasksprints/auction/api/auction/AuctionController.java +++ b/src/main/java/com/tasksprints/auction/api/auction/AuctionController.java @@ -80,8 +80,8 @@ public ResponseEntity> getAuctionStatus(@PathVariable Long auc @GetMapping @Operation(summary = "Get all auctions", description = "Retrieves all auctions.") @ApiResponse(responseCode = "200", description = "All auctions retrieved successfully") - public ResponseEntity>> getAllAuctions(@RequestParam(required = false) AuctionRequest.AuctionCategoryParam auctionCategory, @RequestParam(required = false) AuctionRequest.ProductCategoryParam productCategory) { - List auctions = auctionService.getAuctionsByFilter(productCategory, auctionCategory); + public ResponseEntity>> getAllAuctions(AuctionRequest.SearchCondition searchCondition) { + List auctions = auctionService.getAuctionsByFilter(searchCondition); return ResponseEntity.ok(ApiResult.success(ApiResponseMessages.ALL_AUCTIONS_RETRIEVED, auctions)); } diff --git a/src/main/java/com/tasksprints/auction/common/config/WebConfig.java b/src/main/java/com/tasksprints/auction/common/config/WebConfig.java new file mode 100644 index 00000000..c64b94eb --- /dev/null +++ b/src/main/java/com/tasksprints/auction/common/config/WebConfig.java @@ -0,0 +1,22 @@ +package com.tasksprints.auction.common.config; + +import com.tasksprints.auction.common.resolver.SearchConditionResolver; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + private final SearchConditionResolver searchConditionResolver; + + public WebConfig(SearchConditionResolver searchConditionResolver) { + this.searchConditionResolver = searchConditionResolver; + } + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(searchConditionResolver); + } +} diff --git a/src/main/java/com/tasksprints/auction/common/resolver/SearchConditionResolver.java b/src/main/java/com/tasksprints/auction/common/resolver/SearchConditionResolver.java new file mode 100644 index 00000000..ab9dacb6 --- /dev/null +++ b/src/main/java/com/tasksprints/auction/common/resolver/SearchConditionResolver.java @@ -0,0 +1,60 @@ +package com.tasksprints.auction.common.resolver; + +import com.tasksprints.auction.domain.auction.dto.request.AuctionRequest; +import com.tasksprints.auction.domain.auction.model.AuctionCategory; +import com.tasksprints.auction.domain.auction.model.AuctionStatus; +import com.tasksprints.auction.domain.product.model.ProductCategory; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Component +public class SearchConditionResolver implements HandlerMethodArgumentResolver { + @Override + public boolean supportsParameter(MethodParameter parameter) { + // 메서드 파라미터 타입이 AuctionRequest.SearchCondition일 때 처리 + return parameter.getParameterType().equals(AuctionRequest.SearchCondition.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + + // QueryString에서 값을 추출 + String auctionCategory = webRequest.getParameter("auctionCategory"); + String productCategory = webRequest.getParameter("productCategory"); + String startTime = webRequest.getParameter("startTime"); + String endTime = webRequest.getParameter("endTime"); + String minPrice = webRequest.getParameter("minPrice"); + String maxPrice = webRequest.getParameter("maxPrice"); + String auctionStatus = webRequest.getParameter("auctionStatus"); + String sortBy = webRequest.getParameter("sortBy"); + // 파싱 및 변환 + AuctionCategory parsedAuctionCategory = auctionCategory != null ? AuctionCategory.fromDisplayName(auctionCategory) : null; + ProductCategory parsedProductCategory = productCategory != null ? ProductCategory.fromDisplayName(productCategory) : null; + LocalDateTime parsedStartTime = startTime != null ? LocalDateTime.parse(startTime, DateTimeFormatter.ISO_DATE_TIME) : null; + LocalDateTime parsedEndTime = endTime != null ? LocalDateTime.parse(endTime, DateTimeFormatter.ISO_DATE_TIME) : null; + BigDecimal parsedMinPrice = minPrice != null ? new BigDecimal(minPrice) : null; + BigDecimal parsedMaxPrice = maxPrice != null ? new BigDecimal(maxPrice) : null; + AuctionStatus parsedAuctionStatus = auctionStatus != null ? AuctionStatus.fromDisplayName(auctionStatus) : null; + + // SearchCondition 객체 생성 및 반환 + return new AuctionRequest.SearchCondition( + parsedAuctionCategory, + parsedProductCategory, + parsedStartTime, + parsedEndTime, + parsedMinPrice, + parsedMaxPrice, + parsedAuctionStatus, + sortBy + ); + } +} diff --git a/src/main/java/com/tasksprints/auction/domain/auction/dto/request/AuctionRequest.java b/src/main/java/com/tasksprints/auction/domain/auction/dto/request/AuctionRequest.java index 4b262095..927f297e 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/dto/request/AuctionRequest.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/dto/request/AuctionRequest.java @@ -3,6 +3,7 @@ import com.tasksprints.auction.domain.auction.model.AuctionCategory; import com.tasksprints.auction.domain.auction.model.AuctionStatus; import com.tasksprints.auction.domain.product.model.ProductCategory; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,32 +16,25 @@ public class AuctionRequest { @NoArgsConstructor @AllArgsConstructor public static class Create { - LocalDateTime startTime; - LocalDateTime endTime; - BigDecimal startingBid; - AuctionCategory auctionCategory; - AuctionStatus auctionStatus; + private LocalDateTime startTime; + private LocalDateTime endTime; + private BigDecimal startingBid; + private AuctionCategory auctionCategory; + private AuctionStatus auctionStatus; } @Getter - @NoArgsConstructor - @AllArgsConstructor - public static class AuctionCategoryParam { - AuctionCategory auctionCategory; - - public AuctionCategoryParam(String auctionCategory) { - this.auctionCategory = AuctionCategory.fromDisplayName(auctionCategory); - } - } - - @Getter - @NoArgsConstructor @AllArgsConstructor - public static class ProductCategoryParam { - ProductCategory productCategory; + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class SearchCondition { + private AuctionCategory auctionCategory; + private ProductCategory productCategory; + private LocalDateTime startTime; + private LocalDateTime endTime; + private BigDecimal minPrice; + private BigDecimal maxPrice; + private AuctionStatus auctionStatus; + private String sortBy; - public ProductCategoryParam(String productCategory) { - this.productCategory = ProductCategory.fromDisplayName(productCategory); - } } } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/model/Auction.java b/src/main/java/com/tasksprints/auction/domain/auction/model/Auction.java index df228ef1..320b5078 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/model/Auction.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/model/Auction.java @@ -1,6 +1,7 @@ package com.tasksprints.auction.domain.auction.model; import com.tasksprints.auction.common.entity.BaseEntity; +import com.tasksprints.auction.domain.bid.model.Bid; import com.tasksprints.auction.domain.product.model.Product; import com.tasksprints.auction.domain.user.model.User; import jakarta.persistence.*; @@ -8,6 +9,8 @@ import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; @Builder @NoArgsConstructor @@ -47,6 +50,11 @@ public class Auction extends BaseEntity { @Builder.Default private Product product = null; + + @OneToMany + @Builder.Default + private List bids = new ArrayList<>(); + public static Auction create(LocalDateTime startTime, LocalDateTime endTime, BigDecimal startingBid, AuctionCategory auctionCategory, AuctionStatus auctionStatus, User seller) { Auction newAuction = Auction.builder() .startTime(startTime) diff --git a/src/main/java/com/tasksprints/auction/domain/auction/model/AuctionStatus.java b/src/main/java/com/tasksprints/auction/domain/auction/model/AuctionStatus.java index 8401f93b..2f69867d 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/model/AuctionStatus.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/model/AuctionStatus.java @@ -4,5 +4,13 @@ public enum AuctionStatus { PENDING, ACTIVE, CLOSED, - CANCELED + CANCELED; + + public static AuctionStatus fromDisplayName(String auctionStatus) { + try { + return AuctionStatus.valueOf(auctionStatus.toUpperCase()); // 대문자로 변환하여 비교 + } catch (IllegalArgumentException e) { + return AuctionStatus.ACTIVE; // 유효하지 않은 값일 경우 기본값으로 ACTIVE 반환 + } + } } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/repository/AuctionRepository.java b/src/main/java/com/tasksprints/auction/domain/auction/repository/AuctionRepository.java index 450d5928..24f95a20 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/repository/AuctionRepository.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/repository/AuctionRepository.java @@ -2,9 +2,7 @@ import com.tasksprints.auction.domain.auction.model.Auction; -import com.tasksprints.auction.domain.auction.model.AuctionCategory; import com.tasksprints.auction.domain.auction.repository.support.AuctionCriteriaRepository; -import com.tasksprints.auction.domain.product.model.ProductCategory; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -14,15 +12,11 @@ public interface AuctionRepository extends JpaRepository, AuctionCriteriaRepository { - @Query("SELECT a FROM auction a WHERE a.seller.id = :userId") List findAuctionsByUserId(@Param("userId") Long userId); @Query("SELECT a FROM auction a WHERE a.id = :auctionId") Optional findAuctionById(@Param("auctionId") Long auctionId); - List findAuctionsByAuctionCategory(AuctionCategory auctionCategory); - - List findAuctionByProduct_Category(ProductCategory productCategory); } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/repository/CustomAuctionRepositoryV1.java b/src/main/java/com/tasksprints/auction/domain/auction/repository/CustomAuctionRepositoryV1.java deleted file mode 100644 index b0694286..00000000 --- a/src/main/java/com/tasksprints/auction/domain/auction/repository/CustomAuctionRepositoryV1.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tasksprints.auction.domain.auction.repository; - -import com.tasksprints.auction.domain.auction.model.Auction; -import com.tasksprints.auction.domain.auction.model.AuctionCategory; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public class CustomAuctionRepositoryV1 { - - @PersistenceContext - private EntityManager entityManager; - - public List findByCategoryUsingEntityManager(AuctionCategory auctionCategoryName) { - String jpql = "SELECT a FROM auction a WHERE a.auctionCategory = :category"; - return entityManager.createQuery(jpql, Auction.class) - .setParameter("category", auctionCategoryName) - .getResultList(); - } -} diff --git a/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepository.java b/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepository.java index cc6eea8d..3999b874 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepository.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepository.java @@ -1,12 +1,10 @@ package com.tasksprints.auction.domain.auction.repository.support; +import com.tasksprints.auction.domain.auction.dto.request.AuctionRequest; import com.tasksprints.auction.domain.auction.model.Auction; -import com.tasksprints.auction.domain.auction.model.AuctionCategory; -import com.tasksprints.auction.domain.product.model.ProductCategory; import java.util.List; public interface AuctionCriteriaRepository { - public List getAuctionsByFilters(ProductCategory productCategory, - AuctionCategory category); + List getAuctionsByFilters(AuctionRequest.SearchCondition searchCondition); } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepositoryImpl.java b/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepositoryImpl.java index 0ed51694..9db471af 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepositoryImpl.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/repository/support/AuctionCriteriaRepositoryImpl.java @@ -1,10 +1,11 @@ package com.tasksprints.auction.domain.auction.repository.support; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.OrderSpecifier; import com.querydsl.jpa.impl.JPAQueryFactory; +import com.tasksprints.auction.domain.auction.dto.request.AuctionRequest; import com.tasksprints.auction.domain.auction.model.Auction; -import com.tasksprints.auction.domain.auction.model.AuctionCategory; import com.tasksprints.auction.domain.auction.model.QAuction; -import com.tasksprints.auction.domain.product.model.ProductCategory; import com.tasksprints.auction.domain.product.model.QProduct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -16,17 +17,55 @@ public class AuctionCriteriaRepositoryImpl implements AuctionCriteriaRepository { private final JPAQueryFactory queryFactory; - public List getAuctionsByFilters(ProductCategory productCategory, - AuctionCategory category - ) { + public List getAuctionsByFilters(AuctionRequest.SearchCondition condition) { QAuction auction = QAuction.auction; QProduct product = QProduct.product; - return queryFactory.selectFrom(auction) - .leftJoin(auction.product, product) // Auction과 Product 조인 - .where(category != null ? auction.auctionCategory.eq(category) : null) - .where(productCategory != null ? product.category.eq(productCategory) : null) // ProductCategory 필터 - .fetch(); + + BooleanBuilder builder = buildSearchCondition(condition, auction, product); + + var query = queryFactory.selectFrom(auction) + .leftJoin(auction.product, product) + .where(builder); + + OrderSpecifier sortOrder = getSortOrder(condition, auction); + if (sortOrder != null) { + query = query.orderBy(sortOrder); + } + + return query.fetch(); } + private BooleanBuilder buildSearchCondition(AuctionRequest.SearchCondition condition, QAuction auction, QProduct product) { + BooleanBuilder builder = new BooleanBuilder(); + if (condition.getAuctionCategory() != null) { + builder.and(auction.auctionCategory.eq(condition.getAuctionCategory())); + } + if (condition.getProductCategory() != null) { + builder.and(product.category.eq(condition.getProductCategory())); + } + if (condition.getMinPrice() != null && condition.getMaxPrice() != null) { + builder.and(auction.startingBid.between(condition.getMinPrice(), condition.getMaxPrice())); + } + if (condition.getStartTime() != null && condition.getEndTime() != null) { + builder.and(auction.endTime.between(condition.getStartTime(), condition.getEndTime())); + } + if (condition.getAuctionStatus() != null) { + builder.and(auction.auctionStatus.eq(condition.getAuctionStatus())); + } + + return builder; + } + + private OrderSpecifier getSortOrder(AuctionRequest.SearchCondition condition, QAuction auction) { + if (condition.getSortBy() != null) { + return switch (condition.getSortBy()) { + case "bidsAsc" -> auction.bids.size().asc(); + case "bidsDesc" -> auction.bids.size().desc(); + case "endingSoon" -> auction.endTime.asc(); + default -> null; + }; + } + return null; + } } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionService.java b/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionService.java index f901fada..788d1ddb 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionService.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionService.java @@ -17,13 +17,10 @@ public interface AuctionService { List getAuctionsByUser(Long userId); - List getAuctionsByProductCategory(AuctionRequest.ProductCategoryParam param); - List getAllAuctions(); AuctionResponse getAuctionById(Long auctionId); - List getAuctionsByAuctionCategory(AuctionRequest.AuctionCategoryParam param); + List getAuctionsByFilter(AuctionRequest.SearchCondition searchCondition); - List getAuctionsByFilter(AuctionRequest.ProductCategoryParam productCategoryParam, AuctionRequest.AuctionCategoryParam auctionCategoryParam); } diff --git a/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImpl.java b/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImpl.java index 766a1372..8cfef088 100644 --- a/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImpl.java +++ b/src/main/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImpl.java @@ -101,36 +101,15 @@ public AuctionResponse getAuctionById(Long auctionId) { return AuctionResponse.of(foundAuction); } - @Deprecated - @Override - public List getAuctionsByProductCategory(AuctionRequest.ProductCategoryParam param) { - List foundAuctions = auctionRepository.findAuctionByProduct_Category(param.getProductCategory()); - - return foundAuctions.stream() - .map(AuctionResponse::of) - .toList(); - - } - - @Deprecated - @Override - public List getAuctionsByAuctionCategory(AuctionRequest.AuctionCategoryParam param) { - List foundAuctions = auctionRepository.findAuctionsByAuctionCategory(param.getAuctionCategory()); - - return foundAuctions.stream() - .map(AuctionResponse::of) - .toList(); - } - /** * NULL POINTER EXCEPTION 발생 * NULL 안정성 보장을 해줬음 **/ @Override - public List getAuctionsByFilter(AuctionRequest.ProductCategoryParam productCategoryParam, AuctionRequest.AuctionCategoryParam auctionCategoryParam) { + public List getAuctionsByFilter(AuctionRequest.SearchCondition searchCondition) { List foundAuctions = auctionRepository.getAuctionsByFilters( - productCategoryParam != null ? productCategoryParam.getProductCategory() : null, - auctionCategoryParam != null ? auctionCategoryParam.getAuctionCategory() : null); + searchCondition + ); return foundAuctions.stream() .map(AuctionResponse::of) diff --git a/src/test/java/com/tasksprints/auction/api/AuctionControllerTest.java b/src/test/java/com/tasksprints/auction/api/AuctionControllerTest.java index f2700ef7..e6456531 100644 --- a/src/test/java/com/tasksprints/auction/api/AuctionControllerTest.java +++ b/src/test/java/com/tasksprints/auction/api/AuctionControllerTest.java @@ -6,6 +6,7 @@ import com.tasksprints.auction.domain.auction.dto.request.AuctionRequest; import com.tasksprints.auction.domain.auction.dto.response.AuctionResponse; import com.tasksprints.auction.domain.auction.model.AuctionCategory; +import com.tasksprints.auction.domain.auction.model.AuctionStatus; import com.tasksprints.auction.domain.auction.service.AuctionService; import com.tasksprints.auction.domain.bid.dto.BidResponse; import com.tasksprints.auction.domain.bid.service.BidService; @@ -22,6 +23,7 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -109,31 +111,47 @@ public void testGetAuctionStatus_Success() throws Exception { } @Test - @DisplayName("경매 유형을 통한 경매목록 조회") - public void testFindAuctionByUsingAuctionCategory_Success() throws Exception { + @DisplayName("QueryString을 통한 경매 목록 조회") + public void testFindAuctionByUsingQueryString_Success() throws Exception { + // Given List auctionResponseList = new ArrayList<>(); - when(auctionService.getAuctionsByFilter(any(), any())).thenReturn(auctionResponseList); + when(auctionService.getAuctionsByFilter(any())).thenReturn(auctionResponseList); + + // When & Then mockMvc.perform(get("/api/v1/auction") - .param("auctionCategory", String.valueOf(AuctionCategory.PRIVATE_FREE))) + .param("auctionCategory", AuctionCategory.PRIVATE_FREE.name()) + .param("productCategory", "여성의류") + .param("startTime", LocalDateTime.now().minusDays(1).toString()) + .param("endTime", LocalDateTime.now().toString()) + .param("minPrice", "100") + .param("maxPrice", "500") + .param("auctionStatus", AuctionStatus.ACTIVE.name()) + .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.message").value(ApiResponseMessages.ALL_AUCTIONS_RETRIEVED)); } - /** - * 해당 기저 처리 해야함. - * 기본값으로 대응 PUBLIC_FREE로 - */ - @Test - @DisplayName("잘못된 유형을 통한 경매목록 조회(기본값으로 대응)") - public void testFindAuctionByUsingWrongAuctionCategory_Success() throws Exception { - List auctionResponseList = new ArrayList<>(); - when(auctionService.getAuctionsByFilter(any(), any())).thenReturn(auctionResponseList); +// @Test +// @DisplayName("잘못된 유형을 통한 경매목록 조회(기본값으로 대응)") +// public void testFindAuctionByUsingWrongAuctionCategory_Success() throws Exception { +// List auctionResponseList = new ArrayList<>(); +// when(auctionService.getAuctionsByFilter(any(), any())).thenReturn(auctionResponseList); +// +// mockMvc.perform(get("/api/v1/auction") +// .param("auctionCategory", "NON")) +// .andExpect(status().isOk()) +// .andExpect(jsonPath("$.message").value(ApiResponseMessages.ALL_AUCTIONS_RETRIEVED)); +// } - mockMvc.perform(get("/api/v1/auction") - .param("auctionCategory", "NON")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.message").value(ApiResponseMessages.ALL_AUCTIONS_RETRIEVED)); - } +// @Test +// @DisplayName("마감 기한이 24시간 이하로 남은 경매 목록 조회") +// public void testFindAuctionsEndWithin24Hours_Success() throws Exception { +// +// /* +// 테스트 코드 추가 +// * */ +// +// } @Test @DisplayName("입찰 제출 성공") diff --git a/src/test/java/com/tasksprints/auction/domain/auction/repository/AuctionRepositoryTest.java b/src/test/java/com/tasksprints/auction/domain/auction/repository/AuctionRepositoryTest.java index d9b82b59..1455d8b5 100644 --- a/src/test/java/com/tasksprints/auction/domain/auction/repository/AuctionRepositoryTest.java +++ b/src/test/java/com/tasksprints/auction/domain/auction/repository/AuctionRepositoryTest.java @@ -1,6 +1,7 @@ package com.tasksprints.auction.domain.auction.repository; import com.tasksprints.auction.common.config.QueryDslConfig; +import com.tasksprints.auction.domain.auction.dto.request.AuctionRequest; import com.tasksprints.auction.domain.auction.model.Auction; import com.tasksprints.auction.domain.auction.model.AuctionCategory; import com.tasksprints.auction.domain.auction.model.AuctionStatus; @@ -46,6 +47,17 @@ public void setUp() { userRepository.save(seller); } + private Auction createAuction(User seller, AuctionCategory category, AuctionStatus status) { + return Auction.create( + LocalDateTime.of(2024, 8, 1, 10, 0), + LocalDateTime.of(2024, 9, 1, 10, 0), + BigDecimal.valueOf(100.00), + category, + status, + seller + ); + } + @Test @DisplayName("사용자 ID로 경매 목록 조회") public void testFindAuctionsByUserId() { @@ -93,13 +105,13 @@ public void testFindAuctionsByAuctionCategory() { Auction auction1 = createAuction(seller, AuctionCategory.PUBLIC_FREE, AuctionStatus.ACTIVE); Auction auction2 = createAuction(seller, AuctionCategory.PUBLIC_PAID, AuctionStatus.PENDING); Auction auction3 = createAuction(seller, AuctionCategory.PUBLIC_PAID, AuctionStatus.PENDING); - + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_PAID, null, null, null, null, null, null, null); auctionRepository.save(auction1); auctionRepository.save(auction2); auctionRepository.save(auction3); //when - List auctions = auctionRepository.findAuctionsByAuctionCategory(AuctionCategory.PUBLIC_PAID); + List auctions = auctionRepository.getAuctionsByFilters(condition); //then assertThat(auctions).hasSize(2); @@ -111,11 +123,11 @@ public void testFindAuctionsByAuctionCategory() { public void testFindAllUsingFilter() { Auction auction1 = createAuction(seller, AuctionCategory.PUBLIC_FREE, AuctionStatus.ACTIVE); Auction auction2 = createAuction(seller, AuctionCategory.PUBLIC_PAID, AuctionStatus.PENDING); - + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_FREE, null, null, null, null, null, null, null); auctionRepository.save(auction1); auctionRepository.save(auction2); - List auctions = auctionRepository.getAuctionsByFilters(null, AuctionCategory.PUBLIC_FREE); + List auctions = auctionRepository.getAuctionsByFilters(condition); log.info(auctions.toString()); assertThat(auctions).hasSize(1); @@ -125,14 +137,40 @@ public void testFindAllUsingFilter() { } - private Auction createAuction(User seller, AuctionCategory category, AuctionStatus status) { - return Auction.create( - LocalDateTime.now(), - LocalDateTime.now().plusDays(7), - BigDecimal.valueOf(100.00), - category, - status, - seller - ); - } +// @Test +// @DisplayName("경매 마감 시간까지 24시간 이하로 남은 경매 목록 조회") +// public void testFindAuctionsByEndTimeBetweenOrderByEndTimeAsc() { +// //given +// LocalDateTime fixedNow = LocalDateTime.of(2024, 9, 1, 10, 0); +// LocalDateTime next24Hours = fixedNow.plusHours(24); +// +// List auctions = List.of( +// createAuction(fixedNow.plusHours(23), AuctionStatus.ACTIVE), +// createAuction(fixedNow.plusHours(22), AuctionStatus.ACTIVE), +// createAuction(fixedNow.plusHours(21), AuctionStatus.ACTIVE), +// createAuction(fixedNow.plusHours(48), AuctionStatus.ACTIVE), +// createAuction(fixedNow.plusHours(20), AuctionStatus.PENDING) +// ); +// +// auctionRepository.saveAll(auctions); +// +// // when +// List result = auctionRepository.getAuctionsEndWith24Hours(fixedNow, next24Hours, AuctionStatus.ACTIVE); +// +// //then +// assertThat(result).hasSize(3); +// +// assertAll("endTime을 기준으로 오름차순 정렬이 되었는지 확인", +// () -> { +// LocalDateTime previousEndTime = null; +// for (Auction auction : result) { +// if (previousEndTime != null) { +// assertThat(auction.getEndTime()).isAfterOrEqualTo(previousEndTime); +// } +// previousEndTime = auction.getEndTime(); +// } +// } +// ); +// } + } diff --git a/src/test/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImplTest.java b/src/test/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImplTest.java index 85c6c77a..224ac20c 100644 --- a/src/test/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImplTest.java +++ b/src/test/java/com/tasksprints/auction/domain/auction/service/AuctionServiceImplTest.java @@ -25,7 +25,6 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -62,8 +61,20 @@ private Auction createAuction(Long auctionId, User seller, AuctionStatus status) .id(auctionId) .auctionCategory(AuctionCategory.PUBLIC_PAID) .auctionStatus(status) - .startTime(LocalDateTime.now()) - .endTime(LocalDateTime.now().plusDays(7)) + .startTime(LocalDateTime.of(2024, 8, 1, 10, 0)) + .endTime(LocalDateTime.of(2024, 9, 1, 10, 0)) + .startingBid(BigDecimal.valueOf(100.00)) + .seller(seller) + .build(); + } + + private Auction createAuction(Long auctionId, LocalDateTime endTime, AuctionStatus status) { + return Auction.builder() + .id(auctionId) + .auctionCategory(AuctionCategory.PUBLIC_PAID) + .auctionStatus(status) + .startTime(LocalDateTime.of(2024, 8, 1, 10, 0)) + .endTime(endTime) .startingBid(BigDecimal.valueOf(100.00)) .seller(seller) .build(); @@ -309,15 +320,15 @@ class GetAuctionsByAuctionCategoryTests { public void testGetAuctionsByAuctionCategory_Success() { Auction auction1 = createAuction(1L, seller, AuctionStatus.PENDING); Auction auction2 = createAuction(2L, seller, AuctionStatus.PENDING); - AuctionRequest.AuctionCategoryParam param = new AuctionRequest.AuctionCategoryParam(AuctionCategory.PUBLIC_PAID); + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_PAID, null, null, null, null, null, null, null); List expectedAuctions = List.of(auction1, auction2); - when(auctionRepository.findAuctionsByAuctionCategory(AuctionCategory.PUBLIC_PAID)).thenReturn(expectedAuctions); + when(auctionRepository.getAuctionsByFilters(condition)).thenReturn(expectedAuctions); List expectedResponses = expectedAuctions.stream() .map(AuctionResponse::of) - .collect(Collectors.toList()); + .toList(); - List actualAuctions = auctionService.getAuctionsByAuctionCategory(param); + List actualAuctions = auctionService.getAuctionsByFilter(condition); assertThat(actualAuctions).isEqualTo(expectedResponses); } @@ -326,15 +337,15 @@ public void testGetAuctionsByAuctionCategory_Success() { public void testGetAuctionsByAuctionCategory_Success_Criteria() { Auction auction1 = createAuction(1L, seller, AuctionStatus.PENDING); Auction auction2 = createAuction(2L, seller, AuctionStatus.PENDING); - AuctionRequest.AuctionCategoryParam param = new AuctionRequest.AuctionCategoryParam(AuctionCategory.PUBLIC_PAID); + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_PAID, null, null, null, null, null, null, null); List expectedAuctions = List.of(auction1, auction2); - when(auctionRepository.getAuctionsByFilters(null, AuctionCategory.PUBLIC_PAID)).thenReturn(expectedAuctions); + when(auctionRepository.getAuctionsByFilters(condition)).thenReturn(expectedAuctions); List expectedResponses = expectedAuctions.stream() .map(AuctionResponse::of) .toList(); - List actualAuctions = auctionService.getAuctionsByFilter(null, param); + List actualAuctions = auctionService.getAuctionsByFilter(condition); assertThat(actualAuctions).isEqualTo(expectedResponses); } @@ -342,12 +353,12 @@ public void testGetAuctionsByAuctionCategory_Success_Criteria() { @DisplayName("경매 유형 조회 : [결과 없음]") public void testGetAuctionsByAuctionCategory_AuctionNotFound() { List emptyAuctionList = List.of(); - AuctionRequest.AuctionCategoryParam param = new AuctionRequest.AuctionCategoryParam(AuctionCategory.PUBLIC_FREE); + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_FREE, null, null, null, null, null, null, null); - when(auctionRepository.findAuctionsByAuctionCategory(AuctionCategory.PUBLIC_FREE)) + when(auctionRepository.getAuctionsByFilters(condition)) .thenReturn(emptyAuctionList); - List actualAuctions = auctionService.getAuctionsByAuctionCategory(param); + List actualAuctions = auctionService.getAuctionsByFilter(condition); assertThat(actualAuctions).isEmpty(); } @@ -356,14 +367,45 @@ public void testGetAuctionsByAuctionCategory_AuctionNotFound() { @DisplayName("경매 유형 조회 : [결과 없음] - Criteria 사용") public void testGetAuctionsByAuctionCategory_AuctionNotFound_Criteria() { List emptyAuctionList = List.of(); - AuctionRequest.AuctionCategoryParam param = new AuctionRequest.AuctionCategoryParam(AuctionCategory.PUBLIC_FREE); + AuctionRequest.SearchCondition condition = new AuctionRequest.SearchCondition(AuctionCategory.PUBLIC_PAID, null, null, null, null, null, null, null); - when(auctionRepository.getAuctionsByFilters(null, AuctionCategory.PUBLIC_FREE)) + when(auctionRepository.getAuctionsByFilters(condition)) .thenReturn(emptyAuctionList); - List actualAuctions = auctionService.getAuctionsByFilter(null, param); + List actualAuctions = auctionService.getAuctionsByFilter(condition); assertThat(actualAuctions).isEmpty(); } } + +// @Nested +// @DisplayName("경매 마감 시간이 24시간 이하인 경매 목록 조회") +// class GetAuctionsByEndTimeBetweenAndAuctionStatusOrderByEndTimeAscTests { +// @Test +// @DisplayName("경매 마감 임박 목록 조회 : 성공") +// public void testGetAuctionsByEndTimeBetweenAndAuctionStatusOrderByEndTimeAsc_Success() { +// //given +// LocalDateTime fixedNow = LocalDateTime.of(2024, 9, 1, 10, 0); +// LocalDateTime next24Hours = fixedNow.plusHours(24); +// +// List expectedAuctions = List.of(createAuction(1L, fixedNow.plusHours(21), AuctionStatus.ACTIVE), +// createAuction(2L, fixedNow.plusHours(22), AuctionStatus.ACTIVE), +// createAuction(3L, fixedNow.plusHours(23), AuctionStatus.ACTIVE) +// ); +// +// List expectedResponses = expectedAuctions.stream() +// .map(AuctionResponse::of) +// .toList(); +// +// when(auctionRepository.getAuctionsEndWith24Hours(fixedNow, next24Hours, AuctionStatus.ACTIVE)).thenReturn(expectedAuctions); +// List actualResponses = auctionService.getAuctionsEndWith24Hours(fixedNow, next24Hours); +// +// //then +// assertThat(actualResponses).isEqualTo(expectedResponses); +// +// +// } +// } + + } diff --git a/src/test/java/com/tasksprints/auction/domain/product/ProductServiceImplTest.java b/src/test/java/com/tasksprints/auction/domain/product/ProductServiceImplTest.java index 1e80f143..b751f060 100644 --- a/src/test/java/com/tasksprints/auction/domain/product/ProductServiceImplTest.java +++ b/src/test/java/com/tasksprints/auction/domain/product/ProductServiceImplTest.java @@ -99,9 +99,9 @@ private void deleteAllImagesInDirectory(String directoryPath) throws IOException .forEach(filePath -> { try { Files.delete(filePath); // 파일 삭제 - System.out.println("Deleted: " + filePath.toString()); // 삭제된 파일 로그 출력 + System.out.println("Deleted: " + filePath); // 삭제된 파일 로그 출력 } catch (IOException e) { - System.err.println("Error deleting file: " + filePath.toString() + " - " + e.getMessage()); // 삭제 실패 로그 출력 + System.err.println("Error deleting file: " + filePath + " - " + e.getMessage()); // 삭제 실패 로그 출력 } }); }