예제 #1
0
    def test_with_invalid_params(self, mocked_db):
        batch_size = -1
        start_from = 1
        invalid_args = [
            {
                'start_from_property_value': 'boom',

                'start_from_id': sample_expenses[0]['id'],
                'start_from_property': 'timestamp_utc',
                'batch_size': 1,
                'ordering_direction': 'asc'
            },
            {
                'start_from_id': 1,

                'start_from_property': 'timestamp_utc',
                'start_from_property_value': utc_now_str(),
            },
            {
                'start_from_property_value': utc_now_str().replace('Z', '+00:00'),  # invalid for a ts to end in +00:00
                'start_from_property': 'timestamp_utc',
                'start_from_id': 'some str',
            }
        ]
        for args in invalid_args:
            mocked_db.get_list.return_value = []
            raw_resp = self.get(url=endpoint, url_args={'start_id': start_from, 'batch_size': batch_size})

            self.assertEqual(raw_resp.status_code, 400, "args should have been rejected" + str(args))
            json_resp = loads(raw_resp.get_data(as_text=True))
            self.assertIn("error", json_resp,
                          "error key missing from non-200 response")
            self.assertIn(ApiError.INVALID_QUERY_PARAMS, json_resp['error'])
            self.assertFalse(mocked_db.get_list.called, "Shouldn't have been called")
            mocked_db.get_list.reset_mock()
예제 #2
0
    def test_fails_on_invalid_payload(self, mocked_db):
        type(mocked_db).max_sync_request_size = PropertyMock(return_value=non_mocked_facade.max_sync_request_size)

        invalid_payloads = [
            [{"timestamp_utc_updated": 'invalid ts', 'id': 'valid id'}],
            [{"timestamp_utc_updated": utc_now_str(), 'id': None}],  # valid ts invalid id
            [{"timestamp_utc_updated": utc_now_str()}],  # valid ts but missing id
            [{'id': 'valid id but missing ts'}]
        ]
        for payload in invalid_payloads:
            raw_resp = self.post(url=endpoint, data=payload)
            self.assertEqual(raw_resp.status_code, 400)
예제 #3
0
    def test_(self):
        self.mocked_time = self.patch('app.helpers.time.utc_now_str')

        self.mocked_time.return_value = '1969'

        from app.helpers.time import utc_now_str
        self.assertEqual(utc_now_str(), '1969')
예제 #4
0
    def _touch_expense_in_db(self, item, others=[]):
        """

        :param item:
        :param others: list of dicts. each dict has "attr" and "value" keys
        :return:
        """
        other_updates = {}
        for other in others:
            other_updates[other['attr']] = {
                "Value": other['value'],
                'Action': "PUT"
            }

        self.expenses_table.update_item(Key={
            'timestamp_utc': item['timestamp_utc'],
            'user_uid': self.firebase_uid
        },
                                        AttributeUpdates={
                                            'timestamp_utc_updated': {
                                                'Value': utc_now_str(),
                                                'Action': 'PUT'
                                            },
                                            **other_updates
                                        })
예제 #5
0
    def test_call_on_good_request(self, mocked_db: type(db_facade)):
        mocked_db.get_list.return_value = []
        property_value = utc_now_str()
        property_name = 'timestamp_utc'
        id = 'asd'
        batch_size = 10
        request_args = {
            'start_from_id': id,
            'start_from_property_value': property_value,
            'start_from_property': property_name,
            'batch_size': batch_size,
        }
        resp = self.get(url=endpoint, url_args=request_args)

        self.assertEqual(1, mocked_db.get_list.call_count, 'The get list should have been called once')

        call_args, actual_kwargs = mocked_db.get_list.call_args
        self.assertEqual(0, len(call_args))
        expected_kwargs = {
            'property_value': property_value,
            'property_name': property_name,
            "ordering_direction": OrderingDirection.desc,
            'batch_size': batch_size,
            'user_uid': self.firebase_uid
        }
        self.assertEqual(len(expected_kwargs), len(actual_kwargs))

        self.assertDictEqual(expected_kwargs, actual_kwargs,
                             "get_list wasn't called with the expected kwargs")

        self.assertEqual(200, resp.status_code)
        self.assertEqual('[]', resp.get_data(as_text=True))
예제 #6
0
 def _make_expense(self):
     new_expense = sample_expenses[-1].copy()
     new_expense['id'] = str(uuid.uuid4())
     now = utc_now_str()
     new_expense['timestamp_utc'] = now
     new_expense['timestamp_utc_created'] = now
     new_expense['timestamp_utc_updated'] = now
     new_expense['user_uid'] = self.firebase_uid
     self.expenses_table.put_item(
         Item=self.facade.converter.convertToDbFormat(new_expense))
     return new_expense
예제 #7
0
    def test_timestamp(self):
        exp = sample_expenses[0].copy()
        exp['id'] = None

        persisted = self.facade.persist(exp, user_uid=self.firebase_uid)
        now = dt_from_utc_iso_str(utc_now_str())

        persisted_at_dt = dt_from_utc_iso_str(
            persisted['timestamp_utc_created'])
        updated_at_dt = dt_from_utc_iso_str(persisted['timestamp_utc_created'])
        self.assertEqual(persisted_at_dt, updated_at_dt)

        for ts in [persisted_at_dt, updated_at_dt]:
            diff = int((now - ts).total_seconds())
            self.assertTrue(
                1 >= diff,
                "the expense's ts must be less than a second ago from now")
예제 #8
0
    def test_errors_on_no_such_expense(self):
        """
        remove() should raise an exception in either cases:
        * an expense with the same SORT key attribute doesn't exist
        * an expense with the same `id` attribute doesn't exist
        """
        assert self.expenses_table.item_count
        exp = SINGLE_EXPENSE.copy()
        non_persisted_expenses = [{
            **exp, 'id': 'boom'
        }, {
            **exp, 'timestamp_utc': utc_now_str()
        }]

        for e in non_persisted_expenses:
            self.assertRaises(NoExpenseWithThisId, self.facade.remove, e,
                              self.firebase_uid)
예제 #9
0
    def test_on_range_attr_updated(self):
        old_exp = sample_expenses[0].copy()
        to_update = old_exp.copy()
        assert 'timestamp_utc' == self.facade.RANGE_KEY
        to_update['timestamp_utc'] = utc_now_str()
        assert to_update['timestamp_utc'] != old_exp['timestamp_utc']

        updated = self.facade.update(to_update,
                                     old_exp,
                                     user_uid=self.firebase_uid)
        self.assertTrue(updated['id'] == to_update['id'] == old_exp['id'])
        # check the item in the database now
        exp_from_db = self.expenses_table.get_item(Key={
            'user_uid':
            self.firebase_uid,
            'timestamp_utc':
            updated['timestamp_utc']
        },
                                                   ConsistentRead=True)['Item']
        self.assertTrue(exp_from_db['id'] == old_exp['id'])
예제 #10
0
import json
from dateutil.relativedelta import relativedelta
from app.helpers.time import utc_now_str, ensure_ts_str_ends_with_z
from tests.base_test import BaseTest, BaseTestWithHTTPMethodsMixin, NoAuthenticationMarkerMixin
from tests.test_expenses_api import db_facade_path
from datetime import datetime, timezone, timedelta
from unittest.mock import patch
from app.expenses_api.views import db_facade
from app.expenses_api.api_error_msgs import ApiError

endpoint = 'expenses_api.statistics'
valid_url_args = {
    "from_dt":
    (datetime.now(timezone.utc) - timedelta(minutes=60)).isoformat(),
    "to_dt": utc_now_str()
}


class TestStatisticsAuth(BaseTest, BaseTestWithHTTPMethodsMixin):
    def test_auth(self):
        resp = self.get(url=endpoint, url_for_args=valid_url_args)
        self.assertEqual(403, resp.status_code)


@patch(db_facade_path, autospec=True)
class TestStatistics(BaseTest, BaseTestWithHTTPMethodsMixin,
                     NoAuthenticationMarkerMixin):
    def test_normal_usage(self, mocked_db):
        mocked_result = {"BGN": 100}
        mocked_db.statistics.return_value = mocked_result
예제 #11
0
exp1 = sample_expenses[0].copy()
exp2 = sample_expenses[1].copy()
exp3 = sample_expenses[2].copy()
exp4 = sample_expenses[3].copy()
now = dt.now(tz.utc)

exp1_dt = ensure_ts_str_ends_with_z((now - td(hours=2)).isoformat())
exp1['timestamp_utc'] = exp1_dt
exp1['currency'] = "EUR"

exp2_dt = ensure_ts_str_ends_with_z((now - td(minutes=5)).isoformat())
exp2['timestamp_utc'] = exp2_dt
exp2['currency'] = "EUR"

exp3_dt = utc_now_str()
exp3['timestamp_utc'] = ensure_ts_str_ends_with_z(
    (now - td(seconds=30)).isoformat())
exp3['currency'] = 'USD'

exp4_dt = ensure_ts_str_ends_with_z((now - td(seconds=5)).isoformat())
exp4['timestamp_utc'] = exp4_dt
exp4['currency'] = 'USD'


class TestStatistics(DbTestBase):
    def test_normal_usage(self):
        self.seedData(firebase_uid=self.firebase_uid,
                      items=[exp1, exp2, exp3, exp4])
        test = [{
            'from':
예제 #12
0
    def setUp(self):
        super(TestGETExpensesList, self).setUp()

        self.start_from_property = 'timestamp_utc'
        self.start_from_property_value = utc_now_str()
        self.valid_request_args = valid_request_args
예제 #13
0
from app.helpers.time import utc_now_str
from app.models.expense_validation import Validator

from tests.common_methods import sample_expenses
from tests.test_expenses_api import db_facade_path

from app.expenses_api.views import MAX_BATCH_SIZE, db_facade
from app.expenses_api.api_error_msgs import ApiError

endpoint = 'expenses_api.get_expenses_list'
reversed_expenses = list(reversed(sample_expenses))

valid_request_args = {
    "start_from_id": 'some id',
    "start_from_property": 'timestamp_utc',
    "start_from_property_value": utc_now_str(),
    "batch_size": 10,
    "ordering_direction": 'desc'
}


class TestGetListAuth(BaseTest, BaseTestWithHTTPMethodsMixin):
    def test_auth(self):
        resp = self.get(url=endpoint, url_args=valid_request_args.copy())
        self.assertEqual(403, resp.status_code)


@patch(db_facade_path, autospec=True)
class TestGETExpensesList(BaseTest, BaseTestWithHTTPMethodsMixin, NoAuthenticationMarkerMixin):
    def setUp(self):
        super(TestGETExpensesList, self).setUp()
예제 #14
0
def touch_timestamp(expense, ts_property):
    assert ts_property in expense
    expense[ts_property] = utc_now_str()