chore: update
This commit is contained in:
@@ -52,9 +52,8 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkiverse.wiremock</groupId>
|
||||
<artifactId>quarkus-wiremock-test</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5-mockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -66,10 +65,6 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-messaging-kafka</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-redis-client</artifactId>
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
package com.drinkool.controllers;
|
||||
|
||||
import static io.smallrye.graphql.client.core.Argument.arg;
|
||||
import static io.smallrye.graphql.client.core.Document.document;
|
||||
import static io.smallrye.graphql.client.core.Field.field;
|
||||
import static io.smallrye.graphql.client.core.Operation.operation;
|
||||
|
||||
import com.drinkool.lib.dtos.CartItemRequest;
|
||||
import com.drinkool.lib.dtos.event.MenuItemValidation;
|
||||
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
|
||||
import io.quarkus.redis.datasource.hash.ReactiveHashCommands;
|
||||
import io.quarkus.redis.datasource.keys.ReactiveKeyCommands;
|
||||
import io.quarkus.redis.datasource.value.ReactiveValueCommands;
|
||||
import io.smallrye.graphql.client.GraphQLClient;
|
||||
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.reactive.messaging.Channel;
|
||||
import org.eclipse.microprofile.reactive.messaging.Emitter;
|
||||
import org.eclipse.microprofile.reactive.messaging.Incoming;
|
||||
|
||||
@Path("/")
|
||||
public class CartController {
|
||||
|
||||
@Inject
|
||||
@GraphQLClient("eatery-client")
|
||||
DynamicGraphQLClient dynamicClient;
|
||||
|
||||
@Inject
|
||||
ReactiveRedisDataSource redisDataSource;
|
||||
|
||||
@Inject
|
||||
@Channel("menu-validation-out")
|
||||
Emitter<MenuItemValidation> validationEmitter;
|
||||
|
||||
private ReactiveValueCommands<String, String> valueCommands;
|
||||
private ReactiveHashCommands<String, String, String> hashCommands;
|
||||
private final ReactiveKeyCommands<String> keyCommands;
|
||||
|
||||
@Inject
|
||||
public CartController(ReactiveRedisDataSource ds) {
|
||||
this.redisDataSource = ds;
|
||||
this.valueCommands = ds.value(String.class);
|
||||
this.hashCommands = ds.hash(String.class);
|
||||
this.keyCommands = ds.key();
|
||||
}
|
||||
|
||||
@POST
|
||||
public Uni<Response> createCart(@QueryParam("eateryId") UUID eateryId) {
|
||||
if (eateryId == null) {
|
||||
return Uni.createFrom().item(
|
||||
Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity("EmptyEateryId")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
String eateryCacheKey = "eatery:exists:" + eateryId;
|
||||
|
||||
return valueCommands
|
||||
.get(eateryCacheKey)
|
||||
.<Boolean>chain(existsInCache -> {
|
||||
if (
|
||||
existsInCache != null && Boolean.TRUE.equals(existsInCache)
|
||||
) return Uni.createFrom().item(Boolean.TRUE);
|
||||
|
||||
var query = document(
|
||||
operation(
|
||||
field(
|
||||
"eateryById",
|
||||
List.of(arg("id", eateryId.toString())),
|
||||
field("id")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return dynamicClient
|
||||
.executeAsync(query)
|
||||
.map(response -> !response.hasError() && response.getData() != null);
|
||||
})
|
||||
.chain(isValid -> {
|
||||
if (Boolean.TRUE.equals(isValid)) {
|
||||
String cartId = UUID.randomUUID().toString();
|
||||
return valueCommands
|
||||
.setex("cart:" + cartId, 86400, eateryId.toString())
|
||||
.replaceWith(Response.ok(cartId).build());
|
||||
}
|
||||
|
||||
return Uni.createFrom().item(
|
||||
Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("InvalidEateryId")
|
||||
.build()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{cartId}")
|
||||
public Uni<Response> addItem(
|
||||
@PathParam("cartId") String cartId,
|
||||
CartItemRequest request
|
||||
) {
|
||||
String cartKey = "cart:" + cartId;
|
||||
String cartItemsKey = cartKey + ":items";
|
||||
String menuKey = "menu:item:" + request.menuItemId;
|
||||
|
||||
return valueCommands
|
||||
.get(cartKey)
|
||||
.chain(cart -> {
|
||||
if (cart == null) {
|
||||
return Uni.createFrom().item(
|
||||
Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("CartNotFound")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
UUID eateryId = UUID.fromString(cart);
|
||||
|
||||
return valueCommands
|
||||
.get(menuKey)
|
||||
.chain(menuData ->
|
||||
hashCommands
|
||||
.hincrby(
|
||||
cartItemsKey,
|
||||
request.menuItemId.toString(),
|
||||
request.quantity
|
||||
)
|
||||
.call(_ -> keyCommands.expire(cartItemsKey, 86400L))
|
||||
.replaceWith(menuData)
|
||||
)
|
||||
.map(menuData -> {
|
||||
if (menuData != null) {
|
||||
return Response.ok("ItemAdded").build();
|
||||
}
|
||||
|
||||
MenuItemValidation validation = new MenuItemValidation();
|
||||
validation.menuItemId = request.menuItemId;
|
||||
validation.eateryId = eateryId;
|
||||
|
||||
validationEmitter.send(validation);
|
||||
|
||||
return Response.status(Response.Status.ACCEPTED)
|
||||
.entity("PendingVerification")
|
||||
.build();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// @Incoming("menu-validation-in") // Tên channel trong application.properties
|
||||
// public Uni<Void> processValidationResult(MenuItemStatusE event) {
|
||||
// // Giả sử event trả về có: menuItemId, eateryId, exists (boolean)
|
||||
|
||||
// if (!event.exists) {
|
||||
// // Nếu món ăn không tồn tại, ta xóa nó khỏi Redis
|
||||
// // Lưu ý: Vì ta không biết món này nằm ở cartId nào (do bạn yêu cầu bỏ cartId)
|
||||
// // Bạn sẽ cần một chiến lược tìm kiếm hoặc quản lý key hiệu quả.
|
||||
// // Cách 1: Nếu bạn có danh sách Cart của Eatery đó, duyệt qua và xóa:
|
||||
// // String cartItemsKey = "cart:" + event.cartId + ":items";
|
||||
// // return hashCommands.hdel(cartItemsKey, event.menuItemId.toString()).replaceWithVoid();
|
||||
// // Cách 2: Nếu xóa cache thông tin món ăn để các request sau cũng fail:
|
||||
// // return keyCommands.del("menu:item:" + event.menuItemId).replaceWithVoid();
|
||||
// }
|
||||
|
||||
// return Uni.createFrom().voidItem();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.drinkool.controllers;
|
||||
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
@RegisterRestClient(configKey = "eatery")
|
||||
@Path("/")
|
||||
public interface EateryController {
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
Uni<Response> getEateryById(@PathParam("id") UUID id);
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.drinkool.services;
|
||||
|
||||
import com.drinkool.InternalValue;
|
||||
import com.drinkool.controllers.EateryController;
|
||||
import com.drinkool.dtos.Cart;
|
||||
import com.drinkool.dtos.CartItem;
|
||||
import com.drinkool.lib.dtos.event.MenuItemValidation;
|
||||
import io.quarkus.redis.datasource.RedisDataSource;
|
||||
import io.quarkus.redis.datasource.hash.HashCommands;
|
||||
import io.quarkus.redis.datasource.value.ValueCommands;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -20,9 +22,7 @@ import org.eclipse.microprofile.graphql.GraphQLException;
|
||||
import org.eclipse.microprofile.graphql.Mutation;
|
||||
import org.eclipse.microprofile.graphql.Name;
|
||||
import org.eclipse.microprofile.graphql.Query;
|
||||
import org.eclipse.microprofile.reactive.messaging.Channel;
|
||||
import org.eclipse.microprofile.reactive.messaging.Emitter;
|
||||
import org.eclipse.microprofile.reactive.messaging.Incoming;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
@ApplicationScoped
|
||||
@GraphQLApi
|
||||
@@ -32,8 +32,8 @@ public class CartService {
|
||||
HttpServerRequest request;
|
||||
|
||||
@Inject
|
||||
@Channel("menu-validation-out")
|
||||
Emitter<MenuItemValidation> validationEmitter;
|
||||
@RestClient
|
||||
EateryController eateryController;
|
||||
|
||||
private final HashCommands<String, String, String> hashCommands;
|
||||
private final ValueCommands<String, String> valueCommands;
|
||||
@@ -45,25 +45,43 @@ public class CartService {
|
||||
}
|
||||
|
||||
@Mutation("createCart")
|
||||
public String createCart(@Name("eateryId") UUID eateryId) {
|
||||
public Uni<String> createCart(@Name("eateryId") UUID eateryId) {
|
||||
String userId = request.getHeader(InternalValue.userId);
|
||||
|
||||
String cartId = UUID.randomUUID().toString();
|
||||
String redisKey = "cart:" + cartId;
|
||||
return eateryController
|
||||
.getEateryById(eateryId)
|
||||
.onItem()
|
||||
.transform(response -> {
|
||||
if (response.getStatus() != Response.Status.OK.getStatusCode()) {
|
||||
throw new RuntimeException("NotFoundEatery");
|
||||
}
|
||||
|
||||
hashCommands.hset(
|
||||
redisKey,
|
||||
Map.of(
|
||||
"_metadata_owner",
|
||||
userId != null ? userId : "GUEST",
|
||||
"_metadata_eatery",
|
||||
eateryId.toString()
|
||||
)
|
||||
);
|
||||
String cartId = UUID.randomUUID().toString();
|
||||
String redisKey = "cart:" + cartId;
|
||||
|
||||
valueCommands.getDataSource().key().expire(redisKey, Duration.ofDays(30));
|
||||
hashCommands.hset(
|
||||
redisKey,
|
||||
Map.of(
|
||||
"_metadata_owner",
|
||||
userId != null ? userId : "GUEST",
|
||||
"_metadata_eatery",
|
||||
eateryId.toString()
|
||||
)
|
||||
);
|
||||
|
||||
return cartId;
|
||||
valueCommands
|
||||
.getDataSource()
|
||||
.key()
|
||||
.expire(redisKey, Duration.ofDays(30));
|
||||
|
||||
return cartId;
|
||||
})
|
||||
.onFailure()
|
||||
.transform(f ->
|
||||
new GraphQLException(
|
||||
"Lỗi kết nối đến dịch vụ nhà hàng: " + f.getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Query("getCart")
|
||||
@@ -102,17 +120,11 @@ public class CartService {
|
||||
|
||||
UUID eateryId = UUID.fromString(hashCommands.hget(key, "_metadata_eatery"));
|
||||
|
||||
validationEmitter.send(new MenuItemValidation(menuItemId, eateryId));
|
||||
// validationEmitter.send(new MenuItemValidation(menuItemId, eateryId));
|
||||
|
||||
hashCommands.hincrby(key, menuItemId.toString(), quantity);
|
||||
hashCommands.getDataSource().key().expire(key, Duration.ofDays(30));
|
||||
|
||||
return getCart(cartId);
|
||||
}
|
||||
|
||||
@Incoming("menuItem-deleted-in")
|
||||
public void removeItem(UUID cartId, String menuItemId) {
|
||||
String key = "cart:" + cartId;
|
||||
hashCommands.hdel(key, menuItemId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,5 @@ quarkus.index-dependency.lib.artifact-id=lib
|
||||
# Redis
|
||||
quarkus.redis.hosts=redis://${REDIS_SERVICE_SERVICE_HOST:localhost}:${REDIS_SERVICE_SERVICE_PORT:6379}
|
||||
|
||||
# GraphQl
|
||||
quarkus.smallrye-graphql-client.eatery-client.url=http://eatery-service/graphql
|
||||
|
||||
# Kafka
|
||||
%prod.mp.messaging.connector.smallrye-kafka.bootstrap.servers=${KAFKA_SERVICE_SERVICE_HOST:host.docker.internal}:9092
|
||||
quarkus.messaging.kafka.serializer-generation.enabled=true
|
||||
|
||||
## Create menu validation topic
|
||||
mp.messaging.outgoing.menu-validation-out.connector=smallrye-kafka
|
||||
mp.messaging.outgoing.menu-validation-out.topic=menu-validation
|
||||
mp.messaging.outgoing.menu-validation-out.value.serializer=io.quarkus.kafka.client.serialization.ObjectMapperSerializer
|
||||
# ### In
|
||||
# mp.messaging.incoming.menu-validation-in.connector=smallrye-kafka
|
||||
# mp.messaging.incoming.menu-validation-in.topic=menu-validation
|
||||
# mp.messaging.incoming.menu-validation-in.value.serializer=io.quarkus.kafka.client.serialization.ObjectMapperSerializer
|
||||
# Rest Client
|
||||
quarkus.rest-client.eatery.url=http://eatery-service
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
package com.drinkool.controllers;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.drinkool.dtos.CartItemRequest;
|
||||
import com.drinkool.dtos.event.MenuItemValidation;
|
||||
import io.quarkiverse.wiremock.devservice.ConnectWireMock;
|
||||
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
|
||||
import io.quarkus.test.common.http.TestHTTPEndpoint;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.smallrye.reactive.messaging.memory.InMemoryConnector;
|
||||
import io.smallrye.reactive.messaging.memory.InMemorySink;
|
||||
import jakarta.enterprise.inject.Any;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@QuarkusTest
|
||||
@TestHTTPEndpoint(CartController.class)
|
||||
@ConnectWireMock
|
||||
public class CartControllerTest {
|
||||
|
||||
@Inject
|
||||
ReactiveRedisDataSource redisDataSource;
|
||||
|
||||
@Inject
|
||||
@Any
|
||||
InMemoryConnector connector;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
redisDataSource.flushall().await().indefinitely();
|
||||
|
||||
stubFor(
|
||||
post(urlEqualTo("/graphql")).willReturn(
|
||||
aResponse()
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(
|
||||
"{\"data\":{\"eateryById\":{\"id\":\"" + UUID.randomUUID() + "\"}}}"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
InMemorySink<MenuItemValidation> results = connector.sink(
|
||||
"menu-validation-out"
|
||||
);
|
||||
results.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateCart_Success_WithRealRedis() {
|
||||
UUID eateryId = UUID.randomUUID();
|
||||
|
||||
// 2. Gọi API tạo giỏ hàng
|
||||
String cartId = given()
|
||||
.queryParam("eateryId", eateryId.toString())
|
||||
.when()
|
||||
.post()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.asString();
|
||||
|
||||
// 3. Kiểm tra Redis thật xem dữ liệu đã được lưu chưa
|
||||
String savedEateryId = redisDataSource
|
||||
.value(String.class)
|
||||
.get("cart:" + cartId)
|
||||
.await()
|
||||
.indefinitely();
|
||||
|
||||
assert savedEateryId.equals(eateryId.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddItem_PendingVerification_WithKafkaMock() {
|
||||
InMemorySink<MenuItemValidation> results = connector.sink(
|
||||
"menu-validation-out"
|
||||
);
|
||||
// 1. Chuẩn bị dữ liệu: Tạo một giỏ hàng sẵn trong Redis
|
||||
String cartId = UUID.randomUUID().toString();
|
||||
UUID eateryId = UUID.randomUUID();
|
||||
redisDataSource
|
||||
.value(String.class)
|
||||
.set("cart:" + cartId, eateryId.toString())
|
||||
.await()
|
||||
.indefinitely();
|
||||
|
||||
// 2. Gửi request thêm món ăn KHÔNG có trong cache menu (menuData null)
|
||||
CartItemRequest request = new CartItemRequest();
|
||||
request.menuItemId = UUID.randomUUID();
|
||||
request.quantity = 2;
|
||||
|
||||
given()
|
||||
.pathParam("cartId", cartId)
|
||||
.contentType("application/json")
|
||||
.body(request)
|
||||
.when()
|
||||
.post("/{cartId}")
|
||||
.then()
|
||||
.statusCode(202) // ACCEPTED
|
||||
.body(is("PendingVerification"));
|
||||
|
||||
// 3. Kiểm tra Redis: hincrby có hoạt động không?
|
||||
String quantityStr = redisDataSource
|
||||
.hash(String.class)
|
||||
.hget("cart:" + cartId + ":items", request.menuItemId.toString())
|
||||
.await()
|
||||
.indefinitely();
|
||||
|
||||
assert quantityStr.equals("2");
|
||||
|
||||
assertEquals(1, results.received().size());
|
||||
|
||||
MenuItemValidation payload = results.received().get(0).getPayload();
|
||||
assertEquals(request.menuItemId, payload.menuItemId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddItem_Success_WhenMenuInCache() {
|
||||
InMemorySink<MenuItemValidation> results = connector.sink(
|
||||
"menu-validation-out"
|
||||
);
|
||||
// 1. Chuẩn bị: Cart và Menu đã có sẵn trong Redis cache
|
||||
String cartId = UUID.randomUUID().toString();
|
||||
UUID eateryId = UUID.randomUUID();
|
||||
UUID menuItemId = UUID.randomUUID();
|
||||
|
||||
redisDataSource
|
||||
.value(String.class)
|
||||
.set("cart:" + cartId, eateryId.toString())
|
||||
.await()
|
||||
.indefinitely();
|
||||
// Giả lập menu đã verify (có data trong cache)
|
||||
redisDataSource
|
||||
.value(String.class)
|
||||
.set("menu:item:" + menuItemId, "{\"name\":\"Pizza\"}")
|
||||
.await()
|
||||
.indefinitely();
|
||||
|
||||
CartItemRequest request = new CartItemRequest();
|
||||
request.menuItemId = menuItemId;
|
||||
request.quantity = 1;
|
||||
|
||||
// 2. Thực thi
|
||||
given()
|
||||
.pathParam("cartId", cartId)
|
||||
.contentType("application/json")
|
||||
.body(request)
|
||||
.when()
|
||||
.post("/{cartId}")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body(is("ItemAdded"));
|
||||
|
||||
// 3. Kiểm tra: Không được gửi Kafka vì đã có trong cache
|
||||
assertEquals(0, results.received().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddItem_CartNotFound() {
|
||||
CartItemRequest request = new CartItemRequest();
|
||||
request.menuItemId = UUID.randomUUID();
|
||||
request.quantity = 1;
|
||||
|
||||
given()
|
||||
.pathParam("cartId", "invalid-cart-id")
|
||||
.contentType("application/json")
|
||||
.body(request)
|
||||
.when()
|
||||
.post("/{cartId}")
|
||||
.then()
|
||||
.statusCode(404)
|
||||
.body(is("CartNotFound"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.drinkool.services;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.drinkool.controllers.EateryController;
|
||||
import io.quarkus.redis.datasource.RedisDataSource;
|
||||
import io.quarkus.redis.datasource.hash.HashCommands;
|
||||
import io.quarkus.redis.datasource.keys.KeyCommands;
|
||||
import io.quarkus.redis.datasource.value.ValueCommands;
|
||||
import io.quarkus.test.InjectMock;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.helpers.test.UniAssertSubscriber;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@QuarkusTest
|
||||
public class CartServiceTest {
|
||||
|
||||
@Inject
|
||||
CartService cartService;
|
||||
|
||||
@InjectMock
|
||||
@RestClient
|
||||
EateryController eateryController;
|
||||
|
||||
@InjectMock
|
||||
RedisDataSource redisDataSource;
|
||||
|
||||
HashCommands<String, String, String> hashCommands;
|
||||
ValueCommands<String, String> valueCommands;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
hashCommands = mock(HashCommands.class);
|
||||
valueCommands = mock(ValueCommands.class);
|
||||
|
||||
// Mock các chain gọi của RedisDataSource
|
||||
when(redisDataSource.hash(String.class)).thenReturn(hashCommands);
|
||||
when(redisDataSource.value(String.class)).thenReturn(valueCommands);
|
||||
|
||||
// Mock phần expire key
|
||||
var keyCommands = mock(KeyCommands.class);
|
||||
when(valueCommands.getDataSource()).thenReturn(redisDataSource);
|
||||
when(redisDataSource.key()).thenReturn(keyCommands);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateCart_Success() {
|
||||
UUID eateryId = UUID.randomUUID();
|
||||
|
||||
when(eateryController.getEateryById(eateryId)).thenReturn(
|
||||
Uni.createFrom().item(Response.ok().build())
|
||||
);
|
||||
|
||||
String cartId = cartService
|
||||
.createCart(eateryId)
|
||||
.subscribe()
|
||||
.withSubscriber(UniAssertSubscriber.create())
|
||||
.awaitItem()
|
||||
.getItem();
|
||||
|
||||
assertNotNull(cartId);
|
||||
verify(hashCommands, times(1)).hset(anyString(), anyMap());
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
# Redis
|
||||
quarkus.smallrye-graphql-client.eatery-client.url=http://localhost:8089/graphql
|
||||
|
||||
# WireMock
|
||||
quarkus.wiremock.devservices.host=0.0.0.0
|
||||
quarkus.wiremock.devservices.port=8089
|
||||
|
||||
# Kafka
|
||||
quarkus.kafka.devservices.enabled=false
|
||||
|
||||
mp.messaging.outgoing.menu-validation-out.connector=smallrye-in-memory
|
||||
mp.messaging.incoming.menu-validation-in.connector=smallrye-in-memory
|
||||
@@ -13,6 +13,10 @@ import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.graphql.GraphQLApi;
|
||||
@@ -23,6 +27,7 @@ import org.eclipse.microprofile.reactive.messaging.Incoming;
|
||||
|
||||
@ApplicationScoped
|
||||
@GraphQLApi
|
||||
@Path("/")
|
||||
public class EateryService {
|
||||
|
||||
@Inject
|
||||
@@ -31,6 +36,20 @@ public class EateryService {
|
||||
@Inject
|
||||
HttpServerRequest request;
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public Response checkEateryExists(@PathParam("id") UUID id) {
|
||||
EateryEntity eatery = EateryEntity.findById(id);
|
||||
|
||||
if (eatery == null) {
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity("NotFoundEatery")
|
||||
.build();
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Incoming("manager-in")
|
||||
@Transactional
|
||||
public void consumeManagerSignup(ManagerCreate input) {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.drinkool.lib.dtos.event;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@RegisterForReflection
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MenuItemValidation {
|
||||
|
||||
public UUID menuItemId;
|
||||
public UUID eateryId;
|
||||
}
|
||||
Reference in New Issue
Block a user