diff --git a/src/main/resources/P101.jpg b/src/main/resources/P101.jpg new file mode 100644 index 0000000..51416f4 Binary files /dev/null and b/src/main/resources/P101.jpg differ diff --git a/src/test/java/com/testcontainers/catalog/ApplicationTest.java b/src/test/java/com/testcontainers/catalog/ApplicationTest.java new file mode 100644 index 0000000..0fff780 --- /dev/null +++ b/src/test/java/com/testcontainers/catalog/ApplicationTest.java @@ -0,0 +1,10 @@ +package com.testcontainers.catalog; + +import org.junit.jupiter.api.Test; + +class ApplicationTest extends BaseIntegrationTest { + @Test + void contextLoads() { + + } +} \ No newline at end of file diff --git a/src/test/java/com/testcontainers/catalog/BaseIntegrationTest.java b/src/test/java/com/testcontainers/catalog/BaseIntegrationTest.java new file mode 100644 index 0000000..8944d4b --- /dev/null +++ b/src/test/java/com/testcontainers/catalog/BaseIntegrationTest.java @@ -0,0 +1,31 @@ +package com.testcontainers.catalog; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +import io.restassured.RestAssured; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.utility.DockerImageName; + +@SpringBootTest( + webEnvironment = RANDOM_PORT, + properties = { + "spring.kafka.consumer.auto-offset-reset=earliest" + }) +@Import(ContainersConfig.class) +public abstract class BaseIntegrationTest { + + @LocalServerPort + private int port; + + @BeforeEach + void setUpBase() { + RestAssured.port = port; + } +} \ No newline at end of file diff --git a/src/test/java/com/testcontainers/catalog/ContainersConfig.java b/src/test/java/com/testcontainers/catalog/ContainersConfig.java new file mode 100644 index 0000000..c0e2570 --- /dev/null +++ b/src/test/java/com/testcontainers/catalog/ContainersConfig.java @@ -0,0 +1,48 @@ +package com.testcontainers.catalog; + +import static org.testcontainers.utility.DockerImageName.parse; + +import com.testcontainers.catalog.domain.FileStorageService; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.DependsOn; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.containers.localstack.LocalStackContainer; +import org.testcontainers.elasticsearch.ElasticsearchContainer; + +@TestConfiguration(proxyBeanMethods = false) +public class ContainersConfig { + + @Bean + @ServiceConnection + PostgreSQLContainer postgresContainer() { + return new PostgreSQLContainer<>(parse("postgres:16-alpine")); + } + + @Bean + @ServiceConnection + KafkaContainer kafkaContainer() { + return new KafkaContainer(parse("confluentinc/cp-kafka:7.5.0")).withReuse(true); + } + + @Bean("localstackContainer") + LocalStackContainer localstackContainer(DynamicPropertyRegistry registry) { + LocalStackContainer localStack = new LocalStackContainer(parse("localstack/localstack:2.3")).withReuse(true); + registry.add("spring.cloud.aws.credentials.access-key", localStack::getAccessKey); + registry.add("spring.cloud.aws.credentials.secret-key", localStack::getSecretKey); + registry.add("spring.cloud.aws.region.static", localStack::getRegion); + registry.add("spring.cloud.aws.endpoint", localStack::getEndpoint); + return localStack; + } + + @Bean + @DependsOn("localstackContainer") + ApplicationRunner awsInitializer(ApplicationProperties properties, FileStorageService fileStorageService) { + return args -> fileStorageService.createBucket(properties.productImagesBucketName()); + } +} diff --git a/src/test/java/com/testcontainers/catalog/ProductControllerTest.java b/src/test/java/com/testcontainers/catalog/ProductControllerTest.java new file mode 100644 index 0000000..dfafacd --- /dev/null +++ b/src/test/java/com/testcontainers/catalog/ProductControllerTest.java @@ -0,0 +1,36 @@ +package com.testcontainers.catalog; + +import com.testcontainers.catalog.BaseIntegrationTest; +import com.testcontainers.catalog.domain.ProductService; +import com.testcontainers.catalog.domain.models.Product; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Test; +import java.util.UUID; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.endsWith; + +class ProductControllerTest extends BaseIntegrationTest { + + @Test + void createProductSuccessfully() { + String code = UUID.randomUUID().toString(); + given().contentType(ContentType.JSON) + .body( + """ + { + "code": "%s", + "name": "Product %s", + "description": "Product %s description", + "price": 10.0 + } + """ + .formatted(code, code, code)) + .when() + .post("/api/products") + .then() + .statusCode(201) + .header("Location", endsWith("/api/products/%s".formatted(code))); + } + +} \ No newline at end of file diff --git a/src/test/java/com/testcontainers/catalog/TestApplication.java b/src/test/java/com/testcontainers/catalog/TestApplication.java new file mode 100644 index 0000000..38f1320 --- /dev/null +++ b/src/test/java/com/testcontainers/catalog/TestApplication.java @@ -0,0 +1,10 @@ +package com.testcontainers.catalog; + +import org.springframework.boot.SpringApplication; + +public class TestApplication { + + public static void main(String[] args) { + SpringApplication.from(Application::main).with(ContainersConfig.class).run(args); + } +}