├── .github
└── workflows
│ ├── linux-build-exercises-gradle.yml
│ └── linux-build-exercises-maven.yml
├── .gitignore
├── README.md
├── exercises
├── 01-redis-generic-container
│ ├── instructions.md
│ ├── solution
│ │ ├── .mvn
│ │ │ └── wrapper
│ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ ├── maven-wrapper.jar
│ │ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ └── RedisRepository.java
│ │ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── RedisRepositoryIntegrationTest.java
│ └── start
│ │ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── RedisRepository.java
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── bmuschko
│ │ └── testcontainers
│ │ └── RedisRepositoryIntegrationTest.java
├── 02-postgesql-database-container
│ ├── instructions.md
│ ├── solution
│ │ ├── .mvn
│ │ │ └── wrapper
│ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ ├── maven-wrapper.jar
│ │ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ ├── Item.java
│ │ │ │ ├── WarehouseException.java
│ │ │ │ ├── WarehouseRepository.java
│ │ │ │ └── WarehouseRepositoryImpl.java
│ │ │ └── test
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ └── WarehouseRepositoryIntegrationTest.java
│ │ │ └── resources
│ │ │ └── warehouse.sql
│ └── start
│ │ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ ├── Item.java
│ │ │ ├── WarehouseException.java
│ │ │ ├── WarehouseRepository.java
│ │ │ └── WarehouseRepositoryImpl.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── WarehouseRepositoryIntegrationTest.java
│ │ └── resources
│ │ └── warehouse.sql
├── 03-multi-container
│ ├── instructions.md
│ ├── solution
│ │ ├── docker-compose
│ │ │ ├── .mvn
│ │ │ │ └── wrapper
│ │ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ │ ├── maven-wrapper.jar
│ │ │ │ │ └── maven-wrapper.properties
│ │ │ ├── build.gradle
│ │ │ ├── gradle
│ │ │ │ └── wrapper
│ │ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── mvnw
│ │ │ ├── mvnw.cmd
│ │ │ ├── pom.xml
│ │ │ ├── settings.gradle
│ │ │ └── src
│ │ │ │ ├── main
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── bmuschko
│ │ │ │ │ └── testcontainers
│ │ │ │ │ ├── model
│ │ │ │ │ └── warehouse
│ │ │ │ │ │ └── Product.java
│ │ │ │ │ ├── repository
│ │ │ │ │ └── warehouse
│ │ │ │ │ │ ├── db
│ │ │ │ │ │ ├── UsernamePasswordCredentials.java
│ │ │ │ │ │ ├── WarehouseDatabaseException.java
│ │ │ │ │ │ ├── WarehouseDatabaseRepository.java
│ │ │ │ │ │ └── WarehouseDatabaseRepositoryImpl.java
│ │ │ │ │ │ └── index
│ │ │ │ │ │ ├── ProductIndexException.java
│ │ │ │ │ │ ├── ProductIndexRepository.java
│ │ │ │ │ │ └── ProductIndexRepositoryImpl.java
│ │ │ │ │ └── service
│ │ │ │ │ ├── WarehouseService.java
│ │ │ │ │ └── WarehouseServiceImpl.java
│ │ │ │ └── test
│ │ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── bmuschko
│ │ │ │ │ └── testcontainers
│ │ │ │ │ └── service
│ │ │ │ │ └── WarehouseServiceImplIntegrationTest.java
│ │ │ │ └── resources
│ │ │ │ ├── warehouse-test.yml
│ │ │ │ └── warehouse.sql
│ │ └── multi-container
│ │ │ ├── .mvn
│ │ │ └── wrapper
│ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ ├── maven-wrapper.jar
│ │ │ │ └── maven-wrapper.properties
│ │ │ ├── build.gradle
│ │ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── mvnw
│ │ │ ├── mvnw.cmd
│ │ │ ├── pom.xml
│ │ │ ├── settings.gradle
│ │ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ ├── model
│ │ │ │ └── warehouse
│ │ │ │ │ └── Product.java
│ │ │ │ ├── repository
│ │ │ │ └── warehouse
│ │ │ │ │ ├── db
│ │ │ │ │ ├── UsernamePasswordCredentials.java
│ │ │ │ │ ├── WarehouseDatabaseException.java
│ │ │ │ │ ├── WarehouseDatabaseRepository.java
│ │ │ │ │ └── WarehouseDatabaseRepositoryImpl.java
│ │ │ │ │ └── index
│ │ │ │ │ ├── ProductIndexException.java
│ │ │ │ │ ├── ProductIndexRepository.java
│ │ │ │ │ └── ProductIndexRepositoryImpl.java
│ │ │ │ └── service
│ │ │ │ ├── WarehouseService.java
│ │ │ │ └── WarehouseServiceImpl.java
│ │ │ └── test
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ └── service
│ │ │ │ └── WarehouseServiceImplIntegrationTest.java
│ │ │ └── resources
│ │ │ └── warehouse.sql
│ └── start
│ │ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ ├── model
│ │ │ └── warehouse
│ │ │ │ └── Product.java
│ │ │ ├── repository
│ │ │ └── warehouse
│ │ │ │ ├── db
│ │ │ │ ├── UsernamePasswordCredentials.java
│ │ │ │ ├── WarehouseDatabaseException.java
│ │ │ │ ├── WarehouseDatabaseRepository.java
│ │ │ │ └── WarehouseDatabaseRepositoryImpl.java
│ │ │ │ └── index
│ │ │ │ ├── ProductIndexException.java
│ │ │ │ ├── ProductIndexRepository.java
│ │ │ │ └── ProductIndexRepositoryImpl.java
│ │ │ └── service
│ │ │ ├── WarehouseService.java
│ │ │ └── WarehouseServiceImpl.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── service
│ │ │ └── WarehouseServiceImplIntegrationTest.java
│ │ └── resources
│ │ ├── warehouse-test.yml
│ │ └── warehouse.sql
├── 04-generic-container
│ ├── instructions.md
│ ├── solution
│ │ ├── dockerfile
│ │ │ ├── .mvn
│ │ │ │ └── wrapper
│ │ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ │ ├── maven-wrapper.jar
│ │ │ │ │ └── maven-wrapper.properties
│ │ │ ├── build.gradle
│ │ │ ├── gradle
│ │ │ │ └── wrapper
│ │ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── mvnw
│ │ │ ├── mvnw.cmd
│ │ │ ├── pom.xml
│ │ │ ├── settings.gradle
│ │ │ └── src
│ │ │ │ ├── main
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── bmuschko
│ │ │ │ │ └── testcontainers
│ │ │ │ │ ├── NginxService.java
│ │ │ │ │ └── NginxServiceImpl.java
│ │ │ │ └── test
│ │ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── bmuschko
│ │ │ │ │ └── testcontainers
│ │ │ │ │ └── NginxServiceIntegrationTest.java
│ │ │ │ └── resources
│ │ │ │ └── Dockerfile
│ │ ├── instructions
│ │ │ ├── .mvn
│ │ │ │ └── wrapper
│ │ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ │ ├── maven-wrapper.jar
│ │ │ │ │ └── maven-wrapper.properties
│ │ │ ├── build.gradle
│ │ │ ├── gradle
│ │ │ │ └── wrapper
│ │ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── mvnw
│ │ │ ├── mvnw.cmd
│ │ │ ├── pom.xml
│ │ │ ├── settings.gradle
│ │ │ └── src
│ │ │ │ ├── main
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── bmuschko
│ │ │ │ │ └── testcontainers
│ │ │ │ │ ├── NginxService.java
│ │ │ │ │ └── NginxServiceImpl.java
│ │ │ │ └── test
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ └── NginxServiceIntegrationTest.java
│ │ └── prebuilt
│ │ │ ├── .mvn
│ │ │ └── wrapper
│ │ │ │ ├── MavenWrapperDownloader.java
│ │ │ │ ├── maven-wrapper.jar
│ │ │ │ └── maven-wrapper.properties
│ │ │ ├── build.gradle
│ │ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ │ ├── gradlew
│ │ │ ├── gradlew.bat
│ │ │ ├── mvnw
│ │ │ ├── mvnw.cmd
│ │ │ ├── pom.xml
│ │ │ ├── settings.gradle
│ │ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── bmuschko
│ │ │ │ └── testcontainers
│ │ │ │ ├── NginxService.java
│ │ │ │ └── NginxServiceImpl.java
│ │ │ └── test
│ │ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── NginxServiceIntegrationTest.java
│ └── start
│ │ ├── .mvn
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ │ ├── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── settings.gradle
│ │ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ ├── NginxService.java
│ │ │ └── NginxServiceImpl.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── bmuschko
│ │ │ └── testcontainers
│ │ │ └── NginxServiceIntegrationTest.java
│ │ └── resources
│ │ └── Dockerfile
└── 05-ci-github-actions
│ ├── instructions.md
│ └── solution
│ ├── images
│ ├── github-actions-execution.png
│ └── github-repository-creation.png
│ └── solution.md
├── prerequisites
└── instructions.md
└── slides.pdf
/.github/workflows/linux-build-exercises-gradle.yml:
--------------------------------------------------------------------------------
1 | name: Build Exercises with Gradle [Linux]
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build:
6 | name: Build with Gradle
7 | runs-on: ubuntu-22.04
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v1
11 | - name: Set up Java
12 | uses: actions/setup-java@v1
13 | with:
14 | java-version: 11
15 | - name: Exercise 1 - Redis Generic Container
16 | uses: gradle/gradle-build-action@v2
17 | with:
18 | arguments: build
19 | build-root-directory: exercises/01-redis-generic-container/solution
20 | - name: Exercise 2 - PostgreSQL Database Container
21 | uses: gradle/gradle-build-action@v2
22 | with:
23 | arguments: build
24 | build-root-directory: exercises/02-postgesql-database-container/solution
25 | - name: Exercise 3 - Multi-Container
26 | uses: gradle/gradle-build-action@v2
27 | with:
28 | arguments: build
29 | build-root-directory: exercises/03-multi-container/solution/multi-container
30 | - name: Exercise 3 - Docker Compose
31 | uses: gradle/gradle-build-action@v2
32 | with:
33 | arguments: build
34 | build-root-directory: exercises/03-multi-container/solution/docker-compose
35 | - name: Exercise 4 - Generic Prebuilt Container
36 | uses: gradle/gradle-build-action@v2
37 | with:
38 | arguments: build
39 | build-root-directory: exercises/04-generic-container/solution/prebuilt
40 | - name: Exercise 4 - Generic Container Built By Dockerfile
41 | uses: gradle/gradle-build-action@v2
42 | with:
43 | arguments: build
44 | build-root-directory: exercises/04-generic-container/solution/dockerfile
45 | - name: Exercise 4 - Generic Container Built By Individual Instructions
46 | uses: gradle/gradle-build-action@v2
47 | with:
48 | arguments: build
49 | build-root-directory: exercises/04-generic-container/solution/instructions
--------------------------------------------------------------------------------
/.github/workflows/linux-build-exercises-maven.yml:
--------------------------------------------------------------------------------
1 | name: Build Exercises with Maven [Linux]
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build:
6 | name: Build with Maven
7 | runs-on: ubuntu-22.04
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v1
11 | - name: Set up Java
12 | uses: actions/setup-java@v1
13 | with:
14 | java-version: 11
15 | - name: Exercise 1 - Redis Generic Container
16 | run: cd exercises/01-redis-generic-container/solution;./mvnw test
17 | - name: Exercise 2 - PostgreSQL Database Container
18 | run: cd exercises/02-postgesql-database-container/solution;./mvnw test
19 | - name: Exercise 3 - Multi-Container
20 | run: cd exercises/03-multi-container/solution/multi-container;./mvnw test
21 | - name: Exercise 3 - Docker Compose
22 | run: cd exercises/03-multi-container/solution/docker-compose;./mvnw test
23 | - name: Exercise 4 - Generic Prebuilt Container
24 | run: cd exercises/04-generic-container/solution/prebuilt;./mvnw test
25 | - name: Exercise 4 - Generic Container Built By Dockerfile
26 | run: cd exercises/04-generic-container/solution/dockerfile;./mvnw test
27 | - name: Exercise 4 - Generic Container Built By Individual Instructions
28 | run: cd exercises/04-generic-container/solution/instructions;./mvnw test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | out
4 | build
5 | target
6 | .gradle
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Integration Testing with Docker and Testcontainers
2 |
3 | The process of developing an application typically involves the work of multiple engineers, and that work is usually broken down into several modules. There is always a risk that modules developed by different engineers will not sync when integrating with each other for use in production. Integration testing helps minimize this risk by enabling better integration of modules. But many organizations struggle with maintaining tests that require more complex setup procedures. As a result, integration tests become flaky and unreliable and require manual intervention. In an automate-all-the-things world, this costs organizations time and money.
4 |
5 | Join expert Benjamin Muschko to discover how to set up and run integration and functional tests with the help of the open source library Testcontainers. You will learn how to stand up lightweight, disposable Docker instances running your application as reliable test fixtures.
6 |
7 | ## Prerequisites
8 |
9 | Please make sure to follow the [instructions](./prerequisites/instructions.md) for setting up your environment before joining the training.
10 |
11 | ## Exercises
12 |
13 | All [exercises](./exercises) are numbered and live in dedicated directories starting with the name `exercise-`. You'll find instructions for each exercise in each folder. Solutions are available in the `solution` folder. Try to solve each exercise yourself before having a look at the solution.
14 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/instructions.md:
--------------------------------------------------------------------------------
1 | # Exercise 1
2 |
3 | In this exercise, you will learn how to use Testcontainers to run a Redis database as test fixture managed by a JUnit 5 test class. You can find the initial code in the `start` directory. The production source class under test is named `RedisRepository.java` under the directory `src/main/java`. The test class `RedisRepositoryIntegrationTest.java` under the directory `src/test/java` already implements a test case.
4 |
5 | > **_NOTE:_** You can choose to run the build using Maven or Gradle. Pick the tool you are most comfortable with.
6 |
7 | 1. Add the JUnit Jupiter and Testcontainers dependencies. Use the version 5.8.1 for JUnit, use version 1.17.3 for Testcontainers.
8 | 2. To ensure that Testcontainers can log its messages to the console, add a SLF4J implementation as dependency.
9 | 3. In the test class, create a new container instance of type `org.testcontainers.containers.GenericContainer`. Declare the image `redis:6.2.6-alpine` and the exposed port `6379` for the container. The container should be created and destroyed for every test method.
10 | 4. Instantiate a class of `com.bmuschko.testcontainers.RedisRepository` and assign it to the variable named `redisRepository`. Determine the runtime value for the host and port of the container and provide it in the constructor of the class.
11 | 5. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
12 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/01-redis-generic-container/solution/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | implementation 'redis.clients:jedis:3.7.0'
15 |
16 | def junitJupiterVersion = '5.8.1'
17 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
18 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
19 |
20 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
21 | testImplementation 'org.testcontainers:junit-jupiter'
22 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
23 | }
24 |
25 | test {
26 | useJUnitPlatform()
27 | testLogging {
28 | showStandardStreams = true
29 | }
30 | }
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/01-redis-generic-container/solution/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | redis-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 3.7.0
15 | 5.8.1
16 |
17 |
18 |
19 |
20 | redis.clients
21 | jedis
22 | ${jedis.version}
23 |
24 |
25 | org.junit.jupiter
26 | junit-jupiter-api
27 | ${junit.jupiter.version}
28 | test
29 |
30 |
31 | org.junit.jupiter
32 | junit-jupiter-engine
33 | ${junit.jupiter.version}
34 | test
35 |
36 |
37 | org.testcontainers
38 | junit-jupiter
39 | test
40 |
41 |
42 | org.slf4j
43 | slf4j-simple
44 | 1.7.32
45 | test
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.testcontainers
53 | testcontainers-bom
54 | 1.17.3
55 | pom
56 | import
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.apache.maven.plugins
66 | maven-compiler-plugin
67 | 3.8.1
68 |
69 | ${jdk.version}
70 | ${jdk.version}
71 | ${project.build.sourceEncoding}
72 |
73 |
74 |
75 | maven-surefire-plugin
76 | 2.22.2
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'redis-generic-container'
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/src/main/java/com/bmuschko/testcontainers/RedisRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import redis.clients.jedis.Jedis;
4 |
5 | public class RedisRepository {
6 | private final Jedis jedis;
7 |
8 | public RedisRepository(String host, Integer port) {
9 | this.jedis = new Jedis(host, port);
10 | }
11 |
12 | public void put(String key, String value) {
13 | jedis.set(key, value);
14 | }
15 |
16 | public String get(String key) {
17 | return jedis.get(key);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/solution/src/test/java/com/bmuschko/testcontainers/RedisRepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.GenericContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 | import org.testcontainers.junit.jupiter.Testcontainers;
8 | import org.testcontainers.utility.DockerImageName;
9 |
10 | import static org.junit.jupiter.api.Assertions.assertEquals;
11 |
12 | @Testcontainers
13 | public class RedisRepositoryIntegrationTest {
14 | private RedisRepository redisRepository;
15 |
16 | @Container
17 | private final GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:6.2.6-alpine")).withExposedPorts(6379);
18 |
19 | @BeforeEach
20 | public void setUp() {
21 | String host = redis.getHost();
22 | Integer port = redis.getFirstMappedPort();
23 | redisRepository = new RedisRepository(host, port);
24 | }
25 |
26 | @Test
27 | public void testSimplePutAndGet() {
28 | String key = "test";
29 | String value = "example";
30 |
31 | redisRepository.put(key, value);
32 |
33 | String retrieved = redisRepository.get(key);
34 | assertEquals(value, retrieved);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/01-redis-generic-container/start/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | implementation 'redis.clients:jedis:3.7.0'
15 | }
16 |
17 | test {
18 | useJUnitPlatform()
19 | testLogging {
20 | showStandardStreams = true
21 | }
22 | }
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/01-redis-generic-container/start/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | redis-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 |
15 |
16 |
17 |
18 | redis.clients
19 | jedis
20 | ${jedis.version}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | org.apache.maven.plugins
29 | maven-compiler-plugin
30 | 3.8.1
31 |
32 | ${jdk.version}
33 | ${jdk.version}
34 | ${project.build.sourceEncoding}
35 |
36 |
37 |
38 | maven-surefire-plugin
39 | 2.22.2
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'redis-generic-container'
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/src/main/java/com/bmuschko/testcontainers/RedisRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import redis.clients.jedis.Jedis;
4 |
5 | public class RedisRepository {
6 | private final Jedis jedis;
7 |
8 | public RedisRepository(String host, Integer port) {
9 | this.jedis = new Jedis(host, port);
10 | }
11 |
12 | public void put(String key, String value) {
13 | jedis.set(key, value);
14 | }
15 |
16 | public String get(String key) {
17 | return jedis.get(key);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/exercises/01-redis-generic-container/start/src/test/java/com/bmuschko/testcontainers/RedisRepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertEquals;
6 |
7 | @Testcontainers
8 | public class RedisRepositoryIntegrationTest {
9 | private RedisRepository redisRepository;
10 |
11 | @Test
12 | public void testSimplePutAndGet() {
13 | String key = "test";
14 | String value = "example";
15 |
16 | redisRepository.put(key, value);
17 |
18 | String retrieved = redisRepository.get(key);
19 | assertEquals(value, retrieved);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/instructions.md:
--------------------------------------------------------------------------------
1 | # Exercise 2
2 |
3 | In this exercise, you will learn how to use Testcontainers to bring up a PostgreSQL database with seed data. You can find the initial code in the `start` directory. The production source class under test is named `WarehouseRepository.java` under the directory `src/main/java`. The test class `WarehouseRepositoryIntegrationTest.java` under the directory `src/test/java` already implements a test case.
4 |
5 | > **_NOTE:_** You can choose to run the build using Maven or Gradle. Pick the tool you are most comfortable with.
6 |
7 | 1. Add the Testcontainers dependency that supports creating a PostgreSQL container. Add the dependency for the PostgreSQL JDBC driver with version `42.5.0`.
8 | 2. In the test class, create an instance of `org.testcontainers.containers.PostgreSQLContainer`. Assign the image `postgres:9.6.12` and the database name `warehouse`. Upon creation, the container instance should run the script `warehouse.sql` to create the database schema.
9 | 3. Create an instance of `WarehouseRepositoryImpl` and inject the JDBC URL, username, and password into the constructor before every test method.
10 | 4. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
11 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/02-postgesql-database-container/solution/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | runtimeOnly 'org.postgresql:postgresql:42.5.0'
15 |
16 | def junitJupiterVersion = '5.8.1'
17 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
18 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
19 |
20 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
21 | testImplementation 'org.testcontainers:junit-jupiter'
22 | testImplementation 'org.testcontainers:postgresql'
23 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
24 | }
25 |
26 | test {
27 | useJUnitPlatform()
28 | testLogging {
29 | showStandardStreams = true
30 | }
31 | }
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/02-postgesql-database-container/solution/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | postgresql-database-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 42.5.0
15 | 5.8.1
16 |
17 |
18 |
19 |
20 | org.postgresql
21 | postgresql
22 | ${postgresql.version}
23 | runtime
24 |
25 |
26 | org.junit.jupiter
27 | junit-jupiter-api
28 | ${junit.jupiter.version}
29 | test
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter-engine
34 | ${junit.jupiter.version}
35 | test
36 |
37 |
38 | org.testcontainers
39 | junit-jupiter
40 | test
41 |
42 |
43 | org.testcontainers
44 | postgresql
45 | test
46 |
47 |
48 | org.slf4j
49 | slf4j-simple
50 | 1.7.32
51 | test
52 |
53 |
54 |
55 |
56 |
57 |
58 | org.testcontainers
59 | testcontainers-bom
60 | 1.17.3
61 | pom
62 | import
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.apache.maven.plugins
72 | maven-compiler-plugin
73 | 3.8.1
74 |
75 | ${jdk.version}
76 | ${jdk.version}
77 | ${project.build.sourceEncoding}
78 |
79 |
80 |
81 | maven-surefire-plugin
82 | 2.22.2
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'postgresql-database-container'
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/main/java/com/bmuschko/testcontainers/Item.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Item {
6 | private Long id;
7 | private String name;
8 | private BigDecimal price;
9 |
10 | public Long getId() {
11 | return id;
12 | }
13 |
14 | public void setId(Long id) {
15 | this.id = id;
16 | }
17 |
18 | public String getName() {
19 | return name;
20 | }
21 |
22 | public void setName(String name) {
23 | this.name = name;
24 | }
25 |
26 | public BigDecimal getPrice() {
27 | return price;
28 | }
29 |
30 | public void setPrice(BigDecimal price) {
31 | this.price = price;
32 | }
33 |
34 | @Override
35 | public boolean equals(Object o) {
36 | if (this == o) {
37 | return true;
38 | }
39 | if (!(o instanceof Item)) {
40 | return false;
41 | }
42 |
43 | Item item = (Item) o;
44 |
45 | if (id != null ? !id.equals(item.id) : item.id != null) {
46 | return false;
47 | }
48 | if (name != null ? !name.equals(item.name) : item.name != null) {
49 | return false;
50 | }
51 | return price != null ? price.equals(item.price) : item.price == null;
52 | }
53 |
54 | @Override
55 | public int hashCode() {
56 | int result = id != null ? id.hashCode() : 0;
57 | result = 31 * result + (name != null ? name.hashCode() : 0);
58 | result = 31 * result + (price != null ? price.hashCode() : 0);
59 | return result;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/main/java/com/bmuschko/testcontainers/WarehouseException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public class WarehouseException extends RuntimeException {
4 | public WarehouseException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/main/java/com/bmuschko/testcontainers/WarehouseRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface WarehouseRepository {
4 | void insertItem(Item item);
5 | Item getItem(Long id);
6 | }
7 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/main/java/com/bmuschko/testcontainers/WarehouseRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.sql.Connection;
4 | import java.sql.DriverManager;
5 | import java.sql.PreparedStatement;
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.sql.Statement;
9 | import java.util.Properties;
10 |
11 | public class WarehouseRepositoryImpl implements WarehouseRepository {
12 | private final String jdbcUrl;
13 | private final String username;
14 | private final String password;
15 |
16 | public WarehouseRepositoryImpl(String jdbcUrl, String username, String password) {
17 | this.jdbcUrl = jdbcUrl;
18 | this.username = username;
19 | this.password = password;
20 | }
21 |
22 | @Override
23 | public void insertItem(Item item) {
24 | Connection connection = null;
25 | PreparedStatement pstmt = null;
26 | ResultSet rs = null;
27 |
28 | try {
29 | connection = createConnection();
30 | pstmt = connection.prepareStatement("INSERT INTO item (name, price) VALUES (?, ?) RETURNING ID");
31 | pstmt.setString(1, item.getName());
32 | pstmt.setBigDecimal(2, item.getPrice());
33 | rs = pstmt.executeQuery();
34 |
35 | while (rs.next()) {
36 | item.setId(rs.getLong(1));
37 | }
38 | } catch (SQLException e) {
39 | throw new WarehouseException("Unable to insert item", e);
40 | } finally {
41 | closeResultSet(rs);
42 | closeStatement(pstmt);
43 | closeConnection(connection);
44 | }
45 | }
46 |
47 | @Override
48 | public Item getItem(Long id) {
49 | Connection connection = null;
50 | PreparedStatement pstmt = null;
51 | ResultSet rs = null;
52 | Item item = null;
53 |
54 | try {
55 | connection = createConnection();
56 | pstmt = connection.prepareStatement("SELECT id, name, price FROM item WHERE id = ?");
57 | pstmt.setLong(1, id);
58 | rs = pstmt.executeQuery();
59 |
60 | while (rs.next()) {
61 | item = new Item();
62 | item.setId(rs.getLong(1));
63 | item.setName(rs.getString(2));
64 | item.setPrice(rs.getBigDecimal(3));
65 | }
66 |
67 | return item;
68 | } catch (SQLException e) {
69 | throw new WarehouseException("Unable to insert item", e);
70 | } finally {
71 | closeResultSet(rs);
72 | closeStatement(pstmt);
73 | closeConnection(connection);
74 | }
75 | }
76 |
77 | private Connection createConnection() {
78 | Properties props = new Properties();
79 | props.setProperty("user", username);
80 | props.setProperty("password", password);
81 |
82 | try {
83 | return DriverManager.getConnection(jdbcUrl, props);
84 | } catch (SQLException e) {
85 | throw new WarehouseException("Unable to establish connection to database", e);
86 | }
87 | }
88 |
89 | private void closeConnection(Connection connection) {
90 | try {
91 | if (connection != null && !connection.isClosed()) {
92 | connection.close();
93 | }
94 | } catch (SQLException e) {
95 | // ignore
96 | }
97 | }
98 |
99 | private void closeStatement(Statement statement) {
100 | try {
101 | if (statement != null && !statement.isClosed()) {
102 | statement.close();
103 | }
104 | } catch (SQLException e) {
105 | // ignore
106 | }
107 | }
108 |
109 | private void closeResultSet(ResultSet resultSet) {
110 | try {
111 | if (resultSet != null && !resultSet.isClosed()) {
112 | resultSet.close();
113 | }
114 | } catch (SQLException e) {
115 | // ignore
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/test/java/com/bmuschko/testcontainers/WarehouseRepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.JdbcDatabaseContainer;
6 | import org.testcontainers.containers.PostgreSQLContainer;
7 | import org.testcontainers.junit.jupiter.Container;
8 | import org.testcontainers.junit.jupiter.Testcontainers;
9 |
10 | import java.math.BigDecimal;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 | @Testcontainers
15 | public class WarehouseRepositoryIntegrationTest {
16 | private WarehouseRepository warehouseRepository;
17 |
18 | @Container
19 | private final JdbcDatabaseContainer postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.12")
20 | .withInitScript("warehouse.sql")
21 | .withDatabaseName("warehouse");
22 |
23 | @BeforeEach
24 | public void setUp() {
25 | String jdbcUrl = postgreSQLContainer.getJdbcUrl();
26 | String username = postgreSQLContainer.getUsername();
27 | String password = postgreSQLContainer.getPassword();
28 | warehouseRepository = new WarehouseRepositoryImpl(jdbcUrl, username, password);
29 | }
30 |
31 | @Test
32 | public void testInsertAndGetItem() {
33 | Item clock = new Item();
34 | clock.setName("Clock");
35 | clock.setPrice(new BigDecimal(39.99));
36 |
37 | warehouseRepository.insertItem(clock);
38 |
39 | Item retrieved = warehouseRepository.getItem(clock.getId());
40 | assertEquals(clock, retrieved);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/solution/src/test/resources/warehouse.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS ITEM;
2 |
3 | CREATE TABLE ITEM(
4 | ID SERIAL PRIMARY KEY,
5 | NAME TEXT NOT NULL,
6 | PRICE NUMERIC NOT NULL
7 | );
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/02-postgesql-database-container/start/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | def junitJupiterVersion = '5.8.1'
15 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
16 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
17 |
18 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
19 | testImplementation 'org.testcontainers:junit-jupiter'
20 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | testLogging {
26 | showStandardStreams = true
27 | }
28 | }
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/02-postgesql-database-container/start/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | postgresql-database-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 42.2.24
15 | 5.8.1
16 |
17 |
18 |
19 |
20 | org.junit.jupiter
21 | junit-jupiter-api
22 | ${junit.jupiter.version}
23 | test
24 |
25 |
26 | org.junit.jupiter
27 | junit-jupiter-engine
28 | ${junit.jupiter.version}
29 | test
30 |
31 |
32 | org.testcontainers
33 | junit-jupiter
34 | test
35 |
36 |
37 | org.slf4j
38 | slf4j-simple
39 | 1.7.32
40 | test
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.testcontainers
48 | testcontainers-bom
49 | 1.17.3
50 | pom
51 | import
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-compiler-plugin
62 | 3.8.1
63 |
64 | ${jdk.version}
65 | ${jdk.version}
66 | ${project.build.sourceEncoding}
67 |
68 |
69 |
70 | maven-surefire-plugin
71 | 2.22.2
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'postgresql-database-container'
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/main/java/com/bmuschko/testcontainers/Item.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Item {
6 | private Long id;
7 | private String name;
8 | private BigDecimal price;
9 |
10 | public Long getId() {
11 | return id;
12 | }
13 |
14 | public void setId(Long id) {
15 | this.id = id;
16 | }
17 |
18 | public String getName() {
19 | return name;
20 | }
21 |
22 | public void setName(String name) {
23 | this.name = name;
24 | }
25 |
26 | public BigDecimal getPrice() {
27 | return price;
28 | }
29 |
30 | public void setPrice(BigDecimal price) {
31 | this.price = price;
32 | }
33 |
34 | @Override
35 | public boolean equals(Object o) {
36 | if (this == o) {
37 | return true;
38 | }
39 | if (!(o instanceof Item)) {
40 | return false;
41 | }
42 |
43 | Item item = (Item) o;
44 |
45 | if (id != null ? !id.equals(item.id) : item.id != null) {
46 | return false;
47 | }
48 | if (name != null ? !name.equals(item.name) : item.name != null) {
49 | return false;
50 | }
51 | return price != null ? price.equals(item.price) : item.price == null;
52 | }
53 |
54 | @Override
55 | public int hashCode() {
56 | int result = id != null ? id.hashCode() : 0;
57 | result = 31 * result + (name != null ? name.hashCode() : 0);
58 | result = 31 * result + (price != null ? price.hashCode() : 0);
59 | return result;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/main/java/com/bmuschko/testcontainers/WarehouseException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public class WarehouseException extends RuntimeException {
4 | public WarehouseException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/main/java/com/bmuschko/testcontainers/WarehouseRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface WarehouseRepository {
4 | void insertItem(Item item);
5 | Item getItem(Long id);
6 | }
7 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/main/java/com/bmuschko/testcontainers/WarehouseRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.sql.Connection;
4 | import java.sql.DriverManager;
5 | import java.sql.PreparedStatement;
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.sql.Statement;
9 | import java.util.Properties;
10 |
11 | public class WarehouseRepositoryImpl implements WarehouseRepository {
12 | private final String jdbcUrl;
13 | private final String username;
14 | private final String password;
15 |
16 | public WarehouseRepositoryImpl(String jdbcUrl, String username, String password) {
17 | this.jdbcUrl = jdbcUrl;
18 | this.username = username;
19 | this.password = password;
20 | }
21 |
22 | @Override
23 | public void insertItem(Item item) {
24 | Connection connection = null;
25 | PreparedStatement pstmt = null;
26 | ResultSet rs = null;
27 |
28 | try {
29 | connection = createConnection();
30 | pstmt = connection.prepareStatement("INSERT INTO item (name, price) VALUES (?, ?) RETURNING ID");
31 | pstmt.setString(1, item.getName());
32 | pstmt.setBigDecimal(2, item.getPrice());
33 | rs = pstmt.executeQuery();
34 |
35 | while (rs.next()) {
36 | item.setId(rs.getLong(1));
37 | }
38 | } catch (SQLException e) {
39 | throw new WarehouseException("Unable to insert item", e);
40 | } finally {
41 | closeResultSet(rs);
42 | closeStatement(pstmt);
43 | closeConnection(connection);
44 | }
45 | }
46 |
47 | @Override
48 | public Item getItem(Long id) {
49 | Connection connection = null;
50 | PreparedStatement pstmt = null;
51 | ResultSet rs = null;
52 | Item item = null;
53 |
54 | try {
55 | connection = createConnection();
56 | pstmt = connection.prepareStatement("SELECT id, name, price FROM item WHERE id = ?");
57 | pstmt.setLong(1, id);
58 | rs = pstmt.executeQuery();
59 |
60 | while (rs.next()) {
61 | item = new Item();
62 | item.setId(rs.getLong(1));
63 | item.setName(rs.getString(2));
64 | item.setPrice(rs.getBigDecimal(3));
65 | }
66 |
67 | return item;
68 | } catch (SQLException e) {
69 | throw new WarehouseException("Unable to insert item", e);
70 | } finally {
71 | closeResultSet(rs);
72 | closeStatement(pstmt);
73 | closeConnection(connection);
74 | }
75 | }
76 |
77 | private Connection createConnection() {
78 | Properties props = new Properties();
79 | props.setProperty("user", username);
80 | props.setProperty("password", password);
81 |
82 | try {
83 | return DriverManager.getConnection(jdbcUrl, props);
84 | } catch (SQLException e) {
85 | throw new WarehouseException("Unable to establish connection to database", e);
86 | }
87 | }
88 |
89 | private void closeConnection(Connection connection) {
90 | try {
91 | if (connection != null && !connection.isClosed()) {
92 | connection.close();
93 | }
94 | } catch (SQLException e) {
95 | // ignore
96 | }
97 | }
98 |
99 | private void closeStatement(Statement statement) {
100 | try {
101 | if (statement != null && !statement.isClosed()) {
102 | statement.close();
103 | }
104 | } catch (SQLException e) {
105 | // ignore
106 | }
107 | }
108 |
109 | private void closeResultSet(ResultSet resultSet) {
110 | try {
111 | if (resultSet != null && !resultSet.isClosed()) {
112 | resultSet.close();
113 | }
114 | } catch (SQLException e) {
115 | // ignore
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/test/java/com/bmuschko/testcontainers/WarehouseRepositoryIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.math.BigDecimal;
7 |
8 | import static org.junit.jupiter.api.Assertions.assertEquals;
9 |
10 | public class WarehouseRepositoryIntegrationTest {
11 | private WarehouseRepository warehouseRepository;
12 |
13 | @Test
14 | public void testInsertAndGetItem() {
15 | Item clock = new Item();
16 | clock.setName("Clock");
17 | clock.setPrice(new BigDecimal(39.99));
18 |
19 | warehouseRepository.insertItem(clock);
20 |
21 | Item retrieved = warehouseRepository.getItem(clock.getId());
22 | assertEquals(clock, retrieved);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/exercises/02-postgesql-database-container/start/src/test/resources/warehouse.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS ITEM;
2 |
3 | CREATE TABLE ITEM(
4 | ID SERIAL PRIMARY KEY,
5 | NAME TEXT NOT NULL,
6 | PRICE NUMERIC NOT NULL
7 | );
--------------------------------------------------------------------------------
/exercises/03-multi-container/instructions.md:
--------------------------------------------------------------------------------
1 | # Exercise 3
2 |
3 | In this exercise, you will learn how to use Testcontainers to bring up multiple containers, one for a PostgreSQL database and one for Solr. You can find the initial code in the `start` directory. The production source class under test is named `WarehouseServiceImpl.java` in the directory `src/main/java`. The test class `WarehouseServiceImplIntegrationTest.java` in the directory `src/test/java` already implements a test case.
4 |
5 | > **_NOTE:_** You can choose to run the build using Maven or Gradle. Pick the tool you are most comfortable with.
6 |
7 | 1. In the test class, create an instance of `org.testcontainers.containers.PostgreSQLContainer`. Assign the image `postgres:9.6.12` and the database name `warehouse`. Upon creation, the container instance should run the script `warehouse.sql` to create the database schema.
8 | 2. Create another instance of `org.testcontainers.containers.SolrContainer`. Assign the image `solr:8.9.0`. Call the method `createProductsCollection` to create the initial Solr collection. Make sure to add the right dependency for the container type.
9 | 3. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
10 | 4. Instead of creating individual container instances, use the TestContainers Docker Compose functionality instead. Create an instance of `org.testcontainers.containers.DockerComposeContainer` and point it to the YAML file `src/test/resources/warehouse-test.yml`. PostgreSQL runs on port 5432, Solr exposes its service on port 8983.
11 | 5. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/solution/docker-compose/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | implementation 'org.apache.solr:solr-solrj:8.1.0'
15 | runtimeOnly 'org.postgresql:postgresql:42.5.0'
16 |
17 | def junitJupiterVersion = '5.8.1'
18 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
19 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
20 |
21 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
22 | testImplementation 'org.testcontainers:junit-jupiter'
23 | testImplementation 'org.testcontainers:postgresql'
24 | testImplementation 'org.testcontainers:solr'
25 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
26 | }
27 |
28 | test {
29 | useJUnitPlatform()
30 | testLogging {
31 | showStandardStreams = true
32 | }
33 | }
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/solution/docker-compose/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | docker-compose
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 8.1.0
15 | 42.5.0
16 | 5.8.1
17 |
18 |
19 |
20 |
21 | org.apache.solr
22 | solr-solrj
23 | ${solrj.version}
24 |
25 |
26 | org.postgresql
27 | postgresql
28 | ${postgresql.version}
29 | runtime
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter-api
34 | ${junit.jupiter.version}
35 | test
36 |
37 |
38 | org.junit.jupiter
39 | junit-jupiter-engine
40 | ${junit.jupiter.version}
41 | test
42 |
43 |
44 | org.testcontainers
45 | junit-jupiter
46 | test
47 |
48 |
49 | org.testcontainers
50 | postgresql
51 | test
52 |
53 |
54 | org.testcontainers
55 | solr
56 | test
57 |
58 |
59 | org.slf4j
60 | slf4j-simple
61 | 1.7.32
62 | test
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.testcontainers
70 | testcontainers-bom
71 | 1.17.3
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 | 3.8.1
85 |
86 | ${jdk.version}
87 | ${jdk.version}
88 | ${project.build.sourceEncoding}
89 |
90 |
91 |
92 | maven-surefire-plugin
93 | 2.22.2
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'docker-compose'
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/model/warehouse/Product.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.model.warehouse;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Product {
6 | private Long id;
7 | private String name;
8 | private String category;
9 | private BigDecimal price;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public void setName(String name) {
24 | this.name = name;
25 | }
26 |
27 | public String getCategory() {
28 | return category;
29 | }
30 |
31 | public void setCategory(String category) {
32 | this.category = category;
33 | }
34 |
35 | public BigDecimal getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(BigDecimal price) {
40 | this.price = price;
41 | }
42 |
43 | @Override
44 | public boolean equals(Object o) {
45 | if (this == o) {
46 | return true;
47 | }
48 | if (!(o instanceof Product)) {
49 | return false;
50 | }
51 |
52 | Product product = (Product) o;
53 |
54 | if (id != null ? !id.equals(product.id) : product.id != null) {
55 | return false;
56 | }
57 | if (name != null ? !name.equals(product.name) : product.name != null) {
58 | return false;
59 | }
60 | if (category != null ? !category.equals(product.category) : product.category != null) {
61 | return false;
62 | }
63 | return price != null ? price.equals(product.price) : product.price == null;
64 | }
65 |
66 | @Override
67 | public int hashCode() {
68 | int result = id != null ? id.hashCode() : 0;
69 | result = 31 * result + (name != null ? name.hashCode() : 0);
70 | result = 31 * result + (category != null ? category.hashCode() : 0);
71 | result = 31 * result + (price != null ? price.hashCode() : 0);
72 | return result;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/UsernamePasswordCredentials.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class UsernamePasswordCredentials {
4 | private final String username;
5 | private final String password;
6 |
7 | public UsernamePasswordCredentials(String username, String password) {
8 | this.username = username;
9 | this.password = password;
10 | }
11 |
12 | public String getUsername() {
13 | return username;
14 | }
15 |
16 | public String getPassword() {
17 | return password;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class WarehouseDatabaseException extends RuntimeException {
4 | public WarehouseDatabaseException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseDatabaseRepository {
6 | void insertProduct(Product product);
7 | Product getProduct(Long id);
8 | }
9 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | import java.sql.Connection;
6 | import java.sql.DriverManager;
7 | import java.sql.PreparedStatement;
8 | import java.sql.ResultSet;
9 | import java.sql.SQLException;
10 | import java.sql.Statement;
11 | import java.util.Properties;
12 |
13 | public class WarehouseDatabaseRepositoryImpl implements WarehouseDatabaseRepository {
14 | private final String jdbcUrl;
15 | private final UsernamePasswordCredentials credentials;
16 |
17 | public WarehouseDatabaseRepositoryImpl(String jdbcUrl, UsernamePasswordCredentials credentials) {
18 | this.jdbcUrl = jdbcUrl;
19 | this.credentials = credentials;
20 | }
21 |
22 | @Override
23 | public void insertProduct(Product product) {
24 | Connection connection = null;
25 | PreparedStatement pstmt = null;
26 | ResultSet rs = null;
27 |
28 | try {
29 | connection = createConnection();
30 | pstmt = connection.prepareStatement("INSERT INTO item (name, price) VALUES (?, ?) RETURNING ID");
31 | pstmt.setString(1, product.getName());
32 | pstmt.setBigDecimal(2, product.getPrice());
33 | rs = pstmt.executeQuery();
34 |
35 | while (rs.next()) {
36 | product.setId(rs.getLong(1));
37 | }
38 | } catch (SQLException e) {
39 | throw new WarehouseDatabaseException("Unable to insert item", e);
40 | } finally {
41 | closeResultSet(rs);
42 | closeStatement(pstmt);
43 | closeConnection(connection);
44 | }
45 | }
46 |
47 | @Override
48 | public Product getProduct(Long id) {
49 | Connection connection = null;
50 | PreparedStatement pstmt = null;
51 | ResultSet rs = null;
52 | Product product = null;
53 |
54 | try {
55 | connection = createConnection();
56 | pstmt = connection.prepareStatement("SELECT id, name, price FROM item WHERE id = ?");
57 | pstmt.setLong(1, id);
58 | rs = pstmt.executeQuery();
59 |
60 | while (rs.next()) {
61 | product = new Product();
62 | product.setId(rs.getLong(1));
63 | product.setName(rs.getString(2));
64 | product.setPrice(rs.getBigDecimal(3));
65 | }
66 |
67 | return product;
68 | } catch (SQLException e) {
69 | throw new WarehouseDatabaseException("Unable to insert item", e);
70 | } finally {
71 | closeResultSet(rs);
72 | closeStatement(pstmt);
73 | closeConnection(connection);
74 | }
75 | }
76 |
77 | private Connection createConnection() {
78 | Properties props = new Properties();
79 | props.setProperty("user", credentials.getUsername());
80 | props.setProperty("password", credentials.getPassword());
81 |
82 | try {
83 | return DriverManager.getConnection(jdbcUrl, props);
84 | } catch (SQLException e) {
85 | throw new WarehouseDatabaseException("Unable to establish connection to database", e);
86 | }
87 | }
88 |
89 | private void closeConnection(Connection connection) {
90 | try {
91 | if (connection != null && !connection.isClosed()) {
92 | connection.close();
93 | }
94 | } catch (SQLException e) {
95 | // ignore
96 | }
97 | }
98 |
99 | private void closeStatement(Statement statement) {
100 | try {
101 | if (statement != null && !statement.isClosed()) {
102 | statement.close();
103 | }
104 | } catch (SQLException e) {
105 | // ignore
106 | }
107 | }
108 |
109 | private void closeResultSet(ResultSet resultSet) {
110 | try {
111 | if (resultSet != null && !resultSet.isClosed()) {
112 | resultSet.close();
113 | }
114 | } catch (SQLException e) {
115 | // ignore
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | public class ProductIndexException extends RuntimeException {
4 | public ProductIndexException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface ProductIndexRepository {
6 | void insertProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import org.apache.solr.client.solrj.SolrClient;
5 | import org.apache.solr.client.solrj.SolrServerException;
6 | import org.apache.solr.client.solrj.impl.HttpSolrClient;
7 | import org.apache.solr.common.SolrInputDocument;
8 |
9 | import java.io.IOException;
10 |
11 | public class ProductIndexRepositoryImpl implements ProductIndexRepository {
12 | public static final String PRODUCTS_COLLECTION = "products";
13 | private final String serverUrl;
14 |
15 | public ProductIndexRepositoryImpl(String serverUrl) {
16 | this.serverUrl = serverUrl;
17 | }
18 |
19 | @Override
20 | public void insertProduct(Product product) {
21 | SolrClient client = null;
22 |
23 | try {
24 | client = createSolrClient();
25 | SolrInputDocument doc = new SolrInputDocument() ;
26 | doc.addField("name", product.getName());
27 | doc.addField("category", product.getCategory());
28 | client.add(PRODUCTS_COLLECTION, doc);
29 | client.commit(PRODUCTS_COLLECTION);
30 | } catch (IOException | SolrServerException e) {
31 | throw new ProductIndexException("Failed to insert product", e);
32 | } finally {
33 | closeCloseable(client);
34 | }
35 | }
36 |
37 | private SolrClient createSolrClient() {
38 | return new HttpSolrClient.Builder(serverUrl)
39 | .withConnectionTimeout(10000)
40 | .withSocketTimeout(60000)
41 | .build();
42 | }
43 |
44 | private void closeCloseable(SolrClient client) {
45 | try {
46 | if (client != null) {
47 | client.close();
48 | }
49 | } catch (IOException e) {
50 | // ignore
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/service/WarehouseService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseService {
6 | void addProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/main/java/com/bmuschko/testcontainers/service/WarehouseServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepository;
6 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepositoryImpl;
7 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepository;
8 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepositoryImpl;
9 |
10 | public class WarehouseServiceImpl implements WarehouseService {
11 | private final WarehouseDatabaseRepository warehouseDatabaseRepository;
12 | private final ProductIndexRepository productIndexRepository;
13 |
14 | public WarehouseServiceImpl(String databaseUrl, UsernamePasswordCredentials databaseCredentials, String solrUrl) {
15 | warehouseDatabaseRepository = new WarehouseDatabaseRepositoryImpl(databaseUrl, databaseCredentials);
16 | productIndexRepository = new ProductIndexRepositoryImpl(solrUrl);
17 | }
18 |
19 | @Override
20 | public void addProduct(Product product) {
21 | warehouseDatabaseRepository.insertProduct(product);
22 | productIndexRepository.insertProduct(product);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/test/java/com/bmuschko/testcontainers/service/WarehouseServiceImplIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 | import org.testcontainers.containers.DockerComposeContainer;
8 | import org.testcontainers.junit.jupiter.Container;
9 | import org.testcontainers.junit.jupiter.Testcontainers;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.math.BigDecimal;
14 | import java.net.URI;
15 | import java.net.http.HttpClient;
16 | import java.net.http.HttpRequest;
17 | import java.net.http.HttpResponse;
18 |
19 | @Testcontainers
20 | public class WarehouseServiceImplIntegrationTest {
21 | private static final String POSTGRESQL_SERVICE_NAME = "postgresql_1";
22 | private static final int POSTGRESQL_PORT = 5432;
23 | private static final String SOLR_SERVICE_NAME = "solr_1";
24 | private static final int SOLR_PORT = 8983;
25 | private WarehouseService warehouseService;
26 |
27 | @Container
28 | private final DockerComposeContainer environment = new DockerComposeContainer(new File("src/test/resources/warehouse-test.yml"))
29 | .withExposedService(POSTGRESQL_SERVICE_NAME, POSTGRESQL_PORT)
30 | .withExposedService(SOLR_SERVICE_NAME, SOLR_PORT);
31 |
32 | @BeforeEach
33 | public void setUp() {
34 | UsernamePasswordCredentials postgreSqlCredentials = new UsernamePasswordCredentials("postgres", "postgres");
35 | String solrUrl = createSolrUrl();
36 | createProductsCollection(solrUrl);
37 | warehouseService = new WarehouseServiceImpl(createPostgreSqlUrl(), postgreSqlCredentials, solrUrl);
38 | }
39 |
40 | @Test
41 | public void testInsertProduct() {
42 | Product product = new Product();
43 | product.setName("Clock");
44 | product.setPrice(new BigDecimal(39.99));
45 | product.setCategory("Household");
46 | warehouseService.addProduct(product);
47 | }
48 |
49 | private String createPostgreSqlUrl() {
50 | return "jdbc:postgresql://" + environment.getServiceHost(POSTGRESQL_SERVICE_NAME, POSTGRESQL_PORT) + ":" + environment.getServicePort(POSTGRESQL_SERVICE_NAME, POSTGRESQL_PORT) + "/warehouse";
51 | }
52 |
53 | private String createSolrUrl() {
54 | return "http://" + environment.getServiceHost(SOLR_SERVICE_NAME, SOLR_PORT) + ":" + environment.getServicePort(SOLR_SERVICE_NAME, SOLR_PORT) + "/solr";
55 | }
56 |
57 | private void createProductsCollection(String solrBaseUrl) {
58 | String createCollectionURL = solrBaseUrl + "/admin/collections?action=CREATE&name=products&numShards=1";
59 |
60 | try {
61 | HttpClient client = HttpClient.newHttpClient();
62 | HttpRequest request = HttpRequest.newBuilder(URI.create(createCollectionURL)).build();
63 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
64 |
65 | if (response.statusCode() != 200) {
66 | throw new IllegalStateException("Cannot set up products collection in Solr: " + new String(response.body().getBytes()));
67 | }
68 | } catch (IOException | InterruptedException e) {
69 | throw new IllegalStateException("Cannot set up products collection in Solr");
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/test/resources/warehouse-test.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 |
3 | services:
4 | postgresql:
5 | image: postgres:9.6.12
6 | environment:
7 | - POSTGRES_DB=warehouse
8 | - POSTGRES_USER=postgres
9 | - POSTGRES_PASSWORD=postgres
10 | volumes:
11 | - ./warehouse.sql:/docker-entrypoint-initdb.d/warehouse.sql
12 |
13 | solr:
14 | image: solr:8.9.0
15 | command:
16 | - bash
17 | - "-c"
18 | - "solr -f -cloud"
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/docker-compose/src/test/resources/warehouse.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS ITEM;
2 |
3 | CREATE TABLE ITEM(
4 | ID SERIAL PRIMARY KEY,
5 | NAME TEXT NOT NULL,
6 | PRICE NUMERIC NOT NULL
7 | );
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/solution/multi-container/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | implementation 'org.apache.solr:solr-solrj:8.1.0'
15 | runtimeOnly 'org.postgresql:postgresql:42.5.0'
16 |
17 | def junitJupiterVersion = '5.8.1'
18 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
19 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
20 |
21 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
22 | testImplementation 'org.testcontainers:junit-jupiter'
23 | testImplementation 'org.testcontainers:postgresql'
24 | testImplementation 'org.testcontainers:solr'
25 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
26 | }
27 |
28 | test {
29 | useJUnitPlatform()
30 | testLogging {
31 | showStandardStreams = true
32 | }
33 | }
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/solution/multi-container/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | multi-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 8.1.0
15 | 42.5.0
16 | 5.8.1
17 |
18 |
19 |
20 |
21 | org.apache.solr
22 | solr-solrj
23 | ${solrj.version}
24 |
25 |
26 | org.postgresql
27 | postgresql
28 | ${postgresql.version}
29 | runtime
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter-api
34 | ${junit.jupiter.version}
35 | test
36 |
37 |
38 | org.junit.jupiter
39 | junit-jupiter-engine
40 | ${junit.jupiter.version}
41 | test
42 |
43 |
44 | org.testcontainers
45 | junit-jupiter
46 | test
47 |
48 |
49 | org.testcontainers
50 | postgresql
51 | test
52 |
53 |
54 | org.testcontainers
55 | solr
56 | test
57 |
58 |
59 | org.slf4j
60 | slf4j-simple
61 | 1.7.32
62 | test
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.testcontainers
70 | testcontainers-bom
71 | 1.17.3
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 | 3.8.1
85 |
86 | ${jdk.version}
87 | ${jdk.version}
88 | ${project.build.sourceEncoding}
89 |
90 |
91 |
92 | maven-surefire-plugin
93 | 2.22.2
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'multi-container'
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/model/warehouse/Product.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.model.warehouse;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Product {
6 | private Long id;
7 | private String name;
8 | private String category;
9 | private BigDecimal price;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public void setName(String name) {
24 | this.name = name;
25 | }
26 |
27 | public String getCategory() {
28 | return category;
29 | }
30 |
31 | public void setCategory(String category) {
32 | this.category = category;
33 | }
34 |
35 | public BigDecimal getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(BigDecimal price) {
40 | this.price = price;
41 | }
42 |
43 | @Override
44 | public boolean equals(Object o) {
45 | if (this == o) {
46 | return true;
47 | }
48 | if (!(o instanceof Product)) {
49 | return false;
50 | }
51 |
52 | Product product = (Product) o;
53 |
54 | if (id != null ? !id.equals(product.id) : product.id != null) {
55 | return false;
56 | }
57 | if (name != null ? !name.equals(product.name) : product.name != null) {
58 | return false;
59 | }
60 | if (category != null ? !category.equals(product.category) : product.category != null) {
61 | return false;
62 | }
63 | return price != null ? price.equals(product.price) : product.price == null;
64 | }
65 |
66 | @Override
67 | public int hashCode() {
68 | int result = id != null ? id.hashCode() : 0;
69 | result = 31 * result + (name != null ? name.hashCode() : 0);
70 | result = 31 * result + (category != null ? category.hashCode() : 0);
71 | result = 31 * result + (price != null ? price.hashCode() : 0);
72 | return result;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/UsernamePasswordCredentials.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class UsernamePasswordCredentials {
4 | private final String username;
5 | private final String password;
6 |
7 | public UsernamePasswordCredentials(String username, String password) {
8 | this.username = username;
9 | this.password = password;
10 | }
11 |
12 | public String getUsername() {
13 | return username;
14 | }
15 |
16 | public String getPassword() {
17 | return password;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class WarehouseDatabaseException extends RuntimeException {
4 | public WarehouseDatabaseException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseDatabaseRepository {
6 | void insertProduct(Product product);
7 | Product getProduct(Long id);
8 | }
9 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | import java.sql.Connection;
6 | import java.sql.DriverManager;
7 | import java.sql.PreparedStatement;
8 | import java.sql.ResultSet;
9 | import java.sql.SQLException;
10 | import java.sql.Statement;
11 | import java.util.Properties;
12 |
13 | public class WarehouseDatabaseRepositoryImpl implements WarehouseDatabaseRepository {
14 | private final String jdbcUrl;
15 | private final UsernamePasswordCredentials credentials;
16 |
17 | public WarehouseDatabaseRepositoryImpl(String jdbcUrl, UsernamePasswordCredentials credentials) {
18 | this.jdbcUrl = jdbcUrl;
19 | this.credentials = credentials;
20 | }
21 |
22 | @Override
23 | public void insertProduct(Product product) {
24 | Connection connection = null;
25 | PreparedStatement pstmt = null;
26 | ResultSet rs = null;
27 |
28 | try {
29 | connection = createConnection();
30 | pstmt = connection.prepareStatement("INSERT INTO item (name, price) VALUES (?, ?) RETURNING ID");
31 | pstmt.setString(1, product.getName());
32 | pstmt.setBigDecimal(2, product.getPrice());
33 | rs = pstmt.executeQuery();
34 |
35 | while (rs.next()) {
36 | product.setId(rs.getLong(1));
37 | }
38 | } catch (SQLException e) {
39 | throw new WarehouseDatabaseException("Unable to insert item", e);
40 | } finally {
41 | closeResultSet(rs);
42 | closeStatement(pstmt);
43 | closeConnection(connection);
44 | }
45 | }
46 |
47 | @Override
48 | public Product getProduct(Long id) {
49 | Connection connection = null;
50 | PreparedStatement pstmt = null;
51 | ResultSet rs = null;
52 | Product product = null;
53 |
54 | try {
55 | connection = createConnection();
56 | pstmt = connection.prepareStatement("SELECT id, name, price FROM item WHERE id = ?");
57 | pstmt.setLong(1, id);
58 | rs = pstmt.executeQuery();
59 |
60 | while (rs.next()) {
61 | product = new Product();
62 | product.setId(rs.getLong(1));
63 | product.setName(rs.getString(2));
64 | product.setPrice(rs.getBigDecimal(3));
65 | }
66 |
67 | return product;
68 | } catch (SQLException e) {
69 | throw new WarehouseDatabaseException("Unable to insert item", e);
70 | } finally {
71 | closeResultSet(rs);
72 | closeStatement(pstmt);
73 | closeConnection(connection);
74 | }
75 | }
76 |
77 | private Connection createConnection() {
78 | Properties props = new Properties();
79 | props.setProperty("user", credentials.getUsername());
80 | props.setProperty("password", credentials.getPassword());
81 |
82 | try {
83 | return DriverManager.getConnection(jdbcUrl, props);
84 | } catch (SQLException e) {
85 | throw new WarehouseDatabaseException("Unable to establish connection to database", e);
86 | }
87 | }
88 |
89 | private void closeConnection(Connection connection) {
90 | try {
91 | if (connection != null && !connection.isClosed()) {
92 | connection.close();
93 | }
94 | } catch (SQLException e) {
95 | // ignore
96 | }
97 | }
98 |
99 | private void closeStatement(Statement statement) {
100 | try {
101 | if (statement != null && !statement.isClosed()) {
102 | statement.close();
103 | }
104 | } catch (SQLException e) {
105 | // ignore
106 | }
107 | }
108 |
109 | private void closeResultSet(ResultSet resultSet) {
110 | try {
111 | if (resultSet != null && !resultSet.isClosed()) {
112 | resultSet.close();
113 | }
114 | } catch (SQLException e) {
115 | // ignore
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | public class ProductIndexException extends RuntimeException {
4 | public ProductIndexException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface ProductIndexRepository {
6 | void insertProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import org.apache.solr.client.solrj.SolrClient;
5 | import org.apache.solr.client.solrj.SolrServerException;
6 | import org.apache.solr.client.solrj.impl.HttpSolrClient;
7 | import org.apache.solr.common.SolrInputDocument;
8 |
9 | import java.io.IOException;
10 |
11 | public class ProductIndexRepositoryImpl implements ProductIndexRepository {
12 | public static final String PRODUCTS_COLLECTION = "products";
13 | private final String serverUrl;
14 |
15 | public ProductIndexRepositoryImpl(String serverUrl) {
16 | this.serverUrl = serverUrl;
17 | }
18 |
19 | @Override
20 | public void insertProduct(Product product) {
21 | SolrClient client = null;
22 |
23 | try {
24 | client = createSolrClient();
25 | SolrInputDocument doc = new SolrInputDocument() ;
26 | doc.addField("name", product.getName());
27 | doc.addField("category", product.getCategory());
28 | client.add(PRODUCTS_COLLECTION, doc);
29 | client.commit(PRODUCTS_COLLECTION);
30 | } catch (IOException | SolrServerException e) {
31 | throw new ProductIndexException("Failed to insert product", e);
32 | } finally {
33 | closeCloseable(client);
34 | }
35 | }
36 |
37 | private SolrClient createSolrClient() {
38 | return new HttpSolrClient.Builder(serverUrl)
39 | .withConnectionTimeout(10000)
40 | .withSocketTimeout(60000)
41 | .build();
42 | }
43 |
44 | private void closeCloseable(SolrClient client) {
45 | try {
46 | if (client != null) {
47 | client.close();
48 | }
49 | } catch (IOException e) {
50 | // ignore
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/service/WarehouseService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseService {
6 | void addProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/main/java/com/bmuschko/testcontainers/service/WarehouseServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepository;
6 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepositoryImpl;
7 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepository;
8 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepositoryImpl;
9 |
10 | public class WarehouseServiceImpl implements WarehouseService {
11 | private final WarehouseDatabaseRepository warehouseDatabaseRepository;
12 | private final ProductIndexRepository productIndexRepository;
13 |
14 | public WarehouseServiceImpl(String databaseUrl, UsernamePasswordCredentials databaseCredentials, String solrUrl) {
15 | warehouseDatabaseRepository = new WarehouseDatabaseRepositoryImpl(databaseUrl, databaseCredentials);
16 | productIndexRepository = new ProductIndexRepositoryImpl(solrUrl);
17 | }
18 |
19 | @Override
20 | public void addProduct(Product product) {
21 | warehouseDatabaseRepository.insertProduct(product);
22 | productIndexRepository.insertProduct(product);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/test/java/com/bmuschko/testcontainers/service/WarehouseServiceImplIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 | import org.testcontainers.containers.JdbcDatabaseContainer;
8 | import org.testcontainers.containers.PostgreSQLContainer;
9 | import org.testcontainers.containers.SolrContainer;
10 | import org.testcontainers.junit.jupiter.Container;
11 | import org.testcontainers.junit.jupiter.Testcontainers;
12 | import org.testcontainers.utility.DockerImageName;
13 |
14 | import java.io.IOException;
15 | import java.math.BigDecimal;
16 | import java.net.URI;
17 | import java.net.http.HttpClient;
18 | import java.net.http.HttpRequest;
19 | import java.net.http.HttpResponse;
20 |
21 | @Testcontainers
22 | public class WarehouseServiceImplIntegrationTest {
23 | private WarehouseService warehouseService;
24 |
25 | @Container
26 | private final JdbcDatabaseContainer postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.12")
27 | .withInitScript("warehouse.sql")
28 | .withDatabaseName("warehouse");
29 |
30 | @Container
31 | private final SolrContainer solrContainer = new SolrContainer(DockerImageName.parse("solr:8.9.0"));
32 |
33 | @BeforeEach
34 | public void setUp() {
35 | UsernamePasswordCredentials postgreSqlCredentials = new UsernamePasswordCredentials(postgreSQLContainer.getUsername(), postgreSQLContainer.getPassword());
36 | String solrUrl = createSolrUrl();
37 | createProductsCollection(solrUrl);
38 | warehouseService = new WarehouseServiceImpl(postgreSQLContainer.getJdbcUrl(), postgreSqlCredentials, solrUrl);
39 | }
40 |
41 | @Test
42 | public void testInsertProduct() {
43 | Product product = new Product();
44 | product.setName("Clock");
45 | product.setPrice(new BigDecimal(39.99));
46 | product.setCategory("Household");
47 | warehouseService.addProduct(product);
48 | }
49 |
50 | private String createSolrUrl() {
51 | return "http://" + solrContainer.getContainerIpAddress() + ":" + solrContainer.getSolrPort() + "/solr";
52 | }
53 |
54 | private void createProductsCollection(String solrBaseUrl) {
55 | String createCollectionURL = solrBaseUrl + "/admin/collections?action=CREATE&name=products&numShards=1";
56 |
57 | try {
58 | HttpClient client = HttpClient.newHttpClient();
59 | HttpRequest request = HttpRequest.newBuilder(URI.create(createCollectionURL)).build();
60 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
61 |
62 | if (response.statusCode() != 200) {
63 | throw new IllegalStateException("Cannot set up products collection in Solr: " + new String(response.body().getBytes()));
64 | }
65 | } catch (IOException | InterruptedException e) {
66 | throw new IllegalStateException("Cannot set up products collection in Solr");
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/solution/multi-container/src/test/resources/warehouse.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS ITEM;
2 |
3 | CREATE TABLE ITEM(
4 | ID SERIAL PRIMARY KEY,
5 | NAME TEXT NOT NULL,
6 | PRICE NUMERIC NOT NULL
7 | );
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/start/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | implementation 'org.apache.solr:solr-solrj:8.1.0'
15 | runtimeOnly 'org.postgresql:postgresql:42.5.0'
16 |
17 | def junitJupiterVersion = '5.8.1'
18 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
19 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
20 |
21 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
22 | testImplementation 'org.testcontainers:junit-jupiter'
23 | testImplementation 'org.testcontainers:postgresql'
24 | testImplementation 'org.testcontainers:solr'
25 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
26 | }
27 |
28 | test {
29 | useJUnitPlatform()
30 | testLogging {
31 | showStandardStreams = true
32 | }
33 | }
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/03-multi-container/start/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | multi-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 8.1.0
15 | 42.5.0
16 | 5.8.1
17 |
18 |
19 |
20 |
21 | org.apache.solr
22 | solr-solrj
23 | ${solrj.version}
24 |
25 |
26 | org.postgresql
27 | postgresql
28 | ${postgresql.version}
29 | runtime
30 |
31 |
32 | org.junit.jupiter
33 | junit-jupiter-api
34 | ${junit.jupiter.version}
35 | test
36 |
37 |
38 | org.junit.jupiter
39 | junit-jupiter-engine
40 | ${junit.jupiter.version}
41 | test
42 |
43 |
44 | org.testcontainers
45 | junit-jupiter
46 | test
47 |
48 |
49 | org.testcontainers
50 | postgresql
51 | test
52 |
53 |
54 | org.testcontainers
55 | solr
56 | test
57 |
58 |
59 | org.slf4j
60 | slf4j-simple
61 | 1.7.32
62 | test
63 |
64 |
65 |
66 |
67 |
68 |
69 | org.testcontainers
70 | testcontainers-bom
71 | 1.17.3
72 | pom
73 | import
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-compiler-plugin
84 | 3.8.1
85 |
86 | ${jdk.version}
87 | ${jdk.version}
88 | ${project.build.sourceEncoding}
89 |
90 |
91 |
92 | maven-surefire-plugin
93 | 2.22.2
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'multi-container'
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/model/warehouse/Product.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.model.warehouse;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class Product {
6 | private Long id;
7 | private String name;
8 | private String category;
9 | private BigDecimal price;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public void setName(String name) {
24 | this.name = name;
25 | }
26 |
27 | public String getCategory() {
28 | return category;
29 | }
30 |
31 | public void setCategory(String category) {
32 | this.category = category;
33 | }
34 |
35 | public BigDecimal getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(BigDecimal price) {
40 | this.price = price;
41 | }
42 |
43 | @Override
44 | public boolean equals(Object o) {
45 | if (this == o) {
46 | return true;
47 | }
48 | if (!(o instanceof Product)) {
49 | return false;
50 | }
51 |
52 | Product product = (Product) o;
53 |
54 | if (id != null ? !id.equals(product.id) : product.id != null) {
55 | return false;
56 | }
57 | if (name != null ? !name.equals(product.name) : product.name != null) {
58 | return false;
59 | }
60 | if (category != null ? !category.equals(product.category) : product.category != null) {
61 | return false;
62 | }
63 | return price != null ? price.equals(product.price) : product.price == null;
64 | }
65 |
66 | @Override
67 | public int hashCode() {
68 | int result = id != null ? id.hashCode() : 0;
69 | result = 31 * result + (name != null ? name.hashCode() : 0);
70 | result = 31 * result + (category != null ? category.hashCode() : 0);
71 | result = 31 * result + (price != null ? price.hashCode() : 0);
72 | return result;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/UsernamePasswordCredentials.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class UsernamePasswordCredentials {
4 | private final String username;
5 | private final String password;
6 |
7 | public UsernamePasswordCredentials(String username, String password) {
8 | this.username = username;
9 | this.password = password;
10 | }
11 |
12 | public String getUsername() {
13 | return username;
14 | }
15 |
16 | public String getPassword() {
17 | return password;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | public class WarehouseDatabaseException extends RuntimeException {
4 | public WarehouseDatabaseException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseDatabaseRepository {
6 | void insertProduct(Product product);
7 | Product getProduct(Long id);
8 | }
9 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/db/WarehouseDatabaseRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.db;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | import java.sql.Connection;
6 | import java.sql.DriverManager;
7 | import java.sql.PreparedStatement;
8 | import java.sql.ResultSet;
9 | import java.sql.SQLException;
10 | import java.sql.Statement;
11 | import java.util.Properties;
12 |
13 | public class WarehouseDatabaseRepositoryImpl implements WarehouseDatabaseRepository {
14 | private final String jdbcUrl;
15 | private final UsernamePasswordCredentials credentials;
16 |
17 | public WarehouseDatabaseRepositoryImpl(String jdbcUrl, UsernamePasswordCredentials credentials) {
18 | this.jdbcUrl = jdbcUrl;
19 | this.credentials = credentials;
20 | }
21 |
22 | @Override
23 | public void insertProduct(Product product) {
24 | Connection connection = null;
25 | PreparedStatement pstmt = null;
26 | ResultSet rs = null;
27 |
28 | try {
29 | connection = createConnection();
30 | pstmt = connection.prepareStatement("INSERT INTO item (name, price) VALUES (?, ?) RETURNING ID");
31 | pstmt.setString(1, product.getName());
32 | pstmt.setBigDecimal(2, product.getPrice());
33 | rs = pstmt.executeQuery();
34 |
35 | while (rs.next()) {
36 | product.setId(rs.getLong(1));
37 | }
38 | } catch (SQLException e) {
39 | throw new WarehouseDatabaseException("Unable to insert item", e);
40 | } finally {
41 | closeResultSet(rs);
42 | closeStatement(pstmt);
43 | closeConnection(connection);
44 | }
45 | }
46 |
47 | @Override
48 | public Product getProduct(Long id) {
49 | Connection connection = null;
50 | PreparedStatement pstmt = null;
51 | ResultSet rs = null;
52 | Product product = null;
53 |
54 | try {
55 | connection = createConnection();
56 | pstmt = connection.prepareStatement("SELECT id, name, price FROM item WHERE id = ?");
57 | pstmt.setLong(1, id);
58 | rs = pstmt.executeQuery();
59 |
60 | while (rs.next()) {
61 | product = new Product();
62 | product.setId(rs.getLong(1));
63 | product.setName(rs.getString(2));
64 | product.setPrice(rs.getBigDecimal(3));
65 | }
66 |
67 | return product;
68 | } catch (SQLException e) {
69 | throw new WarehouseDatabaseException("Unable to insert item", e);
70 | } finally {
71 | closeResultSet(rs);
72 | closeStatement(pstmt);
73 | closeConnection(connection);
74 | }
75 | }
76 |
77 | private Connection createConnection() {
78 | Properties props = new Properties();
79 | props.setProperty("user", credentials.getUsername());
80 | props.setProperty("password", credentials.getPassword());
81 |
82 | try {
83 | return DriverManager.getConnection(jdbcUrl, props);
84 | } catch (SQLException e) {
85 | throw new WarehouseDatabaseException("Unable to establish connection to database", e);
86 | }
87 | }
88 |
89 | private void closeConnection(Connection connection) {
90 | try {
91 | if (connection != null && !connection.isClosed()) {
92 | connection.close();
93 | }
94 | } catch (SQLException e) {
95 | // ignore
96 | }
97 | }
98 |
99 | private void closeStatement(Statement statement) {
100 | try {
101 | if (statement != null && !statement.isClosed()) {
102 | statement.close();
103 | }
104 | } catch (SQLException e) {
105 | // ignore
106 | }
107 | }
108 |
109 | private void closeResultSet(ResultSet resultSet) {
110 | try {
111 | if (resultSet != null && !resultSet.isClosed()) {
112 | resultSet.close();
113 | }
114 | } catch (SQLException e) {
115 | // ignore
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexException.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | public class ProductIndexException extends RuntimeException {
4 | public ProductIndexException(String message, Throwable cause) {
5 | super(message, cause);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepository.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface ProductIndexRepository {
6 | void insertProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/repository/warehouse/index/ProductIndexRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.repository.warehouse.index;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import org.apache.solr.client.solrj.SolrClient;
5 | import org.apache.solr.client.solrj.SolrServerException;
6 | import org.apache.solr.client.solrj.impl.HttpSolrClient;
7 | import org.apache.solr.common.SolrInputDocument;
8 |
9 | import java.io.IOException;
10 |
11 | public class ProductIndexRepositoryImpl implements ProductIndexRepository {
12 | public static final String PRODUCTS_COLLECTION = "products";
13 | private final String serverUrl;
14 |
15 | public ProductIndexRepositoryImpl(String serverUrl) {
16 | this.serverUrl = serverUrl;
17 | }
18 |
19 | @Override
20 | public void insertProduct(Product product) {
21 | SolrClient client = null;
22 |
23 | try {
24 | client = createSolrClient();
25 | SolrInputDocument doc = new SolrInputDocument() ;
26 | doc.addField("name", product.getName());
27 | doc.addField("category", product.getCategory());
28 | client.add(PRODUCTS_COLLECTION, doc);
29 | client.commit(PRODUCTS_COLLECTION);
30 | } catch (IOException | SolrServerException e) {
31 | throw new ProductIndexException("Failed to insert product", e);
32 | } finally {
33 | closeCloseable(client);
34 | }
35 | }
36 |
37 | private SolrClient createSolrClient() {
38 | return new HttpSolrClient.Builder(serverUrl)
39 | .withConnectionTimeout(10000)
40 | .withSocketTimeout(60000)
41 | .build();
42 | }
43 |
44 | private void closeCloseable(SolrClient client) {
45 | try {
46 | if (client != null) {
47 | client.close();
48 | }
49 | } catch (IOException e) {
50 | // ignore
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/service/WarehouseService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 |
5 | public interface WarehouseService {
6 | void addProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/main/java/com/bmuschko/testcontainers/service/WarehouseServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepository;
6 | import com.bmuschko.testcontainers.repository.warehouse.db.WarehouseDatabaseRepositoryImpl;
7 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepository;
8 | import com.bmuschko.testcontainers.repository.warehouse.index.ProductIndexRepositoryImpl;
9 |
10 | public class WarehouseServiceImpl implements WarehouseService {
11 | private final WarehouseDatabaseRepository warehouseDatabaseRepository;
12 | private final ProductIndexRepository productIndexRepository;
13 |
14 | public WarehouseServiceImpl(String databaseUrl, UsernamePasswordCredentials databaseCredentials, String solrUrl) {
15 | warehouseDatabaseRepository = new WarehouseDatabaseRepositoryImpl(databaseUrl, databaseCredentials);
16 | productIndexRepository = new ProductIndexRepositoryImpl(solrUrl);
17 | }
18 |
19 | @Override
20 | public void addProduct(Product product) {
21 | warehouseDatabaseRepository.insertProduct(product);
22 | productIndexRepository.insertProduct(product);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/test/java/com/bmuschko/testcontainers/service/WarehouseServiceImplIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers.service;
2 |
3 | import com.bmuschko.testcontainers.model.warehouse.Product;
4 | import com.bmuschko.testcontainers.repository.warehouse.db.UsernamePasswordCredentials;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 | import org.testcontainers.junit.jupiter.Container;
8 | import org.testcontainers.junit.jupiter.Testcontainers;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 | import java.math.BigDecimal;
13 | import java.net.URI;
14 | import java.net.http.HttpClient;
15 | import java.net.http.HttpRequest;
16 | import java.net.http.HttpResponse;
17 |
18 | @Testcontainers
19 | public class WarehouseServiceImplIntegrationTest {
20 | private WarehouseService warehouseService;
21 |
22 | @Container
23 | // Create container
24 |
25 | @BeforeEach
26 | public void setUp() {
27 | UsernamePasswordCredentials postgreSqlCredentials = new UsernamePasswordCredentials("postgres", "postgres");
28 | String solrUrl = createSolrUrl();
29 | createProductsCollection(solrUrl);
30 | warehouseService = new WarehouseServiceImpl(createPostgreSqlUrl(), postgreSqlCredentials, solrUrl);
31 | }
32 |
33 | @Test
34 | public void testInsertProduct() {
35 | Product product = new Product();
36 | product.setName("Clock");
37 | product.setPrice(new BigDecimal(39.99));
38 | product.setCategory("Household");
39 | warehouseService.addProduct(product);
40 | }
41 |
42 | private String createPostgreSqlUrl() {
43 | return null;
44 | }
45 |
46 | private String createSolrUrl() {
47 | return null;
48 | }
49 |
50 | private void createProductsCollection(String solrBaseUrl) {
51 | String createCollectionURL = solrBaseUrl + "/admin/collections?action=CREATE&name=products&numShards=1";
52 |
53 | try {
54 | HttpClient client = HttpClient.newHttpClient();
55 | HttpRequest request = HttpRequest.newBuilder(URI.create(createCollectionURL)).build();
56 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
57 |
58 | if (response.statusCode() != 200) {
59 | throw new IllegalStateException("Cannot set up products collection in Solr: " + new String(response.body().getBytes()));
60 | }
61 | } catch (IOException | InterruptedException e) {
62 | throw new IllegalStateException("Cannot set up products collection in Solr");
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/test/resources/warehouse-test.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 |
3 | services:
4 | postgresql:
5 | image: postgres:9.6.12
6 | environment:
7 | - POSTGRES_DB=warehouse
8 | - POSTGRES_USER=postgres
9 | - POSTGRES_PASSWORD=postgres
10 | volumes:
11 | - ./warehouse.sql:/docker-entrypoint-initdb.d/warehouse.sql
12 |
13 | solr:
14 | image: solr:8.9.0
15 | command:
16 | - bash
17 | - "-c"
18 | - "solr -f -cloud"
--------------------------------------------------------------------------------
/exercises/03-multi-container/start/src/test/resources/warehouse.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS ITEM;
2 |
3 | CREATE TABLE ITEM(
4 | ID SERIAL PRIMARY KEY,
5 | NAME TEXT NOT NULL,
6 | PRICE NUMERIC NOT NULL
7 | );
--------------------------------------------------------------------------------
/exercises/04-generic-container/instructions.md:
--------------------------------------------------------------------------------
1 | # Exercise 4
2 |
3 | In this exercise, you will learn how to use Testcontainers to use a generic container. First, you'll create a container object of type `org.testcontainers.containers.GenericContainer`. Later, you'll build the container on-the-fly.
4 |
5 | > **_NOTE:_** You can choose to run the build using Maven or Gradle. Pick the tool you are most comfortable with.
6 |
7 | 1. In the existing test class, create a `GenericContainer` that uses the image named `nginx:1.21.3`. The test code should be able to reach the endpoint of the Ngix container.
8 | 2. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
9 | 3. Instead of using a pre-built Nginx, build the container using the provided Dockerfile.
10 | 4. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
11 | 5. Instead of using the Dockerfile, build the container with individual instructions defined by Testcontainers method calls.
12 | 6. Run the test and verify its correct behavior. For Maven the command is `./mvnw test`, for Gradle the command is `./gradlew test`. The console output should indicate that the container has been created and destroyed after the test finished.
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/dockerfile/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | def junitJupiterVersion = '5.8.1'
15 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
16 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
17 |
18 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
19 | testImplementation 'org.testcontainers:junit-jupiter'
20 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | testLogging {
26 | showStandardStreams = true
27 | }
28 | }
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/dockerfile/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | on-the-fly-nginx-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 5.8.1
15 |
16 |
17 |
18 |
19 | org.junit.jupiter
20 | junit-jupiter-api
21 | ${junit.jupiter.version}
22 | test
23 |
24 |
25 | org.junit.jupiter
26 | junit-jupiter-engine
27 | ${junit.jupiter.version}
28 | test
29 |
30 |
31 | org.testcontainers
32 | junit-jupiter
33 | test
34 |
35 |
36 | org.slf4j
37 | slf4j-simple
38 | 1.7.32
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.testcontainers
47 | testcontainers-bom
48 | 1.17.3
49 | pom
50 | import
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-compiler-plugin
61 | 3.8.1
62 |
63 | ${jdk.version}
64 | ${jdk.version}
65 | ${project.build.sourceEncoding}
66 |
67 |
68 |
69 | maven-surefire-plugin
70 | 2.22.2
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'on-the-fly-nginx-generic-container'
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/src/main/java/com/bmuschko/testcontainers/NginxService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface NginxService {
4 | void ping();
5 | }
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/src/main/java/com/bmuschko/testcontainers/NginxServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.io.IOException;
4 | import java.net.URI;
5 | import java.net.http.HttpClient;
6 | import java.net.http.HttpRequest;
7 | import java.net.http.HttpResponse;
8 |
9 | public class NginxServiceImpl implements NginxService {
10 | private final String endpointUrl;
11 |
12 | public NginxServiceImpl(String endpointUrl) {
13 | this.endpointUrl = endpointUrl;
14 | }
15 |
16 | @Override
17 | public void ping() {
18 | try {
19 | HttpClient client = HttpClient.newHttpClient();
20 | HttpRequest request = HttpRequest.newBuilder(URI.create(endpointUrl)).build();
21 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
22 |
23 | if (response.statusCode() != 200) {
24 | throw new IllegalStateException("Cannot reach Ngix server: " + new String(response.body().getBytes()));
25 | }
26 | } catch (IOException | InterruptedException e) {
27 | throw new IllegalStateException("Cannot reach Ngix server");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/src/test/java/com/bmuschko/testcontainers/NginxServiceIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.GenericContainer;
6 | import org.testcontainers.images.builder.ImageFromDockerfile;
7 | import org.testcontainers.junit.jupiter.Container;
8 | import org.testcontainers.junit.jupiter.Testcontainers;
9 |
10 | import java.io.File;
11 |
12 | @Testcontainers
13 | public class NginxServiceIntegrationTest {
14 | private NginxService nginxService;
15 |
16 | @Container
17 | private final GenericContainer nginx = new GenericContainer(new ImageFromDockerfile().withDockerfile(new File("src/test/resources/Dockerfile").toPath())).withExposedPorts(80);
18 |
19 | @BeforeEach
20 | public void setUp() {
21 | String host = nginx.getHost();
22 | Integer port = nginx.getFirstMappedPort();
23 | String endpointUrl = "http://" + host + ":" + port;
24 | nginxService = new NginxServiceImpl(endpointUrl);
25 | }
26 |
27 | @Test
28 | public void testPing() {
29 | nginxService.ping();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/dockerfile/src/test/resources/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.2
2 | RUN ["apk", "add", "--update", "nginx"]
3 | CMD ["nginx", "-g", "daemon off;"]
4 | EXPOSE 80
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/instructions/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | def junitJupiterVersion = '5.8.1'
15 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
16 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
17 |
18 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
19 | testImplementation 'org.testcontainers:junit-jupiter'
20 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | testLogging {
26 | showStandardStreams = true
27 | }
28 | }
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/instructions/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | on-the-fly-nginx-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 5.8.1
15 |
16 |
17 |
18 |
19 | org.junit.jupiter
20 | junit-jupiter-api
21 | ${junit.jupiter.version}
22 | test
23 |
24 |
25 | org.junit.jupiter
26 | junit-jupiter-engine
27 | ${junit.jupiter.version}
28 | test
29 |
30 |
31 | org.testcontainers
32 | junit-jupiter
33 | test
34 |
35 |
36 | org.slf4j
37 | slf4j-simple
38 | 1.7.32
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.testcontainers
47 | testcontainers-bom
48 | 1.17.3
49 | pom
50 | import
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-compiler-plugin
61 | 3.8.1
62 |
63 | ${jdk.version}
64 | ${jdk.version}
65 | ${project.build.sourceEncoding}
66 |
67 |
68 |
69 | maven-surefire-plugin
70 | 2.22.2
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'on-the-fly-nginx-generic-container'
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/src/main/java/com/bmuschko/testcontainers/NginxService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface NginxService {
4 | void ping();
5 | }
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/src/main/java/com/bmuschko/testcontainers/NginxServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.io.IOException;
4 | import java.net.URI;
5 | import java.net.http.HttpClient;
6 | import java.net.http.HttpRequest;
7 | import java.net.http.HttpResponse;
8 |
9 | public class NginxServiceImpl implements NginxService {
10 | private final String endpointUrl;
11 |
12 | public NginxServiceImpl(String endpointUrl) {
13 | this.endpointUrl = endpointUrl;
14 | }
15 |
16 | @Override
17 | public void ping() {
18 | try {
19 | HttpClient client = HttpClient.newHttpClient();
20 | HttpRequest request = HttpRequest.newBuilder(URI.create(endpointUrl)).build();
21 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
22 |
23 | if (response.statusCode() != 200) {
24 | throw new IllegalStateException("Cannot reach Ngix server: " + new String(response.body().getBytes()));
25 | }
26 | } catch (IOException | InterruptedException e) {
27 | throw new IllegalStateException("Cannot reach Ngix server");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/instructions/src/test/java/com/bmuschko/testcontainers/NginxServiceIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.GenericContainer;
6 | import org.testcontainers.images.builder.ImageFromDockerfile;
7 | import org.testcontainers.junit.jupiter.Container;
8 | import org.testcontainers.junit.jupiter.Testcontainers;
9 |
10 | import java.io.File;
11 |
12 | @Testcontainers
13 | public class NginxServiceIntegrationTest {
14 | private NginxService nginxService;
15 |
16 | @Container
17 | private final GenericContainer nginx = new GenericContainer(new ImageFromDockerfile().withDockerfileFromBuilder(builder ->
18 | builder.from("alpine:3.2")
19 | .run("apk add --update nginx")
20 | .cmd("nginx", "-g", "daemon off;")
21 | .build())).withExposedPorts(80);
22 |
23 | @BeforeEach
24 | public void setUp() {
25 | String host = nginx.getHost();
26 | Integer port = nginx.getFirstMappedPort();
27 | String endpointUrl = "http://" + host + ":" + port;
28 | nginxService = new NginxServiceImpl(endpointUrl);
29 | }
30 |
31 | @Test
32 | public void testPing() {
33 | nginxService.ping();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/prebuilt/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | def junitJupiterVersion = '5.8.1'
15 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
16 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
17 |
18 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
19 | testImplementation 'org.testcontainers:junit-jupiter'
20 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | testLogging {
26 | showStandardStreams = true
27 | }
28 | }
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/solution/prebuilt/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | prebuilt-nginx-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 5.8.1
15 |
16 |
17 |
18 |
19 | org.junit.jupiter
20 | junit-jupiter-api
21 | ${junit.jupiter.version}
22 | test
23 |
24 |
25 | org.junit.jupiter
26 | junit-jupiter-engine
27 | ${junit.jupiter.version}
28 | test
29 |
30 |
31 | org.testcontainers
32 | junit-jupiter
33 | test
34 |
35 |
36 | org.slf4j
37 | slf4j-simple
38 | 1.7.32
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.testcontainers
47 | testcontainers-bom
48 | 1.17.3
49 | pom
50 | import
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-compiler-plugin
61 | 3.8.1
62 |
63 | ${jdk.version}
64 | ${jdk.version}
65 | ${project.build.sourceEncoding}
66 |
67 |
68 |
69 | maven-surefire-plugin
70 | 2.22.2
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'prebuilt-nginx-generic-container'
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/src/main/java/com/bmuschko/testcontainers/NginxService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface NginxService {
4 | void ping();
5 | }
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/src/main/java/com/bmuschko/testcontainers/NginxServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.io.IOException;
4 | import java.net.URI;
5 | import java.net.http.HttpClient;
6 | import java.net.http.HttpRequest;
7 | import java.net.http.HttpResponse;
8 |
9 | public class NginxServiceImpl implements NginxService {
10 | private final String endpointUrl;
11 |
12 | public NginxServiceImpl(String endpointUrl) {
13 | this.endpointUrl = endpointUrl;
14 | }
15 |
16 | @Override
17 | public void ping() {
18 | try {
19 | HttpClient client = HttpClient.newHttpClient();
20 | HttpRequest request = HttpRequest.newBuilder(URI.create(endpointUrl)).build();
21 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
22 |
23 | if (response.statusCode() != 200) {
24 | throw new IllegalStateException("Cannot reach Ngix server: " + new String(response.body().getBytes()));
25 | }
26 | } catch (IOException | InterruptedException e) {
27 | throw new IllegalStateException("Cannot reach Ngix server");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/solution/prebuilt/src/test/java/com/bmuschko/testcontainers/NginxServiceIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.GenericContainer;
6 | import org.testcontainers.junit.jupiter.Container;
7 | import org.testcontainers.junit.jupiter.Testcontainers;
8 | import org.testcontainers.utility.DockerImageName;
9 |
10 | @Testcontainers
11 | public class NginxServiceIntegrationTest {
12 | private NginxService nginxService;
13 |
14 | @Container
15 | private final GenericContainer nginx = new GenericContainer(DockerImageName.parse("nginx:1.21.3")).withExposedPorts(80);
16 |
17 | @BeforeEach
18 | public void setUp() {
19 | String host = nginx.getHost();
20 | Integer port = nginx.getFirstMappedPort();
21 | String endpointUrl = "http://" + host + ":" + port;
22 | nginxService = new NginxServiceImpl(endpointUrl);
23 | }
24 |
25 | @Test
26 | public void testPing() {
27 | nginxService.ping();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/start/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | group = 'com.bmuschko'
4 | version = '1.0.0'
5 |
6 | sourceCompatibility = JavaVersion.VERSION_11
7 | targetCompatibility = JavaVersion.VERSION_11
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | def junitJupiterVersion = '5.8.1'
15 | testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
16 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
17 |
18 | testImplementation platform('org.testcontainers:testcontainers-bom:1.17.3')
19 | testImplementation 'org.testcontainers:junit-jupiter'
20 | testImplementation 'org.slf4j:slf4j-simple:1.7.32'
21 | }
22 |
23 | test {
24 | useJUnitPlatform()
25 | testLogging {
26 | showStandardStreams = true
27 | }
28 | }
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/04-generic-container/start/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | jar
6 |
7 | com.bmuschko
8 | on-the-fly-nginx-generic-container
9 | 1.0.0
10 |
11 |
12 | 11
13 | UTF-8
14 | 5.8.1
15 |
16 |
17 |
18 |
19 | org.junit.jupiter
20 | junit-jupiter-api
21 | ${junit.jupiter.version}
22 | test
23 |
24 |
25 | org.junit.jupiter
26 | junit-jupiter-engine
27 | ${junit.jupiter.version}
28 | test
29 |
30 |
31 | org.testcontainers
32 | junit-jupiter
33 | test
34 |
35 |
36 | org.slf4j
37 | slf4j-simple
38 | 1.7.32
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.testcontainers
47 | testcontainers-bom
48 | 1.17.3
49 | pom
50 | import
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-compiler-plugin
61 | 3.8.1
62 |
63 | ${jdk.version}
64 | ${jdk.version}
65 | ${project.build.sourceEncoding}
66 |
67 |
68 |
69 | maven-surefire-plugin
70 | 2.22.2
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'on-the-fly-nginx-generic-container'
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/src/main/java/com/bmuschko/testcontainers/NginxService.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | public interface NginxService {
4 | void ping();
5 | }
6 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/src/main/java/com/bmuschko/testcontainers/NginxServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import java.io.IOException;
4 | import java.net.URI;
5 | import java.net.http.HttpClient;
6 | import java.net.http.HttpRequest;
7 | import java.net.http.HttpResponse;
8 |
9 | public class NginxServiceImpl implements NginxService {
10 | private final String endpointUrl;
11 |
12 | public NginxServiceImpl(String endpointUrl) {
13 | this.endpointUrl = endpointUrl;
14 | }
15 |
16 | @Override
17 | public void ping() {
18 | try {
19 | HttpClient client = HttpClient.newHttpClient();
20 | HttpRequest request = HttpRequest.newBuilder(URI.create(endpointUrl)).build();
21 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
22 |
23 | if (response.statusCode() != 200) {
24 | throw new IllegalStateException("Cannot reach Ngix server: " + new String(response.body().getBytes()));
25 | }
26 | } catch (IOException | InterruptedException e) {
27 | throw new IllegalStateException("Cannot reach Ngix server");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/src/test/java/com/bmuschko/testcontainers/NginxServiceIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.bmuschko.testcontainers;
2 |
3 | import org.junit.jupiter.api.BeforeEach;
4 | import org.junit.jupiter.api.Test;
5 | import org.testcontainers.containers.GenericContainer;
6 | import org.testcontainers.images.builder.ImageFromDockerfile;
7 | import org.testcontainers.junit.jupiter.Container;
8 | import org.testcontainers.junit.jupiter.Testcontainers;
9 |
10 | import java.io.File;
11 |
12 | @Testcontainers
13 | public class NginxServiceIntegrationTest {
14 | private NginxService nginxService;
15 |
16 | @BeforeEach
17 | public void setUp() {
18 | String host = nginx.getHost();
19 | Integer port = nginx.getFirstMappedPort();
20 | String endpointUrl = "http://" + host + ":" + port;
21 | nginxService = new NginxServiceImpl(endpointUrl);
22 | }
23 |
24 | @Test
25 | public void testPing() {
26 | nginxService.ping();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/exercises/04-generic-container/start/src/test/resources/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.2
2 | RUN ["apk", "add", "--update", "nginx"]
3 | CMD ["nginx", "-g", "daemon off;"]
4 | EXPOSE 80
--------------------------------------------------------------------------------
/exercises/05-ci-github-actions/instructions.md:
--------------------------------------------------------------------------------
1 | # Exercise 5
2 |
3 | In this exercise, you will execute a Testcontainers test suite on a Continuous Integration product. The CI product of choice will be [GitHub Actions](https://github.com/features/actions).
4 |
5 | > **_NOTE:_** You can choose to run the build using Maven or Gradle. Pick the tool you are most comfortable with.
6 |
7 | 1. Create a new repository on GitHub. You can give it any name you like.
8 | 2. Follow the instructions in the GitHub repository to create a local repository.
9 | 3. Copy the solution of one of the previous exercises into the local repository.
10 | 4. Add the GitHub Actions workflow file at the appropriate location.
11 | 5. The GitHub Actions workflow should exercise the test Gradle or Maven as a step in the job.
12 | 6. Commit and push the code.
13 | 7. Observe the execution of the build in the "Actions" tab of your GitHub repository.
--------------------------------------------------------------------------------
/exercises/05-ci-github-actions/solution/images/github-actions-execution.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/05-ci-github-actions/solution/images/github-actions-execution.png
--------------------------------------------------------------------------------
/exercises/05-ci-github-actions/solution/images/github-repository-creation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/exercises/05-ci-github-actions/solution/images/github-repository-creation.png
--------------------------------------------------------------------------------
/exercises/05-ci-github-actions/solution/solution.md:
--------------------------------------------------------------------------------
1 | # Solution
2 |
3 | Create the repository on GitHub. In this case, the repository name is `redis-generic-container`. You can chose to set the repository visibility to "public" or "private".
4 |
5 | 
6 |
7 | Create a local directory with the same name the repository.
8 |
9 | ```
10 | $ mkdir redis-generic-container
11 | $ cd redis-generic-container
12 | ```
13 |
14 | Copy the contents of one of the solution directories e.g. `01-redis-generic-container/solution` into the directory. Create the GitHub Actions workflow in the file `.github/workflows/build.yaml` with the following contents.
15 |
16 | ```
17 | name: Build [Linux]
18 | on: [push, pull_request]
19 |
20 | jobs:
21 | build:
22 | name: Build
23 | runs-on: ubuntu-20.04
24 | steps:
25 | - uses: actions/checkout@v2
26 | - name: Setup Java
27 | uses: actions/setup-java@v1
28 | with:
29 | java-version: 11
30 | - name: Build with Gradle
31 | uses: gradle/gradle-build-action@v2
32 | with:
33 | arguments: build
34 | - name: Build with Maven
35 | run: ./mvnw test
36 | ```
37 |
38 | Initialize the directory as Git repository, commit the files, and push them to the remote repository. Note that the `git remote add origin` needs to point to your repository URL.
39 |
40 | ```
41 | $ git init
42 | $ git add .
43 | $ git commit . -m "first commit"
44 | $ git remote add origin git@github.com:bmuschko/redis-generic-container.git
45 | $ git push -u origin master
46 | ```
47 |
48 | You will see the build executions under the "Actions" tab of your Git repository.
49 |
50 | 
51 |
--------------------------------------------------------------------------------
/prerequisites/instructions.md:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 |
3 | Excercise will require the tooling listed below. Ensure that all of those tools have been installed before attending the training if you want to following along. The training does not reserve time for setting up or verifying the installed tools or their respective versions.
4 |
5 | ## Tools and Accounts
6 |
7 | * Java 11 OpenJDK and Docker Engine
8 | * A GitHub account
9 | * A Docker Hub account
10 |
11 | ## Recommended Skills
12 |
13 | * A basic understanding of Docker and the Java programming language
14 | * Hands-on experience with common Java frameworks and dependencies
15 | * Experience with writing test code with the test framework JUnit 4 or JUnit 5
--------------------------------------------------------------------------------
/slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bmuschko/testcontainers-integration-testing/71517bc44b9f659260a600590342aa33bb6b8b0d/slides.pdf
--------------------------------------------------------------------------------