Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#46] 경매 상품 결제(포인트) 기능 추가 #47

Merged
merged 8 commits into from
Dec 1, 2024
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.example.moduleapi.service.auction;

import com.example.moduleapi.controller.request.auction.BidRequest;
import com.example.moduleapi.controller.request.point.PointAmount;
import com.example.moduleapi.controller.response.auction.BidResponse;
import com.example.moduleapi.controller.response.product.ProductFindResponse;
import com.example.moduleapi.exception.auction.BiddingFailException;
import com.example.moduleapi.exception.auction.RedisLockAcquisitionException;
import com.example.moduleapi.exception.auction.RedisLockInterruptedException;
import com.example.moduleapi.service.point.PointService;
import com.example.moduleapi.service.product.ProductFacade;
import com.example.moduledomain.domain.user.CustomUserDetails;
import org.redisson.api.RLock;
Expand All @@ -25,12 +27,14 @@ public class AuctionService {
private final HighestBidSseNotificationService bidSseNotificationService;
private final RedissonClient redissonClient;
private final KafkaProducerService kafkaProducerService;
private final PointService pointService;

public AuctionService(ProductFacade productFacade, HighestBidSseNotificationService bidSseNotificationService, RedissonClient redissonClient, KafkaProducerService kafkaProducerService) {
public AuctionService(ProductFacade productFacade, HighestBidSseNotificationService bidSseNotificationService, RedissonClient redissonClient, KafkaProducerService kafkaProducerService, PointService pointService) {
this.productFacade = productFacade;
this.bidSseNotificationService = bidSseNotificationService;
this.redissonClient = redissonClient;
this.kafkaProducerService = kafkaProducerService;
this.pointService = pointService;
}

@Transactional
Expand Down Expand Up @@ -73,7 +77,6 @@ private Long processBid(CustomUserDetails user, BidRequest bidRequest, Long prod
throw new BiddingFailException(user.getUser().getUserId(), bidRequest.getBiddingPrice(), productId);
}

//updateRedisBidData(user, highestBidMap, bidRequest, productId);
return updateRedisBidData(user, highestBidMap, bidRequest, productId);
}

Expand All @@ -83,6 +86,9 @@ private void isBiddingAvailable(CustomUserDetails user, BidRequest bidRequest, L
if (biddingRequestTime.isAfter(product.getCloseDate())) {
throw new BiddingFailException(user.getUser().getUserId(), bidRequest.getBiddingPrice(), productId);
}

PointAmount pointAmount = new PointAmount(bidRequest.getBiddingPrice());
pointService.deductPoint(user, pointAmount);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

경매 입찰이 가능한지 검증하는 메서드쪽에 포인트 차감하는 코드를 추가했습니다

}

private Long updateRedisBidData(CustomUserDetails user, RMap<Long, Pair<Long, Long>> bidMap, BidRequest bidRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import com.example.moduleapi.controller.request.auction.BidRequest
import com.example.moduleapi.controller.response.product.ProductFindResponse
import com.example.moduleapi.exception.auction.BiddingFailException
import com.example.moduleapi.exception.auction.RedisLockAcquisitionException
import com.example.moduleapi.exception.point.PointDeductionFailedException
import com.example.moduleapi.fixture.product.ProductFixtures
import com.example.moduleapi.fixture.user.UserFixtures
import com.example.moduleapi.service.point.PointService
import com.example.moduleapi.service.product.ProductFacade
import com.example.moduledomain.domain.user.CustomUserDetails
import com.example.moduledomain.domain.user.User
Expand All @@ -23,7 +25,9 @@ class AuctionServiceTest extends Specification {

ProductFacade productFacade = Mock()
HighestBidSseNotificationService bidSseNotificationService = Mock()
AuctionService auctionService = new AuctionService(productFacade, bidSseNotificationService, redissonClient)
KafkaProducerService kafkaProducerService = Mock()
PointService pointService = Mock()
AuctionService auctionService = new AuctionService(productFacade, bidSseNotificationService, redissonClient, kafkaProducerService, pointService)

def "경매 입찰 성공"() {
given:
Expand Down Expand Up @@ -143,4 +147,47 @@ class AuctionServiceTest extends Specification {
def e = thrown(BiddingFailException.class)
e.message == String.format("입찰자: %s, 입찰가: %d, 입찰 상품: %d - 입찰 실패.", user.getUserId(), bidRequest.getBiddingPrice(), 1L)
}

def "포인트 부족으로 인한 입찰 실패"() {
given:
// Redisson Lock 관련
RLock lock = Mock()
redissonClient.getLock(_) >> lock
lock.tryLock(5, 10, TimeUnit.SECONDS) >> true
lock.isHeldByCurrentThread() >> true

// 입찰 제시
BidRequest bidRequest = new BidRequest(5000)

// User 관련
User user = UserFixtures.createUser()
user.id = 1L
CustomUserDetails customUserDetails = Mock()
customUserDetails.getUser() >> user

// Redisson Map 관련
RMap<Long, Pair<Long, Long>> highestBidMap = Mock()
Pair<Long, Long> userIdAndCurrentPrice = new Pair<>(1L, 7000L)
highestBidMap.get(1L) >> userIdAndCurrentPrice
userIdAndCurrentPrice.getSecond() >> 7000L
redissonClient.getMap(_) >> highestBidMap

// Product 관련
ProductFindResponse productFindResponse = ProductFixtures.createProductFindResponse()
productFacade.findById(1L) >> productFindResponse

// Point
pointService.deductPoint(customUserDetails, _) >> { throw new PointDeductionFailedException(1L) }

when:
auctionService.biddingPrice(customUserDetails, bidRequest, 1L)

then:
def e = thrown(PointDeductionFailedException.class)
e.message == 1L + ": 포인트가 부족합니다."
0 * kafkaProducerService.publishAuctionPriceChangeNotification(_, _)
0 * bidSseNotificationService.sendToAllUsers(_, _, _)
}


}
Loading