From 04d46d06b092e55f008642200c09632744f9c99d Mon Sep 17 00:00:00 2001 From: Ameya Shenoy Date: Sun, 14 Feb 2021 16:59:35 +0530 Subject: [PATCH] fix: verify date with TDD - add tests for the function Signed-off-by: Ameya Shenoy --- README.md | 6 ++++++ backend/app/tests.py | 37 +++++++++++++++++++++++++++++++++++++ backend/app/utils.py | 43 +++++++++++++++++++++++++++++++++---------- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5cd6c19..6121e17 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,12 @@ docker-compose exec backend python manage.py makemigrations docker-compose exec backend python manage.py migrate ``` +- To run unit tests + +```sh +docker-compose exec backend python manage.py test +``` + Similarly all django commands can be run this way. ## Endpoints diff --git a/backend/app/tests.py b/backend/app/tests.py index 7ce503c..57e4ffd 100644 --- a/backend/app/tests.py +++ b/backend/app/tests.py @@ -1,3 +1,40 @@ from django.test import TestCase +from unittest import mock +from app.utils import verify_date +import datetime # Create your tests here. +class StubDate(datetime.datetime): + pass + + +class TestApp(TestCase): + """Test app utils. + + Publish time: datetime.datetime(2021, 2, 14, 12, 30) + """ + + @mock.patch('app.utils.datetime.datetime', StubDate) + def test_today_before_publish_time(self): + StubDate.now = classmethod(lambda cls: datetime.datetime(2021, 2, 12, 8, 0, 0)) + date, _ = verify_date('2021-02-14', '') + self.assertEqual(date.date(), datetime.datetime(2021, 2, 11).date()) + + @mock.patch('app.utils.datetime.datetime', StubDate) + def test_today_after_publish_time(self): + StubDate.now = classmethod(lambda cls: datetime.datetime(2021, 2, 12, 13, 0, 0)) + date, _ = verify_date('2021-02-14', '') + self.assertEqual(date.date(), datetime.datetime(2021, 2, 12).date()) + + @mock.patch('app.utils.datetime.datetime', StubDate) + def test_weekend_returns_friday(self): + StubDate.now = classmethod(lambda cls: datetime.datetime(2021, 2, 14, 13, 0, 0)) + date, _ = verify_date('2021-02-14', '') + self.assertEqual(date.date(), datetime.datetime(2021, 2, 12).date()) + + @mock.patch('app.utils.datetime.datetime', StubDate) + def test_a_future_date(self): + StubDate.now = classmethod(lambda cls: datetime.datetime(2021, 2, 15, 13, 0, 0)) + date, _ = verify_date('2021-02-20', '') + self.assertEqual(date.date(), datetime.datetime(2021, 2, 15).date()) + diff --git a/backend/app/utils.py b/backend/app/utils.py index c0133aa..4c838af 100644 --- a/backend/app/utils.py +++ b/backend/app/utils.py @@ -8,6 +8,7 @@ import csv import json import datetime import logging +from typing import Tuple from io import BytesIO, TextIOWrapper from zipfile import ZipFile @@ -114,7 +115,10 @@ def populate_bhav_copy_data_into_postgres(data=None, date=None): del data[0] if date is None: date = datetime.datetime.now().date() + # data = stocks_csv_to_json(data) for stock in data: + # stock['date'] = date + # BhavCopyEquity.objects.get_or_create(**stock) BhavCopyEquity.objects.get_or_create( date=date, sc_code=int(stock[0]), @@ -156,17 +160,36 @@ def stocks_csv_to_json(data): return stocks -def verify_date(date, ret_message): +def verify_date(date, ret_message) -> Tuple[datetime.datetime, str]: + """Verify current date. + + Check current date and time and return the appropriate date. Also take care + of the following usecases + - if today before publish time return yesterdays data + - if today after publish time return todays data + - if a future date, return current day's data with time travel message + - if a weekend return Friday's data with custom message + """ # Verify Date logger.info('Verifying date %s', date) - req_date = datetime.datetime.strptime(date, '%Y-%m-%d') - # 18:00 IST == 12:30 UTC - today = datetime.datetime.now().replace(hour=12, minute=30, second=0, microsecond=0) - logger.info('Req Date: %s; Today: %s', req_date, today) - if req_date > today: + curr_datetime = datetime.datetime.now() - datetime.timedelta(hours=5, minutes=30) + req_datetime = datetime.datetime.strptime(date, '%Y-%m-%d') + next_publish_time = curr_datetime.replace(hour=6, minute=0, second=0, + microsecond=0) + logger.info('Current IST Datetime: %s; Request Datetime: %s; Next Publish: %s', + curr_datetime, req_datetime, next_publish_time) + # Check for future date + if req_datetime.date() > curr_datetime.date(): ret_message = "Time travel not yet invented! Returning latest available data." - req_date = today - if req_date.date() == today.date() and req_date < today: - req_date = today - datetime.timedelta(days=1) - return req_date, ret_message + req_datetime = curr_datetime + # Check for weekend + day_num = req_datetime.weekday() + if day_num in [5, 6]: + ret_message = "Markets are closed on weekends. Returning data for Friday." + req_datetime -= datetime.timedelta(days=day_num-4) # change req to Friday + # Check for day + if req_datetime.date() == curr_datetime.date() and curr_datetime < next_publish_time: + ret_message = "Today's data not yet published, returning yesterday's data." + req_datetime -= datetime.timedelta(days=1) + return req_datetime, ret_message