Merge pull request 'Create unit tests' (#3) from testing into master
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Torma Kristóf 2020-03-31 21:49:57 +02:00
commit bfbbb3f089
8 changed files with 269 additions and 21 deletions

View File

@ -4,7 +4,7 @@ name: default
steps: steps:
- name: static_analysis - name: static_analysis
image: python:3 image: python:3.8
commands: commands:
- pip3 install pylint bandit mccabe - pip3 install pylint bandit mccabe
- pip3 install -r requirements.txt - pip3 install -r requirements.txt
@ -13,6 +13,12 @@ steps:
- find . -name "*.py" -exec python3 -m mccabe --min 3 '{}' + || if [ $? -eq 1 ]; then echo "you fail"; fi - find . -name "*.py" -exec python3 -m mccabe --min 3 '{}' + || if [ $? -eq 1 ]; then echo "you fail"; fi
- bandit -r . + || if [ $? -eq 1 ]; then echo "you fail"; fi - bandit -r . + || if [ $? -eq 1 ]; then echo "you fail"; fi
- name: unit_test
image: python:3.8
commands:
- pip3 install -r requirements.txt
- pytest test.py
- name: build - name: build
image: docker:stable-dind image: docker:stable-dind
volumes: volumes:

View File

@ -1,4 +1,4 @@
FROM python:3 FROM python:3.8
WORKDIR /app WORKDIR /app

8
app.py
View File

@ -1,4 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
import os
import random import random
import uuid import uuid
import logging import logging
@ -21,12 +23,14 @@ sentry_sdk.init("https://3fa5ae886ba1489092ad49a93cb419c1@sentry.kmlabz.com/9")
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
KNOWNCONSUMER = os.getenv("PRODUCER_KNOWNCONSUMER",'10.69.42.1')
if __name__ == "__main__": if __name__ == "__main__":
LOGGER.info("Producer started") LOGGER.info("Producer started")
generateduuid = str(uuid) generateduuid = str(uuid)
communicator = Communicator(currentconsumer=KNOWNCONSUMER, uuid=generateduuid)
LOGGER.debug(f"My uuid is {generateduuid}") LOGGER.debug(f"My uuid is {generateduuid}")
consumerlocator = ConsumerLocator(uuid=generateduuid) consumerlocator = ConsumerLocator(uuid=generateduuid, communicator=communicator)
communicator = Communicator(consumerlocator=consumerlocator,uuid=generateduuid)
messagesender = MessageSender(communicator=communicator) messagesender = MessageSender(communicator=communicator)
while True: while True:

View File

@ -1,8 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
import logging import logging
import random
import requests import requests
from consumerlocator import ConsumerLocator
""" """
Communicator module Communicator module
@ -21,13 +19,13 @@ class Communicator:
Class handling low level communication with consumers. Class handling low level communication with consumers.
""" """
def __init__(self, consumerlocator: ConsumerLocator, uuid: str): def __init__(self, currentconsumer: str, uuid: str):
""" """
Initialize object Initialize object
:param consumerlocator: :param consumerlocator:
:param uuid: :param uuid:
""" """
self.consumerlocator=consumerlocator self.currenctconsumer=currentconsumer
self.uuid = uuid self.uuid = uuid
def sendmessage(self, message: str) -> None: def sendmessage(self, message: str) -> None:
@ -36,7 +34,7 @@ class Communicator:
:param message: :param message:
:return: none :return: none
""" """
currentconsumer=self.consumerlocator.getcurrentconsumer() currentconsumer=self.currenctconsumer
LOGGER.debug(f"Sending message to {currentconsumer}") LOGGER.debug(f"Sending message to {currentconsumer}")
requests.post(f'http://{currentconsumer}/log', json={'uuid': self.uuid, 'message': message}) requests.post(f'http://{currentconsumer}/log', json={'uuid': self.uuid, 'message': message})
@ -45,7 +43,7 @@ class Communicator:
Get the list of available consumer from the current primary consumer. Get the list of available consumer from the current primary consumer.
:return: :return:
""" """
currentconsumer = self.consumerlocator.getcurrentconsumer() currentconsumer = self.currenctconsumer
response = requests.get(f'http://{currentconsumer}/consumer') response = requests.get(f'http://{currentconsumer}/consumer')
json = response.json() json = response.json()
LOGGER.debug(f"List of currently available consumers: {json}") LOGGER.debug(f"List of currently available consumers: {json}")
@ -56,9 +54,13 @@ class Communicator:
Readiness probe primary consumer. Readiness probe primary consumer.
:return: :return:
""" """
currentconsumer = self.consumerlocator.getcurrentconsumer() currentconsumer = self.currenctconsumer
try:
response = requests.get(f'http://{currentconsumer}/consumer') response = requests.get(f'http://{currentconsumer}/consumer')
isavailable = response.status_code == 200 isavailable = response.status_code == 200
except Exception as e:
LOGGER.exception(e)
isavailable = False
LOGGER.debug(f"Current consumer availability: {isavailable}") LOGGER.debug(f"Current consumer availability: {isavailable}")
return isavailable return isavailable
@ -68,7 +70,19 @@ class Communicator:
:param consumer: :param consumer:
:return: :return:
""" """
try:
response = requests.get(f'http://{consumer}/consumer') response = requests.get(f'http://{consumer}/consumer')
isavailable = response.status_code == 200 isavailable = response.status_code == 200
except Exception as e:
LOGGER.exception(e)
isavailable = False
LOGGER.debug(f"Consumer {consumer} availability: {isavailable}") LOGGER.debug(f"Consumer {consumer} availability: {isavailable}")
return isavailable return isavailable
def set_currentconsumer(self,currenctconsumer):
"""
Set current consumer
:param currenctconsumer:
:return:
"""
self.currenctconsumer=currenctconsumer

View File

@ -13,6 +13,7 @@ __copyright__ = "Copyright 2020, GoldenPogácsa Team"
__module_name__ = "consumerlocator" __module_name__ = "consumerlocator"
__version__text__ = "1" __version__text__ = "1"
KNOWNCONSUMER = os.getenv("PRODUCER_KNOWNCONSUMER",'10.69.42.1')
class ConsumerLocator: class ConsumerLocator:
@ -20,13 +21,13 @@ class ConsumerLocator:
Manages the list of consumers. Manages the list of consumers.
""" """
def __init__(self, uuid: str): def __init__(self, uuid: str, communicator: Communicator):
""" """
Initialize class. Initialize class.
""" """
self.consumerlist = [{"Host": os.environ["KnownConsumer"], "State": True, "LastOk": datetime.datetime.now()}] self.consumerlist = [{"Host": KNOWNCONSUMER, "State": True, "LastOk": datetime.datetime.now()}]
self.currentconsumer = self.consumerlist[0] self.currentconsumer = self.consumerlist[0]
self.communicator = Communicator(consumerlocator=self,uuid=uuid) self.communicator = communicator
def learnconsumerlist(self) -> None: def learnconsumerlist(self) -> None:
"""" """"
@ -82,6 +83,7 @@ class ConsumerLocator:
self.learnconsumerlist() self.learnconsumerlist()
if self.currentconsumer is not None: if self.currentconsumer is not None:
self.communicator.set_currentconsumer(self.currentconsumer["Host"])
return self.currentconsumer["Host"] return self.currentconsumer["Host"]
else: else:
return None return None

View File

@ -28,10 +28,10 @@ class MessageSender:
""" """
self.communicator = communicator self.communicator = communicator
def randomstring(self, stringLength) -> str: def randomstring(self, stringlength: int) -> str:
"""Generate a random string of fixed length """ """Generate a random string of fixed length """
letters = string.ascii_lowercase letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength)) return ''.join(random.choice(letters) for i in range(stringlength))
def sendmessage(self, message: str = "") -> None: def sendmessage(self, message: str = "") -> None:
""" """

View File

@ -1,2 +1,5 @@
sentry_sdk sentry_sdk
requests requests
pytest
pytest-mock
pytest-httpserver

219
test.py Normal file
View File

@ -0,0 +1,219 @@
#!/usr/bin/env python
import re
import consumerlocator
import communicator
import messagesender
"""
Unit tests for producer module.
"""
__author__ = "@tormakris"
__copyright__ = "Copyright 2020, GoldenPogácsa Team"
__module_name__ = "test"
__version__text__ = "1"
generateduuid = 'c959ad81-58f9-4445-aab4-8f3d68aee1ad'
def test_generate_string(mocker):
mocker.patch('communicator.Communicator')
comm = communicator.Communicator(
currentconsumer="localhost",
uuid=generateduuid)
mess = messagesender.MessageSender(communicator=comm)
msg = mess.randomstring(stringlength=32)
assert isinstance(msg, str)
assert len(msg) == 32
def test_sendmessage(httpserver):
httpserver.expect_oneshot_request(
uri="/log",
method='POST',
data="{\"uuid\": \"c959ad81-58f9-4445-aab4-8f3d68aee1ad\", \"message\": \"SENDING\"}").respond_with_json(
{
"test": "ok"})
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
mess = "SENDING"
ret = comm.sendmessage(message=mess)
assert ret is None
def test_send_message(mocker):
mocker.patch('communicator.Communicator')
comm = communicator.Communicator(
currentconsumer="127.0.0.1",
uuid=generateduuid)
mess = messagesender.MessageSender(communicator=comm)
messa = "SENDING"
msg = mess.sendmessage(message=messa)
assert msg is None
def test_discoveravailableconsumers(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
ret = comm.discoveravailableconsumers()
assert isinstance(ret, list)
assert ret == ["10.69.42.1", "10.10.10.10", "10.20.30.40"]
def test_isconsumeravailable(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
ret = comm.isconsumeravailable()
assert isinstance(ret, bool)
assert ret
ret2 = comm.isconsumeravailable()
assert isinstance(ret2, bool)
assert ret2 == False
comm2 = communicator.Communicator(
currentconsumer="127.0.0.1:69",
uuid=generateduuid)
ret3 = comm2.isconsumeravailable()
assert isinstance(ret3, bool)
assert ret3 == False
def test_checkconsumer(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer="127.0.0.1",
uuid=generateduuid)
ret = comm.checkconsumer(f"127.0.0.1:{port}")
assert isinstance(ret, bool)
assert ret
ret2 = comm.checkconsumer(f"127.0.0.1:{port}")
assert isinstance(ret2, bool)
assert ret2 == False
comm2 = communicator.Communicator(
currentconsumer="127.0.0.1",
uuid=generateduuid)
ret3 = comm2.checkconsumer(f"127.0.0.1:{port}")
assert isinstance(ret3, bool)
assert ret3 == False
def test_setcurrentconsumer():
comm = communicator.Communicator(
currentconsumer="127.0.0.1",
uuid=generateduuid)
comm.set_currentconsumer("10.69.42.1")
assert comm.currenctconsumer == "10.69.42.1"
def test_learnconsumerlist(httpserver):
httpserver.expect_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
consumerlocator.KNOWNCONSUMER = f"127.0.0.1:{port}"
locator = consumerlocator.ConsumerLocator(
uuid=generateduuid, communicator=comm)
ret = locator.learnconsumerlist()
assert ret is None
def test_getcurrentconsumer(mocker):
mocker.patch('communicator.Communicator')
comm = communicator.Communicator(
currentconsumer="127.0.0.1",
uuid=generateduuid)
locator = consumerlocator.ConsumerLocator(
uuid=generateduuid, communicator=comm)
assert locator.getcurrentconsumer() == consumerlocator.KNOWNCONSUMER
def test_checkcurrentconsumer(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
consumerlocator.KNOWNCONSUMER = f"127.0.0.1:{port}"
locator = consumerlocator.ConsumerLocator(
uuid=generateduuid, communicator=comm)
ret = locator.checkcurrentconsumer()
assert ret == True
def test_updateconsumer(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
consumerlocator.KNOWNCONSUMER = f"127.0.0.1:{port}"
locator = consumerlocator.ConsumerLocator(
uuid=generateduuid, communicator=comm)
assert locator.currentconsumer is not None
ret = locator.updateconsumer()
assert ret == f"127.0.0.1:{port}"
def test_updateconsumerlist(httpserver):
httpserver.expect_oneshot_request(
uri="/consumer",
method='GET',
data="").respond_with_json(
["10.69.42.1", "10.10.10.10", "10.20.30.40"])
url = httpserver.url_for("/")
port = re.match(r"\W*http[^:]*\D*(\d+)", url).group(1)
comm = communicator.Communicator(
currentconsumer=f"127.0.0.1:{port}",
uuid=generateduuid)
consumerlocator.KNOWNCONSUMER = f"127.0.0.1:{port}"
locator = consumerlocator.ConsumerLocator(
uuid=generateduuid, communicator=comm)
ret = locator.updateconsumerlist()
assert ret is None