Skip to content

Commit

Permalink
Improve the documentation of integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robertmrk committed Nov 28, 2018
1 parent 51a4d4c commit 2138689
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 5 deletions.
42 changes: 41 additions & 1 deletion tests/integration/helpers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Helper classes for integration tests"""
import time
from urllib.request import urlopen
from http import HTTPStatus
Expand All @@ -7,54 +8,91 @@


class DockerContainer:
"""Docker container encapsulation
If the container with the given *name* doesn't exists yet it'll be created.
"""
def __init__(self, image_name, name, container_port, host_port):
"""
:param str image_name: A docker image name with or without a tag
:param name: Container name
:param container_port: TCP port exposed by the container
:param host_port: TCP port on the host where the exposed container \
port gets published
"""
#: docker image name with or without a tag
self.image_name = image_name
#: container name
self.name = name
#: TCP port exposed by the container
self.contaner_port = container_port
#: TCP port on the host where the exposed container port gets published
self.host_port = host_port
#: container instance
self._container = None
#: docker client
self.client = docker.from_env()

self._ensure_exists()

def _ensure_exists(self):
"""Create the container if it doesn't already exists"""
# try to find the container by name and image
filter = {
"name": self.name,
"ancestor": self.image_name
}
results = self.client.containers.list(all=True, filters=filter)

# if it doesn't exists then create it
if not results:
self._container = self.client.containers.run(
name=self.name,
image=self.image_name,
ports={f"{self.contaner_port}/tcp": self.host_port},
detach=True
)
# if it exists assign it to the instance attribute
else:
self._container = results[0]

def _wait_for_state(self, state):
"""Wait until the state of the container becomes the given *state*
value
"""
while self._container.status != state:
time.sleep(1)
self._container.reload()

def _ensure_running(self):
"""Get the container into the ``running`` state if it's in a different
one"""
# make sure the container exists
self._ensure_exists()

# if the container is not running
if self._container.status != "running":
# if the container is stopped then start it
if self._container.status == "exited":
self._container.start()
# if the container is paused then resume it
if self._container.status == "paused":
self._container.unpause()

self._wait_for_state("running")

def _get_url(self):
"""Return the url of the container's service"""
return f"http://localhost:{self.host_port}"

def ensure_reacheable(self):
def ensure_reachable(self):
"""Start the container and make sure it's exposed service is reachable
"""
# make sure the container is running
self._ensure_running()
url = self._get_url()

# query the service's URL until it can be reached
status = None
with suppress(Exception):
status = urlopen(url).status
Expand All @@ -66,9 +104,11 @@ def ensure_reacheable(self):
return url

def stop(self):
"""Stop the container"""
self._container.stop()
self._wait_for_state("exited")

def pause(self):
"""Pause the container"""
self._container.pause()
self._wait_for_state("paused")
20 changes: 16 additions & 4 deletions tests/integration/test_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
import asyncio

from asynctest import TestCase, TestSuite
Expand All @@ -9,24 +8,37 @@


class BaseTestCase(TestCase):
#: name of the docker image containing the CometD demo services
IMAGE_NAME = "robertmrk/cometd-demos:alpine"
#: a name for the container
CONTAINER_NAME = "aiocometd-integration-test"
#: TCP port exposed by the container
CONTAINER_PORT = 8080
#: TCP port where the container's port will be published
HOST_PORT = 9999
#: URL of the CometD service
COMETD_URL = f"http://localhost:{HOST_PORT}/cometd"
#: CometD connection type
CONNECTION_TYPE = None

#: container instance
container = None

#: name of the chat room
CHAT_ROOM = "demo"
#: channel where the room's messages get published
CHAT_ROOM_CHANNEL = "/chat/" + CHAT_ROOM
#: channel where the room's memeber get published
MEMBERS_CHANGED_CHANNEL = "/members/" + CHAT_ROOM
#: channel for adding user's to the room
MEMBERS_CHANNEL = "/service/members"
#: name of the first user
USER_NAME1 = "user1"
#: name of the second user
USER_NAME2 = "user2"

def setUp(self):
self.container.ensure_reacheable()
self.container.ensure_reachable()

@classmethod
def setUpClass(cls):
Expand Down Expand Up @@ -214,7 +226,7 @@ async def test_revover_on_server_restart(self):
await asyncio.sleep(3)

# start the service
self.container.ensure_reacheable()
self.container.ensure_reachable()
# give a few seconds for the client to recover the connection
await asyncio.sleep(3)

Expand Down Expand Up @@ -247,7 +259,7 @@ async def test_recover_on_temporary_network_outage(self):
await asyncio.sleep(3)

# start the service
self.container.ensure_reacheable()
self.container.ensure_reachable()
# give a few seconds for the client to recover the connection
await asyncio.sleep(3)

Expand Down

0 comments on commit 2138689

Please sign in to comment.