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:
- Aerospike is not written in Java and cannot be easily embedded in our application.
- I want the developer to run tests on all popular platforms: Windows, OS X or Linux. Aerospike also provides binaries only for Linux.
- Tests can be run in parallel, therefore we need several servers?
- Each test should receive a clean database instance.
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:
')
- Running tests on a remote server takes significantly more time than running local tests. This is especially noticeable when working with slow Internet.
- There are problems with isolation, in case several developers decide to test the application at the same time.
- Quite often, a company's information security policy requires hiding servers behind corporate VPNs. The prospect of setting up a VPN client can discourage all desire to work from home.
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:
- Start / stop containers.
- Mount the aerospike.conf configuration file inside the container.
- Bind the container port to a free host port.
- 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.