Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions popi-reservation-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,16 @@ dependencies {
// Kafka
implementation 'org.springframework.kafka:spring-kafka'
testImplementation 'org.springframework.kafka:spring-kafka-test'

// Protobuf serialization
implementation "com.google.protobuf:protobuf-java:${protobufVersion}"

// gRPC
implementation "net.devh:grpc-client-spring-boot-starter:${grpcSpringVersion}"
implementation "io.grpc:grpc-netty-shaded:${grpcVersion}"
implementation "io.grpc:grpc-stub:${grpcVersion}"
implementation "io.grpc:grpc-inprocess:${grpcVersion}"

// prometheus
implementation 'io.micrometer:micrometer-registry-prometheus'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.lgcns.client;

import com.popi.common.grpc.member.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class MemberGrpcClient {

private final MemberServiceGrpc.MemberServiceBlockingStub memberServiceBlockingStub;

public MemberInternalInfoResponse findByMemberId(MemberInternalIdRequest request) {
return memberServiceBlockingStub.findByMemberId(request);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.lgcns.config;

import com.popi.common.grpc.member.MemberServiceGrpc;
import io.grpc.Channel;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("!test")
public class GrpcClientConfig {

@GrpcClient("member-service")
private Channel channel;

@Bean
public MemberServiceGrpc.MemberServiceBlockingStub memberServiceBlockingStub() {
return MemberServiceGrpc.newBlockingStub(channel);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.lgcns.repository;

import static com.lgcns.domain.MemberReservationStatus.RESERVED;
import static com.lgcns.domain.QMemberReservation.memberReservation;

import com.lgcns.domain.MemberReservation;
Expand All @@ -10,6 +9,7 @@
import com.lgcns.dto.response.HourlyReservationCount;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.LocalDate;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -44,25 +44,20 @@ public List<DailyReservationCountResponse> findDailyReservationCount(

@Override
public MemberReservation findUpcomingReservation(Long memberId) {
LocalDateTime now = LocalDateTime.now();
LocalDate nowDate = now.toLocalDate();
LocalTime nowTime = now.toLocalTime();

LocalDateTime threshold = LocalDateTime.now().minusMinutes(30);

return queryFactory
.selectFrom(memberReservation)
.where(
memberReservation.memberId.eq(memberId),
memberReservation.status.eq(RESERVED),
memberReservation
.reservationDate
.gt(nowDate)
.or(
memberReservation
.reservationDate
.eq(nowDate)
.and(
memberReservation.reservationTime.goe(
nowTime))))
memberReservation.status.eq(MemberReservationStatus.RESERVED),
Expressions.dateTimeTemplate(
LocalDateTime.class,
"cast(concat({0}, ' ', {1}) as timestamp)",
memberReservation.reservationDate,
memberReservation.reservationTime)
.after(threshold))
.orderBy(
memberReservation.reservationDate.asc(),
memberReservation.reservationTime.asc())
Expand All @@ -89,25 +84,20 @@ public List<Long> findHotPopupIds() {
@Override
public List<MemberReservation> findByMemberIdAndStatus(
Long memberId, MemberReservationStatus status) {
LocalDateTime now = LocalDateTime.now();
LocalDate nowDate = now.toLocalDate();
LocalTime nowTime = now.toLocalTime();

LocalDateTime threshold = LocalDateTime.now().minusMinutes(30);

return queryFactory
.selectFrom(memberReservation)
.where(
memberReservation.memberId.eq(memberId),
memberReservation.status.eq(status),
memberReservation
.reservationDate
.gt(nowDate)
.or(
memberReservation
.reservationDate
.eq(nowDate)
.and(
memberReservation.reservationTime.goe(
nowTime))))
Expressions.dateTimeTemplate(
LocalDateTime.class,
"cast(concat({0}, ' ', {1}) as timestamp)",
memberReservation.reservationDate,
memberReservation.reservationTime)
.after(threshold))
.orderBy(
memberReservation.reservationDate.asc(),
memberReservation.reservationTime.asc())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.lgcns.client.MemberGrpcClient;
import com.lgcns.client.managerClient.ManagerServiceClient;
import com.lgcns.client.managerClient.dto.request.PopupIdsRequest;
import com.lgcns.client.managerClient.dto.response.*;
import com.lgcns.client.memberClient.MemberServiceClient;
import com.lgcns.domain.MemberReservation;
import com.lgcns.dto.request.QrEntranceInfoRequest;
import com.lgcns.dto.request.SurveyChoiceRequest;
Expand All @@ -25,6 +25,8 @@
import com.lgcns.kafka.message.MemberEnteredMessage;
import com.lgcns.kafka.producer.MemberAnswerProducer;
import com.lgcns.repository.MemberReservationRepository;
import com.popi.common.grpc.member.MemberInternalIdRequest;
import com.popi.common.grpc.member.MemberInternalInfoResponse;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import java.awt.image.BufferedImage;
Expand Down Expand Up @@ -52,7 +54,7 @@ public class MemberReservationServiceImpl implements MemberReservationService {
private final MemberReservationRepository memberReservationRepository;

private final ManagerServiceClient managerServiceClient;
private final MemberServiceClient memberServiceClient;
private final MemberGrpcClient memberGrpcClient;

private final ApplicationEventPublisher eventPublisher;

Expand Down Expand Up @@ -236,8 +238,12 @@ public void createMemberReservation(String memberId, Long reservationId) {
@Override
public void updateMemberReservation(Long memberReservationId) {
MemberReservation memberReservation = findMemberReservationById(memberReservationId);

MemberInternalInfoResponse memberInfo =
memberServiceClient.findMemberInfo(memberReservation.getMemberId());
memberGrpcClient.findByMemberId(
MemberInternalIdRequest.newBuilder()
.setMemberId(memberReservation.getMemberId())
.build());

ReservationInfoResponse reservationInfoResponse =
managerServiceClient.findReservationById(memberReservation.getReservationId());
Expand All @@ -247,8 +253,8 @@ public void updateMemberReservation(Long memberReservationId) {
memberReservation.getId(),
memberReservation.getReservationId(),
reservationInfoResponse.popupId(),
memberInfo.age().toString(),
memberInfo.gender().toString(),
memberInfo.getAge().toString(),
memberInfo.getGender().toString(),
reservationInfoResponse.reservationDate(),
reservationInfoResponse.reservationTime());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,9 @@ manager:
member:
service:
name: members

grpc:
client:
member-service:
address: "static://localhost:9092"
negotiationType: plaintext
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.lgcns;

import com.lgcns.service.integration.GrpcClientTestConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

@SpringBootTest
@ActiveProfiles("test")
@Import(GrpcClientTestConfig.class)
class PopiReservationServiceApplicationTests {

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.lgcns.kafka;

import com.lgcns.service.integration.IntegrationTest;
import java.util.Map;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
Expand All @@ -8,7 +9,7 @@
import org.springframework.kafka.test.EmbeddedKafkaBroker;
import org.springframework.kafka.test.utils.KafkaTestUtils;

public abstract class AbstractKafkaIntegrationTest {
public abstract class AbstractKafkaIntegrationTest extends IntegrationTest {

@Autowired protected EmbeddedKafkaBroker embeddedKafkaBroker;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.support.serializer.JsonDeserializer;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.context.ActiveProfiles;

@SpringBootTest
@ActiveProfiles("test")
@EmbeddedKafka(partitions = 1, topics = MemberEnteredKafkaTest.TOPIC)
public class MemberEnteredKafkaTest extends AbstractKafkaIntegrationTest {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.lgcns.service.integration;

import static com.lgcns.service.integration.GrpcTestConstants.SERVER_NAME;

import com.popi.common.grpc.member.MemberServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.inprocess.InProcessChannelBuilder;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;

@TestConfiguration
public class GrpcClientTestConfig {

@Bean
public MemberServiceGrpc.MemberServiceBlockingStub memberServiceBlockingStub() {
ManagedChannel channel =
InProcessChannelBuilder.forName(SERVER_NAME)
.usePlaintext()
.directExecutor()
.build();

return MemberServiceGrpc.newBlockingStub(channel);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.lgcns.service.integration;

public final class GrpcTestConstants {
public static final String SERVER_NAME = "test-grpc-server";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.lgcns.service.integration;

import static com.lgcns.service.integration.GrpcTestConstants.SERVER_NAME;

import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.inprocess.InProcessServerBuilder;
import java.io.IOException;
import org.springframework.stereotype.Component;

@Component
public class InMemoryGrpcServer {

private Server server;

public void start(BindableService... services) throws IOException {
InProcessServerBuilder builder =
InProcessServerBuilder.forName(SERVER_NAME).directExecutor();
for (BindableService service : services) {
builder.addService(service);
}
server = builder.build().start();
}

public void shutdown() {
if (server != null) {
server.shutdownNow();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
package com.lgcns.service.integration;

import com.github.tomakehurst.wiremock.WireMockServer;
import java.io.IOException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureWireMock(port = 0)
public abstract class WireMockIntegrationTest {
@Import(GrpcClientTestConfig.class)
public abstract class IntegrationTest {

@Autowired protected WireMockServer wireMockServer;
@Autowired private InMemoryGrpcServer inMemoryGrpcServer;

@BeforeEach
void restartWireMock() {
void restartWireMock() throws IOException {
wireMockServer.stop();
wireMockServer.start();

inMemoryGrpcServer.start(new TestMemberGrpcService());
}

@AfterEach
void resetWireMock() {
wireMockServer.resetAll();

inMemoryGrpcServer.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.lgcns.domain.MemberReservation;
import com.lgcns.repository.MemberReservationRepository;
import com.lgcns.service.MemberReservationService;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand All @@ -23,7 +22,7 @@
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;

public class MemberReservationMockTest extends WireMockIntegrationTest {
public class MemberReservationMockTest extends IntegrationTest {

@MockitoBean private MemberReservationRepository memberReservationRepository;
@Autowired private MemberReservationService memberReservationService;
Expand Down Expand Up @@ -54,11 +53,7 @@ class 회원이_예약_생성_할_때 {
void 예약_저장_중_예외_발생시_복구_및_예외_반환() throws JsonProcessingException {
// given
reservationRedisTemplate.opsForValue().set(reservationId.toString(), 10L);
stubForFindMemberInternalInfo(
memberId,
200,
objectMapper.writeValueAsString(
Map.of("memberId", memberId, "role", "USER", "status", "NORMAL")));

given(memberReservationRepository.save(ArgumentMatchers.any(MemberReservation.class)))
.willThrow(new RuntimeException("DB error"));

Expand Down
Loading
Loading