From 8abbe3462fda6f0fdb202c6a43a65031d2709649 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 26 Dec 2013 21:48:45 +0100 Subject: [PATCH] [tests] Check transactions for errors before being added - Added support for Exception-specific HTTP response codes for AccountinExceptions. --- accounting/decorators.py | 6 ++++- accounting/exceptions.py | 7 +++--- accounting/storage/ledgercli.py | 12 ++++++++++ accounting/tests/test_transactions.py | 34 +++++++++++++++++++++++---- accounting/transport.py | 3 ++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/accounting/decorators.py b/accounting/decorators.py index da4cb55..634767e 100644 --- a/accounting/decorators.py +++ b/accounting/decorators.py @@ -19,7 +19,11 @@ def jsonify_exceptions(func): try: return func(*args, **kw) except AccountingException as exc: - return jsonify(error=exc) + response = jsonify(error=exc) + + response.status_code = exc.http_code + + return response return wrapper diff --git a/accounting/exceptions.py b/accounting/exceptions.py index 6d751ca..42b179f 100644 --- a/accounting/exceptions.py +++ b/accounting/exceptions.py @@ -7,6 +7,7 @@ class AccountingException(Exception): Used as a base for exceptions that are returned to the caller via the jsonify_exceptions decorator ''' + http_code = 500 def __init__(self, message, **kw): self.message = message for key, value in kw.items(): @@ -14,12 +15,12 @@ class AccountingException(Exception): class TransactionNotFound(AccountingException): - pass + http_code = 404 class LedgerNotBalanced(AccountingException): - pass + http_code = 400 class TransactionIDCollision(AccountingException): - pass + http_code = 400 diff --git a/accounting/storage/ledgercli.py b/accounting/storage/ledgercli.py index 919d8f7..eb86445 100644 --- a/accounting/storage/ledgercli.py +++ b/accounting/storage/ledgercli.py @@ -173,6 +173,18 @@ class Ledger(Storage): with open(self.ledger_file, 'ab') as f: f.write(output) + # Check to see that no errors were introduced + try: + self.get_transactions() + except AccountingException as exc: + # TODO: Do a hard reset on the repository using Repository.reset, + # this is on hold because of + # https://github.com/libgit2/pygit2/issues/271. + # This solution will work in the meantime + self.delete_transaction(transaction.id) + setattr(exc, 'transaction', transaction) + raise exc + self.commit_changes('Added transaction %s' % transaction.id) _log.info('Added transaction %s', transaction.id) diff --git a/accounting/tests/test_transactions.py b/accounting/tests/test_transactions.py index 03ea2fc..f7d9bd1 100644 --- a/accounting/tests/test_transactions.py +++ b/accounting/tests/test_transactions.py @@ -9,6 +9,7 @@ import copy import uuid from datetime import datetime +from decimal import Decimal from flask import json @@ -17,7 +18,7 @@ from accounting.web import app, init_ledger from accounting.transport import AccountingEncoder, AccountingDecoder from accounting.models import Transaction, Posting, Amount -logging.basicConfig(level=logging.DEBUG) +#logging.basicConfig(level=logging.DEBUG) class TransactionTestCase(unittest.TestCase): @@ -263,13 +264,36 @@ class TransactionTestCase(unittest.TestCase): ] ) - self._post_json('/transaction', transaction) + response = self._post_json('/transaction', transaction, expect=400) - response = self._get_json('/transaction') + self.assertEqual(response['error']['type'], 'LedgerNotBalanced') - import pdb; pdb.set_trace() + def test_update_transaction_amounts(self): + transaction = self._add_simple_transaction() + response = self._get_json( + '/transaction/' + transaction.id) - def test_update_transaction_amounts(self): pass + transaction = response['transaction'] + + for posting in transaction.postings: + posting.amount.amount *= Decimal(1.50) + + response = self._post_json('/transaction/' + transaction.id, + {'transaction': transaction}) + + self.assertEqual(response['status'], 'OK') + + response = self._get_json('/transaction/' + transaction.id) + + self.assertEqual(response['transaction'], transaction) + + def test_delete_nonexistent_transaction(self): + response = self._open_json('DELETE', '/transaction/I-do-not-exist', + expect=404) + + self.assertEqual(response['error']['type'], 'TransactionNotFound') + + def test_post_transaction_with_metadata(self): pass if __name__ == '__main__': diff --git a/accounting/transport.py b/accounting/transport.py index e838be9..ac155b7 100644 --- a/accounting/transport.py +++ b/accounting/transport.py @@ -44,7 +44,8 @@ class AccountingEncoder(json.JSONEncoder): elif isinstance(o, AccountingException): return dict( type=o.__class__.__name__, - message=o.message + message=o.message, + transaction=getattr(o, 'transaction', None) ) return json.JSONEncoder.default(self, o)