📜 ⬆️ ⬇️

How docker helped us in writing tests

In order to show you ads - we at GetIntent must be confident in the steady and reliable operation of our advertising platform. The reliability of the system consists of many components: the type of hardware used, the system / network configuration, and the application architecture. Making changes to fairly complex, distributed applications always carries a risk.
The developers, for their part, are trying to minimize these risks and write tests: unit and integration. Writing unit tests is usually not difficult. With integration tests, depending on their sophistication, the situation is more complicated.



When tests use Tomcat or Jetty, this poses no problems: these servers are written in java and can easily be built into tests. But, for example, we use Aerospike and when we want to test interaction with this database, the following difficulties await us:


Often, a common test environment is used for these purposes, for example, a remote server on which Aerospike is already configured and on which some tests can be run. However, the approach has certain disadvantages:
')

Alternatively, you need to prepare a local environment for tests, write long instructions for installing and configuring Aerospike for three platforms (Win / Mac / Linux). But there is another option - use automation tools such as Docker.

Docker is a system for deploying and managing applications in an isolated environment (containers). It is built on the principles of the client-server architecture, the docker client is for all major OSs, and the docker daemon only works on Linux systems. However, this is not a problem: using docker-machine, you can run docker on Windows / OS X (albeit on a virtual host). So, in order to run the tests, the developer needs to have the docker client configured on the machine — you can verify this with the command: docker run hello-world. For Windows and OS X, you will need to install docker-machine .

Embedded aerospike


To use Aerospike in integration tests, we wrote a wrapper for docker and docker-machine . She can:

  1. Start / stop containers.
  2. Mount the aerospike.conf configuration file inside the container.
  3. Bind the container port to a free host port.
  4. Start / stop the Docker Machine if the tests are run on Windows / OS X.

To manage containers, we use the docker-java API client - a popular Java API client for Docker. To start the Aerospike server inside the Docker container, configure port forwarding and mount the configuration file, run the following command:

docker run -d -P -p 3000:3000 -v path/to/aerospike.conf:/etc/aerospike/aerospike.conf --name aerospike aerospike 

But the code that does the same thing using Docker Remote Api

 ExposedPort tcp3000 = ExposedPort.tcp(3000); Volume volume = new Volume("/etc/aerospike/aerospike.conf"); Ports portBindings = new Ports(); portBindings.bind(tcp3000, Ports.binding(aerospikePort)); CreateContainerResponse container = dockerClient.createContainerCmd(IMAGE_ID) .withExposedPorts(tcp3000) .withPortBindings(portBindings) .withBinds(new Bind(aerospikeConfPath, volume, AccessMode.ro)) .exec(); dockerClient.startContainerCmd(container.getId()) .exec(); 

More details can be viewed in the class AerospikeServer .

We write a test


Let's look at an example of an integration test using embedded-aerospike. Suppose we have a class SimpleAerospikeClient, which can store and retrieve user segments by identifier.

  public Set getSegments(Long userId); public void addSegments(Long userId, Set segments); 

View the full class.

We write a test that checks the correctness of the implementation of these methods.

First you need to configure and start the server.

  @BeforeMethod public void setUp() throws Exception { aerospikeServer = AerospikeServer.builder() .aerospikeConfPath(getClass().getResource("/aerospike.conf").getFile()) .dockerConfig(DockerClientConfig.createDefaultConfigBuilder().build()) .build(); aerospikeServer.start(); } 

We check that the data is correctly recorded and read from the database.

  @Test public void test() { long userId = ThreadLocalRandom.current().nextLong(); aerospikeClient.addSegments(userId, new HashSet<Integer>() {{ add(150); add(151); }}); Set<Integer> segments = aerospikeClient.getSegments(userId); Assert.assertEquals(segments.size(), 2); Assert.assertTrue(segments.contains(150)); Assert.assertTrue(segments.contains(151)); } 

Do not forget to stop and delete the containers that were created during the tests.

  @AfterMethod public void tearDown() throws Exception { aerospikeServer.stop(); } 

Conclusion


This approach allows you to run integration tests on the developer's machine, which means that, firstly, you do not need to spend resources on maintaining test servers, and secondly, you can develop and test the application without access to the infrastructure. We looked at an example of working with Aerospike, but it is obvious that this way you can test the interaction of your program with any services.

The authors of the article are kiruxan and zeliboba69.

Source: https://habr.com/ru/post/301868/


All Articles