Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 30 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
FROM maven:3.9.6-eclipse-temurin-21 AS build

WORKDIR /app

COPY pom.xml .
COPY src ./src

RUN mvn clean test-compile package -DskipTests

RUN mvn dependency:copy-dependencies -DoutputDirectory=target/dependency

FROM eclipse-temurin:21-jdk-alpine

RUN apk add --no-cache curl

RUN mkdir -p /otel && \
curl -L -o /otel/opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

WORKDIR /app

COPY --from=build /app/target/classes ./classes
COPY --from=build /app/target/test-classes ./test-classes
COPY --from=build /app/target/dependency ./dependency

EXPOSE 8080

ENV JAVA_TOOL_OPTIONS="-javaagent:/otel/opentelemetry-javaagent.jar"

ENTRYPOINT ["java", "-cp", "classes:test-classes:dependency/*", "com.bazaar.orders.OrdersApplication", "--spring.profiles.active=stress"]
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,25 @@ cp .env.example .env
```bash
# The flag -v is optional
docker-compose down -v
```
```

---

## k6 Testing

In order to run the k6 tests, it is necessary to start the service in stress mode:

1. **Configure the enviorment variables** Create a `.env` file based on [.env.example](/auth/.env.example):
* `ENVIORMENT` - Must be set to `stress`.
* `RABBITMQ_ADDRESSES` - Must be set to `amqp://guest:guest@rabbitmq:5672/`.
2. **Running the Service**
```bash
docker compose -f docker-compose.test.yml up --build
```
3. **Stopping the Service**
```bash
docker compose -f docker-compose.test.yml down -v
```

> [!IMPORTANT]
> Please do not use production envs for k6 testing. If there is any issue, just ask.
44 changes: 44 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
services:
postgres-orders:
image: postgres:15
container_name: postgres-orders
env_file: .env
environment:
POSTGRES_DB: ${DATABASE_NAME}
POSTGRES_USER: ${DATABASE_USER}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
ports:
- "${EXPOSE_PORT}:${DATABASE_PORT}"
volumes:
- postgres_orders_data_test:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -p ${DATABASE_PORT} -U ${DATABASE_USER} -d ${DATABASE_NAME}"]
interval: 5s
timeout: 5s
retries: 5

orders-service:
build:
context: .
dockerfile: Dockerfile.test
image: bazaar-orders-test
container_name: orders-service-test
depends_on:
postgres-orders:
condition: service_healthy
env_file: .env
ports:
- "${PORT}:${PORT}"
healthcheck:
test: [ "CMD-SHELL", "curl -f http://localhost:${PORT}/actuator/health || exit 1" ]
interval: 10s
timeout: 5s
retries: 5

volumes:
postgres_orders_data_test:

networks:
default:
external: true
name: bazaar-network
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
18 changes: 7 additions & 11 deletions src/main/java/com/bazaar/orders/config/CacheConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,13 @@
@EnableCaching
public class CacheConfig {

@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager =
new CaffeineCacheManager("sellerReputation");
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("sellerReputation");

cacheManager.setCaffeine(
Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(5))
.maximumSize(1000)
);
cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(5)).maximumSize(1000));

return cacheManager;
}

return cacheManager;
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/bazaar/orders/config/MercadoPagoConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("!stress")
public class MercadoPagoConfig {

@Value("${mercadopago.access.token}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,19 @@ public OrderReviewDTO getOrderReview(@RequestHeader("X-User-Id") Long userId, @P
* @param orderId identifier of the reviewed order.
* @return matching {@link OrderReviewDTO}.
*/
@Operation(summary = "Get order review", description = "Retrieves the review and products review associated with an order.")
@Operation(summary = "Get order review",
description = "Retrieves the review and products review associated with an order.")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Order review retrieved successfully"),
@ApiResponse(responseCode = "404", description = "Order review not found"),
@ApiResponse(responseCode = "403", description = "Forbidden user") })
@GetMapping("/orders/{orderId}/detailed")
public OrderDetailedReviewDTO getDetailedOrderReview(@RequestHeader("X-User-Id") Long userId, @PathVariable Long orderId) {
public OrderDetailedReviewDTO getDetailedOrderReview(@RequestHeader("X-User-Id") Long userId,
@PathVariable Long orderId) {
LOGGER.info("Received request to get full review for order {} from user {}", orderId, userId);

return reviewsService.getDetailedOrderReview(orderId, userId);
}


/**
* Creates reviews for multiple products in an order.
* @param orderId identifier of the associated order.
Expand Down Expand Up @@ -176,7 +177,8 @@ public OrderItemReviewDTO getOrderItemReview(@PathVariable Long productId, @Path
* @return list of {@link OrderItemReviewDTO}.
*/
@Operation(summary = "Get product reviews", description = "Retrieves all reviews associated with a product.")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Product reviews retrieved successfully") })
@ApiResponses(
value = { @ApiResponse(responseCode = "200", description = "Product reviews retrieved successfully") })
@GetMapping("/products/{productId}")
public List<OrderItemReviewDTO> getProductReviews(@PathVariable Long productId) {
LOGGER.info("Received request to get reviews for product {}", productId);
Expand Down Expand Up @@ -204,7 +206,8 @@ public List<OrderReviewDTO> getSellerReviews(@PathVariable Long sellerId) {
* @return list of {@link OrderItemReviewDTO}.
*/
@Operation(summary = "Get seller reviews", description = "Retrieves all reviews associated with a seller.")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Seller reputation retrieved successfully") })
@ApiResponses(
value = { @ApiResponse(responseCode = "200", description = "Seller reputation retrieved successfully") })
@GetMapping("/seller/{sellerId}/reputation")
public SellerReputationDTO getSellerReputation(@PathVariable Long sellerId) {
LOGGER.info("Received request to get reputation for seller {}", sellerId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@
* @param name user name
* @param surname user surname
*/
public record OrderDetailedReviewDTO(Long id, Long sellerId, Integer rating, String comment, String name, String surname, List<OrderItemReviewDTO> itemReviews) {
public record OrderDetailedReviewDTO(Long id, Long sellerId, Integer rating, String comment, String name,
String surname, List<OrderItemReviewDTO> itemReviews) {

/**
* Converts an OrderReview entity into its detailed DTO representation.
* @return {@link OrderReview} containing the review data.
*/
public static OrderDetailedReviewDTO fromOrderReview(OrderReview orderReview, List<OrderItemReviewDTO> itemReviews, UserProfileResponseDTO userProfile) {
return new OrderDetailedReviewDTO(orderReview.getId(), orderReview.getSellerId(), orderReview.getRating(),
orderReview.getComment(), userProfile.name(), userProfile.surname(), itemReviews);
}
/**
* Converts an OrderReview entity into its detailed DTO representation.
* @return {@link OrderReview} containing the review data.
*/
public static OrderDetailedReviewDTO fromOrderReview(OrderReview orderReview, List<OrderItemReviewDTO> itemReviews,
UserProfileResponseDTO userProfile) {
return new OrderDetailedReviewDTO(orderReview.getId(), orderReview.getSellerId(), orderReview.getRating(),
orderReview.getComment(), userProfile.name(), userProfile.surname(), itemReviews);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
* @param name user name
* @param surname user surname
*/
public record OrderItemReviewDTO(Long id, Long orderItemId, Long orderId, Long userId, Integer rating, String comment, String name, String surname) {
public record OrderItemReviewDTO(Long id, Long orderItemId, Long orderId, Long userId, Integer rating, String comment,
String name, String surname) {

/**
* Converts an OrderItemReview entity into its DTO representation.
* @return {@link OrderItemReviewDTO} containing the review data.
*/
public static OrderItemReviewDTO fromOrderItemReview(OrderItemReview orderItemReview, UserProfileResponseDTO userProfile) {
public static OrderItemReviewDTO fromOrderItemReview(OrderItemReview orderItemReview,
UserProfileResponseDTO userProfile) {
return new OrderItemReviewDTO(orderItemReview.getId(), orderItemReview.getOrderItemId(),
orderItemReview.getOrderId(), orderItemReview.getUserId(), orderItemReview.getRating(),
orderItemReview.getComment(), userProfile.name(), userProfile.surname());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
* @param name user name
* @param surname user surname
*/
public record OrderReviewDTO(Long id, Long sellerId, Integer rating, String comment, String name, String surname, LocalDateTime createdAt) {
public record OrderReviewDTO(Long id, Long sellerId, Integer rating, String comment, String name, String surname,
LocalDateTime createdAt) {

/**
* Converts an OrderReview entity into its DTO representation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@
* @param averageRating the average rating received by the seller.
* @param totalReviews the total number of reviews received by the seller.
*/
public record SellerReputationDTO(
Long sellerId,
Double averageRating,
Long totalReviews
) {
public record SellerReputationDTO(Long sellerId, Double averageRating, Long totalReviews) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
* @param description User's current description.
* @param createdAt User's created account date.
*/
public record UserProfileResponseDTO(
String name, String surname, String imageURL, String description,
LocalDateTime createdAt
) {
public record UserProfileResponseDTO(String name, String surname, String imageURL, String description,
LocalDateTime createdAt) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ public interface OrderItemReviewRepository extends JpaRepository<OrderItemReview
*/
List<OrderItemReview> findAllByOrderId(Long orderId);

/**
* Deletes all order item reviews associated with the given order item IDs.
* @param orderItemIds The list of order item IDs whose reviews should be deleted.
*/
void deleteByOrderItemIdIn(List<Long> orderItemIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,20 @@ public interface OrderReviewRepository extends JpaRepository<OrderReview, Long>
* @return an {@link SellerReputationDTO}
*/
@Query("""
SELECT new com.bazaar.orders.dto.reviews.SellerReputationDTO(
:sellerId,
COALESCE(AVG(r.rating), 0),
COUNT(r)
)
FROM OrderReview r
WHERE r.sellerId = :sellerId
""")
SELECT new com.bazaar.orders.dto.reviews.SellerReputationDTO(
:sellerId,
COALESCE(AVG(r.rating), 0),
COUNT(r)
)
FROM OrderReview r
WHERE r.sellerId = :sellerId
""")
SellerReputationDTO getSellerReputation(@Param("sellerId") Long sellerId);

/**
* Deletes all order reviews associated with the given order IDs.
* @param orderIds The list of order IDs whose reviews should be deleted.
*/
void deleteByOrderIdIn(List<Long> orderIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ public interface OrderStatusHistoryRepository extends JpaRepository<OrderStatusH
*/
List<OrderStatusHistory> findByOrderIdOrderByChangedAtAsc(Long orderId);

/**
* Deletes all status history entries associated with the given order IDs.
* @param orderIds The list of order IDs whose history entries should be deleted.
*/
void deleteByOrderIdIn(List<Long> orderIds);

}
13 changes: 13 additions & 0 deletions src/main/java/com/bazaar/orders/service/CleanupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import com.bazaar.orders.model.OrderItem;
import com.bazaar.orders.model.OrderPayment;
import com.bazaar.orders.repository.OrderItemRepository;
import com.bazaar.orders.repository.OrderItemReviewRepository;
import com.bazaar.orders.repository.OrderPaymentRepository;
import com.bazaar.orders.repository.OrderRepository;
import com.bazaar.orders.repository.OrderReviewRepository;
import com.bazaar.orders.repository.OrderStatusHistoryRepository;

import lombok.RequiredArgsConstructor;

Expand All @@ -35,6 +38,12 @@ public class CleanupService {

private final OrderItemRepository orderItemRepository;

private final OrderItemReviewRepository orderItemReviewRepository;

private final OrderReviewRepository orderReviewRepository;

private final OrderStatusHistoryRepository orderStatusHistoryRepository;

/**
* Performs an atomic cleanup of a single abandoned payment.
* <p>
Expand All @@ -60,13 +69,17 @@ public void orderPaymentCleanup(OrderPayment payment) {
List<Order> orders = orderRepository.findByOrderPaymentId(payment.getId());
List<Long> orderIds = orders.stream().map(Order::getId).toList();
List<OrderItem> orderItems = orderItemRepository.findByOrderIdIn(orderIds);
List<Long> orderItemIds = orderItems.stream().map(OrderItem::getId).toList();

List<UpdateProductStockRequestDTO> stockRequests = orderItems.stream()
.map(UpdateProductStockRequestDTO::fromOrderItem)
.toList();

rabbitMQProducer.send(new UpdateProductsStockRequestDTO(stockRequests), RabbitMQConfig.ROUTING_KEY_RESTORE);

orderItemReviewRepository.deleteByOrderItemIdIn(orderItemIds);
orderReviewRepository.deleteByOrderIdIn(orderIds);
orderStatusHistoryRepository.deleteByOrderIdIn(orderIds);
orderItemRepository.deleteAll(orderItems);
orderRepository.deleteAll(orders);
orderPaymentRepository.delete(payment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.bazaar.orders.model.Order;
import com.bazaar.orders.model.OrderItem;
import com.bazaar.orders.model.OrderPayment;

import com.mercadopago.client.payment.PaymentClient;
import com.mercadopago.client.preference.PreferenceBackUrlsRequest;
import com.mercadopago.client.preference.PreferenceClient;
Expand Down
Loading
Loading