From 46aaff43c06d19cf27989e89d0295bcba0d54430 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sun, 1 Jan 2023 21:52:43 +0000 Subject: [PATCH] Begin writing live tests --- Makefile | 2 +- core/tests/helpers.py | 88 +++++++++++++++++++++++++++++++++ core/tests/trading/test_live.py | 12 +++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 core/tests/helpers.py create mode 100644 core/tests/trading/test_live.py diff --git a/Makefile b/Makefile index a258255..934ed54 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ log: docker-compose --env-file=stack.env logs -f test: - docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" + docker-compose --env-file=stack.env run -e LIVE=$(LIVE) --rm app sh -c ". /venv/bin/activate && python manage.py test $(MODULES) -v 2" migrate: docker-compose --env-file=stack.env run --rm app sh -c ". /venv/bin/activate && python manage.py migrate" diff --git a/core/tests/helpers.py b/core/tests/helpers.py new file mode 100644 index 0000000..c9b753a --- /dev/null +++ b/core/tests/helpers.py @@ -0,0 +1,88 @@ +from os import getenv +from unittest.mock import Mock, patch + +from core.models import Account, User + + +# Create patch mixin to mock out the Elastic client +class ElasticMock: + """ + Mixin to mock out the Elastic client. + Patches the initialise_elasticsearch function to return a mock client. + This client returns a mock response for the index function. + """ + + @classmethod + def setUpClass(cls): + super(ElasticMock, cls).setUpClass() + cls.patcher = patch("core.lib.elastic.initialise_elasticsearch") + # Pretend the object has been created + patcher = cls.patcher.start() + + fake_client = Mock() + fake_client.index = Mock() + fake_client.index.return_value = {"result": "created"} + + patcher.return_value = fake_client + + @classmethod + def tearDownClass(cls): + super(ElasticMock, cls).tearDownClass() + cls.patcher.stop() + + +class LiveBase: + @classmethod + def setUpClass(cls): + super(LiveBase, cls).setUpClass() + cls.live = getenv("LIVE", "0") == "1" + + account_name = getenv("TEST_ACCOUNT_NAME", "Test Account") + exchange = getenv("TEST_ACCOUNT_EXCHANGE", None) + api_key = getenv("TEST_ACCOUNT_API_KEY", None) + api_secret = getenv("TEST_ACCOUNT_API_SECRET", None) + if not cls.live: + cls.skipTest(LiveBase, "Not running live tests") + + # Make sure all the variables are set + cls.fail = False + if not exchange: + cls.fail = True + reason = "No exchange specified" + if not api_key: + cls.fail = True + reason = "No API key specified" + if not api_secret: + cls.fail = True + reason = "No API secret specified" + if cls.fail: + print("Live tests aborted.") + print( + f""" +Please check that the following environment variables are set: +TEST_ACCOUNT_NAME="Test Account" +TEST_ACCOUNT_EXCHANGE="oanda" +TEST_ACCOUNT_API_KEY="xxx-xxx-xxxxxxxx-xxx" +TEST_ACCOUNT_API_SECRET="xxx-xxx" + +If you have done this, please see the following line for more information: +{reason} +""" + ) + + cls.user = User.objects.create_user( + username="testuser", + email="test@example.com", + ) + + cls.account = Account.objects.create( + user=cls.user, + name=account_name, + exchange=exchange, + api_key=api_key, + api_secret=api_secret, + ) + + def setUp(self): + if self.fail: + self.skipTest("Live tests aborted") diff --git a/core/tests/trading/test_live.py b/core/tests/trading/test_live.py new file mode 100644 index 0000000..1e40a8a --- /dev/null +++ b/core/tests/trading/test_live.py @@ -0,0 +1,12 @@ +from django.test import TestCase + +from core.tests.helpers import ElasticMock, LiveBase + + +class LiveTradingTestCase(ElasticMock, LiveBase, TestCase): + def test_account_functional(self): + """ + Test that the account is functional. + """ + balance = self.account.client.get_balance() + self.assertTrue(balance > 0)