Beispiel #1
0
    def test_normal_usage(self):
        self.assertEqual(len(sample_expenses), self.expenses_table.item_count)

        old_expense = sample_expenses[0].copy()

        to_update = old_expense.copy()
        new_amount = old_expense['amount'] + 10
        to_update['amount'] = new_amount

        updated = self.facade.update(to_update, old_expense, self.firebase_uid)
        self.assertTrue(Validator.validate_expense_simple(updated))

        # check the item in the database now
        exp_from_db = self.expenses_table.get_item(Key={
            'user_uid':
            self.firebase_uid,
            'timestamp_utc':
            old_expense['timestamp_utc']
        },
                                                   ConsistentRead=True)['Item']

        exp_from_db = self.facade.converter.convertFromDbFormat(
            sanitize_expense(exp_from_db))
        self.assertTrue(Validator.validate_expense_simple(exp_from_db))

        self.assertEqual(exp_from_db['id'], old_expense['id'])
        self.assertTrue(to_update['id'] == updated['id'] == old_expense['id'])
        self.assertEqual(exp_from_db['amount'], new_amount)
    def test_invalid_expense(self):
        no_id = valid_expense.copy()
        no_id.pop('id')
        is_valid, errs = Validator.validate_expense(no_id)
        self.assertFalse(is_valid, "Should be reported as invalid")
        self.assertIn(ValidatorErrorPrefix.MISSING_PROPERTY, errs)

        amount_is_null = valid_expense.copy()
        amount_is_null['amount'] = None
        is_valid, errs = Validator.validate_expense(amount_is_null)
        self.assertFalse(is_valid, "Should be reported as invalid")
        self.assertIn(ValidatorErrorPrefix.WRONG_TYPE, errs)
Beispiel #3
0
 def _valid_sync_response(self, sync_result):
     self.assertIn("to_add", sync_result.keys())
     self.assertIn("to_remove", sync_result.keys())
     self.assertIn("to_update", sync_result.keys())
     self.assertTrue(
         all(
             Validator.validate_expense_simple(e)
             for e in sync_result['to_add']))
     self.assertTrue(
         all(
             Validator.validate_expense_simple(e)
             for e in sync_result['to_update']))
     self.assertTrue(
         all(
             Validator.validate_property(exp_id, 'id')
             for exp_id in sync_result['to_remove']))
    def test_valid_request_returns_valid_response(self, mocked_db):
        mocked_db.get_list.return_value = reversed_expenses[1:]
        batch_size = len(reversed_expenses) - 1

        request_params = valid_request_args.copy()
        request_params['start_from_property'] = self.start_from_property
        request_params['start_from_property_value'] = self.start_from_property_value
        request_params['start_from_id'] = reversed_expenses[0]['id']
        request_params['batch_size'] = batch_size
        request_params['ordering_direction'] = 'desc'

        raw_resp = self.get(endpoint, url_args=request_params,
                            raw_response=True)

        self.assertEqual(200, raw_resp.status_code)

        json_resp = loads(raw_resp.get_data(as_text=True))

        self.assertTrue(all([Validator.validate_expense_simple(exp) for exp in json_resp]),
                        "All returned objects must be valid expenses")

        self.assertEqual(batch_size, len(json_resp), "The result should be of size %i" % batch_size)

        property_values = [exp[self.start_from_property] for exp in json_resp]
        self.assertEqual(property_values, list(sorted(property_values, reverse=True)),
                         "Result should be sorted by the selected property descendigly")
        self.assertTrue(property_values[0] > property_values[1],
                        'The first result should be with the highest property value')

        self.assertLess(json_resp[0][self.start_from_property], reversed_expenses[0][self.start_from_property],
                        "The start_from must be `larger` than the first result when ordered in desc order")
 def test_validation(self):
     is_valid, errs = Validator.validate_expense(valid_expense)
     errs = list(map(str, errs))
     self.assertTrue(
         is_valid,
         "A valid expense is reported as invalid with reason: \n[%s] " %
         "\n".join(errs))
Beispiel #6
0
    def test_normal_usage(self, mocked_db):
        type(mocked_db).max_sync_request_size = PropertyMock(return_value=non_mocked_facade.max_sync_request_size)

        mocked_db.sync.return_value = {
            'to_remove': ['some uuid'],
            'to_add': [SINGLE_EXPENSE],
            'to_update': [sample_expenses[1]]
        }

        raw_resp = self.post(url=endpoint, data=valid_payload)
        self.assertEqual(200, raw_resp.status_code)
        json = loads(raw_resp.get_data(as_text=True))

        self.assertTrue(type(json) == dict)
        self.assertTrue(all([Validator.validate_expense_simple(exp) for exp in json['to_add']]))
        self.assertTrue(all([Validator.validate_expense_simple(exp) for exp in json['to_update']]))
        self.assertTrue(all([type(e) == str for e in json['to_remove']]))
 def test_timestamp_must_end_with_z(self):
     invalid_ts = valid_expense.copy()
     invalid_ts['timestamp_utc'] = datetime.now(
         tz.utc).isoformat()  # ends with +00:00
     is_valid, errs = Validator.validate_expense(invalid_ts)
     self.assertFalse(is_valid)
     self.assertIn('timestamp_utc', errs)
     self.assertIn('not a valid timestamp', errs)
    def test_timestamp_validation(self):
        invalid_ts = valid_expense.copy()
        invalid_ts['timestamp_utc'] = str(datetime.now())

        is_valid, errs = Validator.validate_expense(invalid_ts)
        self.assertFalse(
            is_valid,
            'Should be reported as invalid because it is a naive ts and not a UTC ts.'
        )
        self.assertIn('timestamp_utc', errs)
        self.assertIn('not a valid timestamp', errs)
Beispiel #9
0
    def test_normal_usage(self, mocked_facade):
        mocked_facade.update.return_value = SINGLE_EXPENSE
        updated = valid_payload['updated'].copy()

        raw_resp = self.put(url=endpoint, data=valid_payload)

        self.assertEqual(200, raw_resp.status_code)
        exp_json = loads(raw_resp.get_data(as_text=True))
        self.assertTrue(Validator.validate_expense_simple(exp_json))

        # the facade would have updated these (tested in the db facade tests)
        del exp_json['timestamp_utc_updated']
        del updated['timestamp_utc_updated']
        self.assertDictEqual(updated, exp_json)
Beispiel #10
0
def validate_update_request(request_data):
    try:
        assert request_data, ApiError.EMPTY_REQUEST_BODY
        assert 'updated' in request_data, '`updated` field not in the request body'
        assert 'previous_state' in request_data, ApiError.PREVIOUS_STATE_OF_EXP_MISSING

        check_valid = [('updated', request_data['updated']),
                       ('previous_state', request_data['previous_state'])]
        for field, value in check_valid:
            is_valid, _ = Validator.validate_expense(value)
            assert is_valid, "%s is not a valid expense" % field
            assert 'id' in value and value['id'], ApiError.ID_PROPERTY_MANDATORY
    except AssertionError as err:
        return False, str(err)

    return True, None
Beispiel #11
0
def validate_get_expenses_list(property_name,
                               property_value,
                               expense_id,
                               ordering_direction,
                               batch_size,
                               none_is_ok=True):
    assert property_name in expense_schema['properties'].keys(
    ), "%s is not a valid expense property" % property_name

    if property_value:
        assert Validator.validate_property(property_value, property_name), '%s is not a valid value for %s' % \
                                                                           (str(property_value), property_name)

    assert OrderingDirection.is_member(
        ordering_direction), ApiError.INVALID_ORDER_PARAM

    if property_value:
        assert expense_id, "If a property_value is set, the start_from_id is mandatory"

    assert batch_size < MAX_BATCH_SIZE, ApiError.BATCH_SIZE_EXCEEDED
    assert batch_size > 0, ApiError.INVALID_BATCH_SIZE
Beispiel #12
0
    def test_normal_usage(self):
        expense_to_persist = SINGLE_EXPENSE.copy()
        expense_to_persist['id'] = None

        persisted = self.facade.persist(expense_to_persist,
                                        user_uid=self.firebase_uid)
        self.assertTrue(Validator.validate_expense_simple(persisted))

        self.assertIsNotNone(persisted['id'])
        self.assertNotEqual(
            expense_to_persist['timestamp_utc_created'],
            persisted['timestamp_utc_created'],
            "When an expense is created, its created_at must be set by the server right before persisting"
        )

        raw_persisted_expense = self.expenses_table.get_item(
            Key={
                'timestamp_utc': persisted['timestamp_utc'],
                'user_uid': self.firebase_uid
            },
            ConsistentRead=True)['Item']

        self.assertEqual(raw_persisted_expense['id'], persisted['id'])
Beispiel #13
0
def validate_remove_request(request_data):
    assert request_data, ApiError.EMPTY_REQUEST_BODY
    assert Validator.validate_expense_simple(
        request_data), ApiError.INVALID_EXPENSE
    assert 'id' in request_data and request_data[
        'id'], ApiError.ID_PROPERTY_MANDATORY
Beispiel #14
0
def validate_persist_request(expense):
    is_valid, err_msg = Validator.validate_expense(expense)
    assert is_valid, "%s %s" % (ApiError.INVALID_EXPENSE, err_msg)
    assert expense['id'] == None, ApiError.ID_PROPERTY_FORBIDDEN  # must be non
Beispiel #15
0
def is_valid_expense(exp):
    is_valid, _ = Validator.validate_expense(exp)
    return is_valid