├── .gitignore
├── README.md
├── examples
└── my-batis
│ ├── pom.xml
│ └── src
│ ├── main
│ └── java
│ │ └── br
│ │ └── eng
│ │ └── rafaelsouza
│ │ └── imdb
│ │ ├── Application.java
│ │ ├── domain
│ │ ├── Blog.java
│ │ └── BlogRepository.java
│ │ └── persistence
│ │ ├── BlogMapper.java
│ │ └── MyBatisUtil.java
│ └── test
│ └── java
│ └── br
│ └── eng
│ └── rafaelsouza
│ └── imdb
│ └── domain
│ └── BlogRepositoryTest.java
├── pom.xml
└── src
├── main
└── java
│ └── br
│ └── eng
│ └── rafaelsouza
│ └── imdb
│ ├── DatabaseConfig.java
│ ├── DatabaseStatus.java
│ ├── DockerDatabaseManager.java
│ ├── DockerPostgresql.java
│ ├── InMemoryDatabase.java
│ ├── Migration.java
│ └── junit
│ ├── DockerDatabaseConfig.java
│ ├── DockerDatabaseRunner.java
│ └── TestExecutionListener.java
└── test
└── java
└── br
└── eng
└── rafaelsouza
├── AppTest.java
├── SomeTest.java
└── imdb
└── DockerPostgresqlTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### Java ###
4 | *.class
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
14 |
15 | ### NetBeans ###
16 | nbproject/private/
17 | build/
18 | nbbuild/
19 | dist/
20 | nbdist/
21 | nbactions.xml
22 | nb-configuration.xml
23 | .nb-gradle/
24 |
25 |
26 | ### Maven ###
27 | target/
28 | pom.xml.tag
29 | pom.xml.releaseBackup
30 | pom.xml.versionsBackup
31 | pom.xml.next
32 | release.properties
33 | dependency-reduced-pom.xml
34 | buildNumber.properties
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # In Memory Docker Database
2 |
3 |
4 | In the Java world the most popular approach to test with in memory databases is using H2 or HSQLDB. These databases work well and can emulate some database syntax and features, but like most emulations, this is superficial, imperfect and doesn't cover important database features.
5 |
6 | In Memory Docker Database is a Java library that allow you to easily launch a docker container with a real database instance (like postgres, mysql and so on). This database will be running [in memory][1] and the process to do that is lightweight and quick, what is really useful for test purposes.
7 |
8 |
9 | ## Overview
10 |
11 | 
12 |
13 |
14 | ## Setup
15 |
16 | #### Pull the database images
17 | ```sh
18 | sudo docker pull postgres
19 | ```
20 |
21 |
22 | #### Enable Docker remote REST API:
23 | ```sh
24 | $ echo "DOCKER_OPTS='-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock'" > /etc/default/docker
25 | $ service docker restart
26 | ```
27 | [Read here more about it!][2]
28 |
29 |
30 | #### Maven dependencies:
31 |
32 | ```xml
33 |
34 |
35 | in-memory-docker-database-mvn-repo
36 | https://raw.github.com/rafaelpsouza/in-memory-docker-database/mvn-repo/
37 |
38 | true
39 | always
40 |
41 |
42 |
43 | ```
44 |
45 |
46 | ```xml
47 |
48 | br.eng.rafaelsouza
49 | in-memory-docker-database
50 | 1.0-SNAPSHOT
51 | test
52 |
53 | ```
54 |
55 |
56 | ## How to use
57 |
58 | Basically you need to add two annotations in your tests:
59 |
60 | ```java
61 | @RunWith(DockerDatabaseRunner.class)
62 | @DockerDatabaseConfig(type = DatabaseType.POSTGRES, port = 5432)
63 | public class BlogRepositoryTest {
64 | ```
65 |
66 | * **@RunWith(DockerDatabaseRunner.class)**: The test runner that will enable test listeners (start database before start tests and stop afterwards)
67 | * **@DockerDatabaseConfig(type = DatabaseType.POSTGRES, port = 5432)**: The database configuration. **type** is the database that you want to launch (only Postgres 9.4 is supported at this monent). **port** the port that the database you listen for connections.
68 |
69 | You can also see the example projects here:
70 | [examples][3]
71 |
72 |
73 |
74 |
75 | ### How to contribute
76 |
77 | Fell free to open issues and pull requests or send me an [e-mail][4] if you want to code it.
78 |
79 |
80 |
81 | [1]: http://www.martinfowler.com/bliki/InMemoryTestDatabase.html
82 | [2]: http://infoslack.com/devops/exploring-docker-remote-api/
83 | [3]: https://github.com/rafaelpsouza/in-memory-docker-database/tree/master/examples/
84 | [4]: mailto:rafael.bnc@gmail.com
85 |
--------------------------------------------------------------------------------
/examples/my-batis/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | br.eng.rafaelsouza
5 | my-batis
6 | 1.0-SNAPSHOT
7 | jar
8 |
9 | UTF-8
10 | 1.8
11 | 1.8
12 |
13 |
14 |
15 |
16 | org.mybatis
17 | mybatis
18 | 3.3.0
19 |
20 |
21 | org.postgresql
22 | postgresql
23 | 9.4-1201-jdbc41
24 |
25 |
26 | junit
27 | junit
28 | 4.10
29 | test
30 |
31 |
32 | br.eng.rafaelsouza
33 | in-memory-docker-database
34 | 1.0-SNAPSHOT
35 | test
36 | jar
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/examples/my-batis/src/main/java/br/eng/rafaelsouza/imdb/Application.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | import br.eng.rafaelsouza.imdb.persistence.MyBatisUtil;
4 | import br.eng.rafaelsouza.imdb.persistence.BlogMapper;
5 | import br.eng.rafaelsouza.imdb.domain.BlogRepository;
6 | import org.apache.ibatis.session.SqlSession;
7 |
8 | /**
9 | *
10 | * @author Rafael Souza
11 | */
12 | public class Application {
13 |
14 | public static void main(String[] args) {
15 | SqlSession session = MyBatisUtil.buildSqlSessionFactory().openSession();
16 | BlogRepository repository = new BlogRepository(session.getMapper(BlogMapper.class));
17 | System.out.println("Blog: " + repository.findById(1));
18 | repository.listAll().forEach(blog -> System.out.println("Blog: " + blog));
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/examples/my-batis/src/main/java/br/eng/rafaelsouza/imdb/domain/Blog.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.domain;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | *
7 | * @author Rafael Souza
8 | */
9 | public class Blog {
10 |
11 | private int id;
12 | private String name;
13 | private String author;
14 |
15 | public Blog() {
16 | }
17 |
18 | public Blog(int id, String name, String author) {
19 | this.id = id;
20 | this.name = name;
21 | this.author = author;
22 | }
23 |
24 | public int getId() {
25 | return id;
26 | }
27 |
28 | public void setId(int id) {
29 | this.id = id;
30 | }
31 |
32 | public String getName() {
33 | return name;
34 | }
35 |
36 | public void setName(String name) {
37 | this.name = name;
38 | }
39 |
40 | public String getAuthor() {
41 | return author;
42 | }
43 |
44 | public void setAuthor(String author) {
45 | this.author = author;
46 | }
47 |
48 | @Override
49 | public String toString() {
50 | return "Blog{" + "id=" + id + ", name=" + name + ", author=" + author + '}';
51 | }
52 |
53 | @Override
54 | public int hashCode() {
55 | int hash = 7;
56 | hash = 79 * hash + this.id;
57 | return hash;
58 | }
59 |
60 | @Override
61 | public boolean equals(Object obj) {
62 | if (obj == null) {
63 | return false;
64 | }
65 | if (getClass() != obj.getClass()) {
66 | return false;
67 | }
68 | final Blog other = (Blog) obj;
69 | if (this.id != other.id) {
70 | return false;
71 | }
72 | if (!Objects.equals(this.name, other.name)) {
73 | return false;
74 | }
75 | if (!Objects.equals(this.author, other.author)) {
76 | return false;
77 | }
78 | return true;
79 | }
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/examples/my-batis/src/main/java/br/eng/rafaelsouza/imdb/domain/BlogRepository.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.domain;
2 |
3 | import br.eng.rafaelsouza.imdb.persistence.BlogMapper;
4 | import br.eng.rafaelsouza.imdb.domain.Blog;
5 | import java.util.List;
6 |
7 | /**
8 | *
9 | * @author Rafael Souza
10 | */
11 | public class BlogRepository {
12 |
13 | BlogMapper blogMapper;
14 |
15 | public BlogRepository(BlogMapper blogMapper) {
16 | this.blogMapper = blogMapper;
17 | }
18 |
19 |
20 | public Blog findById(int id){
21 | return blogMapper.selectBlog(id);
22 | }
23 |
24 |
25 | public List listAll(){
26 | return blogMapper.select();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/examples/my-batis/src/main/java/br/eng/rafaelsouza/imdb/persistence/BlogMapper.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.persistence;
2 |
3 | import br.eng.rafaelsouza.imdb.domain.Blog;
4 | import java.util.List;
5 | import org.apache.ibatis.annotations.Select;
6 |
7 | /**
8 | *
9 | * @author Rafael Souza
10 | */
11 | public interface BlogMapper {
12 |
13 | @Select("SELECT * FROM blog WHERE id = #{id}")
14 | Blog selectBlog(int id);
15 |
16 | @Select("SELECT * FROM blog")
17 | List select();
18 | }
19 |
--------------------------------------------------------------------------------
/examples/my-batis/src/main/java/br/eng/rafaelsouza/imdb/persistence/MyBatisUtil.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.persistence;
2 |
3 | import javax.sql.DataSource;
4 | import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
5 | import org.apache.ibatis.mapping.Environment;
6 | import org.apache.ibatis.session.Configuration;
7 | import org.apache.ibatis.session.SqlSessionFactory;
8 | import org.apache.ibatis.session.SqlSessionFactoryBuilder;
9 | import org.apache.ibatis.transaction.TransactionFactory;
10 | import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
11 |
12 | /**
13 | *
14 | * @author Rafael Souza
15 | */
16 | public class MyBatisUtil {
17 |
18 | public static SqlSessionFactory buildSqlSessionFactory() {
19 | DataSource dataSource = new UnpooledDataSource("org.postgresql.Driver", "jdbc:postgresql://localhost:5432/postgres", "postgres", "");
20 | TransactionFactory transactionFactory = new JdbcTransactionFactory();
21 | Environment environment = new Environment("development", transactionFactory, dataSource);
22 | Configuration configuration = new Configuration(environment);
23 | configuration.addMapper(BlogMapper.class);
24 | SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
25 | return sqlSessionFactory;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/examples/my-batis/src/test/java/br/eng/rafaelsouza/imdb/domain/BlogRepositoryTest.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.domain;
2 |
3 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig;
4 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig.DatabaseType;
5 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseRunner;
6 | import br.eng.rafaelsouza.imdb.persistence.BlogMapper;
7 | import br.eng.rafaelsouza.imdb.persistence.MyBatisUtil;
8 | import java.sql.SQLException;
9 | import java.util.List;
10 | import org.apache.ibatis.session.SqlSession;
11 | import org.junit.After;
12 | import org.junit.Test;
13 | import static org.junit.Assert.*;
14 | import org.junit.Before;
15 | import org.junit.BeforeClass;
16 | import org.junit.runner.RunWith;
17 |
18 | /**
19 | *
20 | * @author Rafael Souza
21 | */
22 | @RunWith(DockerDatabaseRunner.class)
23 | @DockerDatabaseConfig(type = DatabaseType.POSTGRES, port = 5432)
24 | public class BlogRepositoryTest {
25 |
26 | SqlSession sqlSession;
27 |
28 | @BeforeClass
29 | public static void migrate() throws SQLException {
30 | String createTable = "CREATE TABLE blog(id serial NOT NULL, name character varying(50), author character varying(50), CONSTRAINT blog_pkey PRIMARY KEY (id));";
31 | String blog1 = "INSERT INTO blog (name, author) VALUES ('Blog1', 'Rafael');";
32 | String blog2 = "INSERT INTO blog (name, author) VALUES ('Blog2', 'ilegra');";
33 | SqlSession session = MyBatisUtil.buildSqlSessionFactory().openSession();
34 | session.getConnection().prepareCall(createTable).execute();
35 | session.getConnection().prepareCall(blog1).executeUpdate();
36 | session.getConnection().prepareCall(blog2).executeUpdate();
37 | session.commit();
38 | session.close();
39 | }
40 |
41 | @Before
42 | public void setUp() throws SQLException {
43 | sqlSession = MyBatisUtil.buildSqlSessionFactory().openSession();
44 | }
45 |
46 | @After
47 | public void after() {
48 | sqlSession.close();
49 | }
50 |
51 | @Test
52 | public void testFindById() throws SQLException, InterruptedException {
53 | BlogRepository blogRepository = new BlogRepository(sqlSession.getMapper(BlogMapper.class));
54 | Blog result = blogRepository.findById(1);
55 | assertEquals(new Blog(1, "Blog1", "Rafael"), result);
56 | }
57 |
58 | @Test
59 | public void testListAll() {
60 | BlogRepository blogRepository = new BlogRepository(sqlSession.getMapper(BlogMapper.class));
61 | List result = blogRepository.listAll();
62 | assertEquals(2, result.size());
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | br.eng.rafaelsouza
5 | in-memory-docker-database
6 | 1.0-SNAPSHOT
7 | jar
8 |
9 | UTF-8
10 | 1.8
11 | 1.8
12 | github
13 |
14 |
15 |
16 |
17 |
18 | maven-deploy-plugin
19 | 2.8.1
20 |
21 | internal.repo::default::file://${project.build.directory}/mvn-repo
22 |
23 |
24 |
25 | com.github.github
26 | site-maven-plugin
27 | 0.11
28 |
29 | Maven artifacts for ${project.version}
30 | true
31 | ${project.build.directory}/mvn-repo
32 | refs/heads/mvn-repo
33 |
34 | **/*
35 |
36 | in-memory-docker-database
37 | rafaelpsouza
38 |
39 |
40 |
41 |
42 |
43 | site
44 |
45 | deploy
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | internal.repo
55 | Temporary Staging Repository
56 | file://${project.build.directory}/mvn-repo
57 |
58 |
59 |
60 |
61 |
62 | com.github.docker-java
63 | docker-java
64 | 1.3.0
65 |
66 |
67 | junit
68 | junit
69 | 4.10
70 | compile
71 |
72 |
73 | org.mockito
74 | mockito-core
75 | 1.10.19
76 | test
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/DatabaseConfig.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | import java.util.Optional;
4 |
5 | /**
6 | *
7 | * @author Rafael Souza
8 | */
9 | public class DatabaseConfig {
10 |
11 | public enum DatabaseType {
12 | POSTGRES
13 | }
14 |
15 | private DatabaseType dbType;
16 | private Optional dbName;
17 | private Optional user;
18 | private Optional password;
19 | private Optional port;
20 |
21 | public DatabaseConfig(DatabaseType databaseType) {
22 | this.dbType = databaseType;
23 | this.dbName = Optional.empty();
24 | this.user = Optional.empty();
25 | this.password = Optional.empty();
26 | this.port = Optional.empty();;
27 | }
28 |
29 | public Optional getDbName() {
30 | return dbName;
31 | }
32 |
33 | public DatabaseConfig withDbName(String dbName) {
34 | if (!isEmpty(dbName)) {
35 | this.dbName = Optional.of(dbName);
36 | }
37 | return this;
38 | }
39 |
40 | public Optional getUser() {
41 | return user;
42 | }
43 |
44 | public DatabaseConfig withUser(String user) {
45 | if (!isEmpty(user)) {
46 | this.user = Optional.of(user);
47 | }
48 | return this;
49 | }
50 |
51 | public Optional getPassword() {
52 | return password;
53 | }
54 |
55 | public DatabaseConfig withPassword(String password) {
56 | if (!isEmpty(password)) {
57 | this.password = Optional.of(password);
58 | }
59 | return this;
60 | }
61 |
62 | public Optional getPort() {
63 | return port;
64 | }
65 |
66 | public DatabaseConfig withPort(Integer port) {
67 | if (port > 0)
68 | this.port = Optional.of(port);
69 | return this;
70 | }
71 |
72 | public DatabaseType getDbType() {
73 | return dbType;
74 | }
75 |
76 | private boolean isEmpty(String value) {
77 | return value == null || value.isEmpty();
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/DatabaseStatus.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | *
7 | * @author Rafael Souza
8 | */
9 | public class DatabaseStatus {
10 |
11 | private Boolean started;
12 | private String containerId;
13 | private int port;
14 |
15 | public DatabaseStatus(Boolean started) {
16 | this.started = started;
17 | }
18 |
19 | public DatabaseStatus(Boolean started, String containerId, int port) {
20 | this.started = started;
21 | this.containerId = containerId;
22 | this.port = port;
23 | }
24 |
25 | public Boolean getStarted() {
26 | return started;
27 | }
28 |
29 | public void setStarted(Boolean started) {
30 | this.started = started;
31 | }
32 |
33 | public String getContainerId() {
34 | return containerId;
35 | }
36 |
37 | public void setContainerId(String containerId) {
38 | this.containerId = containerId;
39 | }
40 |
41 | public int getExposedPort() {
42 | return port;
43 | }
44 |
45 | public void setExposedPort(int exposedPort) {
46 | this.port = exposedPort;
47 | }
48 |
49 | @Override
50 | public int hashCode() {
51 | int hash = 5;
52 | hash = 59 * hash + Objects.hashCode(this.containerId);
53 | return hash;
54 | }
55 |
56 | @Override
57 | public boolean equals(Object obj) {
58 | if (obj == null) {
59 | return false;
60 | }
61 | if (getClass() != obj.getClass()) {
62 | return false;
63 | }
64 | final DatabaseStatus other = (DatabaseStatus) obj;
65 | if (!Objects.equals(this.started, other.started)) {
66 | return false;
67 | }
68 | if (!Objects.equals(this.containerId, other.containerId)) {
69 | return false;
70 | }
71 | if (this.port != other.port) {
72 | return false;
73 | }
74 | return true;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/DockerDatabaseManager.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | import com.github.dockerjava.core.DockerClientBuilder;
4 |
5 | /**
6 | *
7 | * @author Rafael Souza
8 | */
9 | public class DockerDatabaseManager {
10 |
11 | private static InMemoryDatabase dbInstance;
12 |
13 | private DockerDatabaseManager() {}
14 |
15 | public static void startDb(DatabaseConfig databaseConfig) {
16 | if (dbInstance == null) {
17 | System.out.println("#################### startign database");
18 | dbInstance = new DockerPostgresql(DockerClientBuilder.getInstance("http://localhost:2375").build(), databaseConfig);
19 | dbInstance.start();
20 | }
21 | }
22 |
23 | public static void stop() {
24 | if (dbInstance != null) {
25 | System.out.println("#################### stoping database");
26 | dbInstance.stop();
27 | dbInstance = null;
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/DockerPostgresql.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | import com.github.dockerjava.api.DockerClient;
4 | import com.github.dockerjava.api.command.CreateContainerResponse;
5 | import com.github.dockerjava.api.model.ExposedPort;
6 | import com.github.dockerjava.api.model.Ports;
7 | import java.util.logging.Level;
8 | import java.util.logging.Logger;
9 |
10 | /**
11 | *
12 | * @author Rafael Souza
13 | */
14 | public class DockerPostgresql implements InMemoryDatabase {
15 |
16 | private final DockerClient dockerClient;
17 | private String containerId;
18 | private final DatabaseConfig config;
19 |
20 | public DockerPostgresql(DockerClient dockerClient, DatabaseConfig config) {
21 | this.dockerClient = dockerClient;
22 | this.config = config;
23 | }
24 |
25 | @Override
26 | public DatabaseStatus start() {
27 | try {
28 | int databasePort = config.getPort().orElse(5432);
29 | Ports portBindings = new Ports();
30 | portBindings.bind(ExposedPort.tcp(5432), Ports.Binding(databasePort));
31 | CreateContainerResponse createContainerResponse = dockerClient.createContainerCmd("postgres")
32 | .withPortBindings(portBindings)
33 | .exec();
34 |
35 | containerId = createContainerResponse.getId();
36 | dockerClient.startContainerCmd(containerId).exec();
37 | Thread.sleep(4000); //Time waiting database, change fora a database check
38 | return new DatabaseStatus(true, containerId, databasePort);
39 | } catch (InterruptedException ex) {
40 | //TODO Log
41 | //Logger.getLogger(DockerPostgresql.class.getName()).log(Level.SEVERE, null, ex);
42 | }
43 | return new DatabaseStatus(false);
44 | }
45 |
46 | @Override
47 | public void migrate(Migration migration) {
48 | throw new UnsupportedOperationException("Not supported yet.");
49 | }
50 |
51 | @Override
52 | public void stop() {
53 | dockerClient.stopContainerCmd(containerId).exec();
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/InMemoryDatabase.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | /**
4 | *
5 | * @author Rafael Souza
6 | */
7 | public interface InMemoryDatabase {
8 |
9 | public DatabaseStatus start();
10 | public void migrate(Migration migration);
11 | public void stop();
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/Migration.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb;
2 |
3 | /**
4 | *
5 | * @author Rafael Souza
6 | */
7 | public interface Migration {
8 |
9 | public void apply();
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/junit/DockerDatabaseConfig.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.junit;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Inherited;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | *
11 | * @author Rafael Souza
12 | */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.TYPE)
15 | @Inherited
16 | public @interface DockerDatabaseConfig {
17 |
18 | public enum DatabaseType {
19 | POSTGRES
20 | }
21 |
22 | DatabaseType type();
23 | String database() default "";
24 | String user() default "";
25 | String password() default "";
26 | int port() default -1;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/junit/DockerDatabaseRunner.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.junit;
2 |
3 | import br.eng.rafaelsouza.imdb.DatabaseConfig;
4 | import br.eng.rafaelsouza.imdb.DockerDatabaseManager;
5 | import org.junit.runner.notification.RunNotifier;
6 | import org.junit.runners.BlockJUnit4ClassRunner;
7 | import org.junit.runners.model.InitializationError;
8 |
9 | /**
10 | *
11 | * @author Rafael Souza
12 | */
13 | public class DockerDatabaseRunner extends BlockJUnit4ClassRunner {
14 |
15 | public DockerDatabaseRunner(Class> klass) throws InitializationError {
16 | super(klass);
17 | }
18 |
19 | @Override
20 | public void run(RunNotifier notifier) {
21 | notifier.addFirstListener(new TestExecutionListener());
22 | DockerDatabaseManager.startDb(getConfigByAnnotation(this.getDescription().getTestClass().getAnnotationsByType(DockerDatabaseConfig.class)));
23 | super.run(notifier);
24 | }
25 |
26 | private DatabaseConfig getConfigByAnnotation(DockerDatabaseConfig[] configAnnotations) {
27 | if (configAnnotations.length > 0) {
28 | DockerDatabaseConfig annotation = configAnnotations[0];
29 | return new DatabaseConfig(DatabaseConfig.DatabaseType.POSTGRES)
30 | .withDbName(annotation.database())
31 | .withUser(annotation.user())
32 | .withPassword(annotation.password())
33 | .withPort(annotation.port());
34 | }
35 | return new DatabaseConfig(DatabaseConfig.DatabaseType.POSTGRES);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/br/eng/rafaelsouza/imdb/junit/TestExecutionListener.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza.imdb.junit;
2 |
3 | import br.eng.rafaelsouza.imdb.DockerDatabaseManager;
4 | import org.junit.runner.Result;
5 | import org.junit.runner.notification.RunListener;
6 |
7 | /**
8 | *
9 | * @author Rafael Souza
10 | */
11 | class TestExecutionListener extends RunListener {
12 |
13 | @Override
14 | public void testRunFinished(Result result) throws Exception {
15 | DockerDatabaseManager.stop();
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/br/eng/rafaelsouza/AppTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package br.eng.rafaelsouza;
7 |
8 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig;
9 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig.DatabaseType;
10 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseRunner;
11 | import org.junit.Test;
12 | import org.junit.runner.RunWith;
13 |
14 | /**
15 | *
16 | * @author Rafael Souza
17 | */
18 | @RunWith(DockerDatabaseRunner.class)
19 | @DockerDatabaseConfig(type = DatabaseType.POSTGRES, port = 5432)
20 | public class AppTest {
21 |
22 |
23 | @Test
24 | public void test1() {
25 | System.out.println("RUNNIN TEST: AppTest.test1()");
26 | }
27 |
28 | @Test
29 | public void test2() {
30 | System.out.println("RUNNIN TEST: AppTest.test2()");
31 | }
32 |
33 | @Test
34 | public void test3() {
35 | System.out.println("RUNNIN TEST: AppTest.test3()");
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/br/eng/rafaelsouza/SomeTest.java:
--------------------------------------------------------------------------------
1 | package br.eng.rafaelsouza;
2 |
3 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig;
4 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseConfig.DatabaseType;
5 | import br.eng.rafaelsouza.imdb.junit.DockerDatabaseRunner;
6 | import org.junit.BeforeClass;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | /**
11 | *
12 | * @author Rafael Souza
13 | */
14 | @RunWith(DockerDatabaseRunner.class)
15 | @DockerDatabaseConfig(type = DatabaseType.POSTGRES, port = 5432)
16 | public class SomeTest {
17 |
18 | @BeforeClass
19 | public static void before(){
20 | System.out.println("BEFORE CLASS");
21 | }
22 |
23 | @Test
24 | public void test1() {
25 | System.out.println("RUNNIN TEST: SomeTest.test1()");
26 | }
27 |
28 | @Test
29 | public void test2() {
30 | System.out.println("RUNNIN TEST: SomeTest.test1()");
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/br/eng/rafaelsouza/imdb/DockerPostgresqlTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package br.eng.rafaelsouza.imdb;
7 |
8 | import com.github.dockerjava.api.ConflictException;
9 | import com.github.dockerjava.api.DockerClient;
10 | import com.github.dockerjava.api.NotFoundException;
11 | import com.github.dockerjava.api.command.CreateContainerCmd;
12 | import com.github.dockerjava.api.command.CreateContainerResponse;
13 | import com.github.dockerjava.api.command.StartContainerCmd;
14 | import com.github.dockerjava.api.command.StopContainerCmd;
15 | import com.github.dockerjava.api.model.Ports;
16 | import org.junit.Test;
17 | import static org.junit.Assert.*;
18 | import static org.mockito.Mockito.*;
19 |
20 | /**
21 | *
22 | * @author Rafael Souza
23 | */
24 | public class DockerPostgresqlTest {
25 |
26 | @Test
27 | public void testStartDefaultConfig() {
28 | DockerClient client = mockedClient("aabb11");
29 | DockerPostgresql postgresInstance = new DockerPostgresql(client, new DatabaseConfig(DatabaseConfig.DatabaseType.POSTGRES));
30 | DatabaseStatus status = postgresInstance.start();
31 | assertEquals(new DatabaseStatus(true, "aabb11", 5432), status);
32 | }
33 |
34 | @Test
35 | public void testStartCustonPort() {
36 | DockerClient client = mockedClient("1111");
37 | DockerPostgresql postgresInstance = new DockerPostgresql(client, new DatabaseConfig(DatabaseConfig.DatabaseType.POSTGRES).withPort(1000));
38 | DatabaseStatus status = postgresInstance.start();
39 | assertEquals(new DatabaseStatus(true, "1111", 1000), status);
40 | }
41 |
42 | @Test
43 | public void testStop() {
44 | DockerClient client = mockedClient("2222");
45 | DockerPostgresql postgresInstance = new DockerPostgresql(client, new DatabaseConfig(DatabaseConfig.DatabaseType.POSTGRES).withPort(1000));
46 | DatabaseStatus status = postgresInstance.start();
47 | postgresInstance.stop();
48 | verify(client, times(1)).stopContainerCmd(status.getContainerId());
49 | }
50 |
51 | private DockerClient mockedClient(String createdId) {
52 | DockerClient client = mock(DockerClient.class);
53 | CreateContainerCmd containerCmd = mockedCreateContainerCmd(createdId);
54 | when(client.createContainerCmd("postgres")).thenReturn(containerCmd);
55 | StartContainerCmd startContainerCmd = mockedStartContainerCmd(createdId);
56 | when(client.startContainerCmd(createdId)).thenReturn(startContainerCmd);
57 | when(client.stopContainerCmd(any())).thenReturn(mock(StopContainerCmd.class));
58 | return client;
59 | }
60 |
61 | private CreateContainerCmd mockedCreateContainerCmd(String createdId) throws NotFoundException, ConflictException {
62 | CreateContainerResponse containerResponse = mockedCreateContainerResponse(createdId);
63 | CreateContainerCmd containerCmd = mock(CreateContainerCmd.class);
64 | when(containerCmd.withPortBindings(any(Ports.class))).thenReturn(containerCmd);
65 | when(containerCmd.exec()).thenReturn(containerResponse);
66 | return containerCmd;
67 | }
68 |
69 | private CreateContainerResponse mockedCreateContainerResponse(String createdId) {
70 | CreateContainerResponse containerResponse = mock(CreateContainerResponse.class);
71 | when(containerResponse.getId()).thenReturn(createdId);
72 | return containerResponse;
73 | }
74 |
75 | private StartContainerCmd mockedStartContainerCmd(String createdId) {
76 | StartContainerCmd startContainerCmd = mock(StartContainerCmd.class);
77 | when(startContainerCmd.getContainerId()).thenReturn(createdId);
78 | return startContainerCmd;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------