[tests] Check transactions for errors before being added
- Added support for Exception-specific HTTP response codes for AccountinExceptions.
This commit is contained in:
		
							parent
							
								
									ef12c232ad
								
							
						
					
					
						commit
						8abbe3462f
					
				
					 5 changed files with 52 additions and 10 deletions
				
			
		| 
						 | 
					@ -19,7 +19,11 @@ def jsonify_exceptions(func):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            return func(*args, **kw)
 | 
					            return func(*args, **kw)
 | 
				
			||||||
        except AccountingException as exc:
 | 
					        except AccountingException as exc:
 | 
				
			||||||
            return jsonify(error=exc)
 | 
					            response = jsonify(error=exc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response.status_code = exc.http_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return wrapper
 | 
					    return wrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ class AccountingException(Exception):
 | 
				
			||||||
    Used as a base for exceptions that are returned to the caller via the
 | 
					    Used as a base for exceptions that are returned to the caller via the
 | 
				
			||||||
    jsonify_exceptions decorator
 | 
					    jsonify_exceptions decorator
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
 | 
					    http_code = 500
 | 
				
			||||||
    def __init__(self, message, **kw):
 | 
					    def __init__(self, message, **kw):
 | 
				
			||||||
        self.message = message
 | 
					        self.message = message
 | 
				
			||||||
        for key, value in kw.items():
 | 
					        for key, value in kw.items():
 | 
				
			||||||
| 
						 | 
					@ -14,12 +15,12 @@ class AccountingException(Exception):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionNotFound(AccountingException):
 | 
					class TransactionNotFound(AccountingException):
 | 
				
			||||||
    pass
 | 
					    http_code = 404
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LedgerNotBalanced(AccountingException):
 | 
					class LedgerNotBalanced(AccountingException):
 | 
				
			||||||
    pass
 | 
					    http_code = 400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionIDCollision(AccountingException):
 | 
					class TransactionIDCollision(AccountingException):
 | 
				
			||||||
    pass
 | 
					    http_code = 400
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,6 +173,18 @@ class Ledger(Storage):
 | 
				
			||||||
        with open(self.ledger_file, 'ab') as f:
 | 
					        with open(self.ledger_file, 'ab') as f:
 | 
				
			||||||
            f.write(output)
 | 
					            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)
 | 
					        self.commit_changes('Added transaction %s' % transaction.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _log.info('Added transaction %s', transaction.id)
 | 
					        _log.info('Added transaction %s', transaction.id)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import copy
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from decimal import Decimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import json
 | 
					from flask import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +18,7 @@ from accounting.web import app, init_ledger
 | 
				
			||||||
from accounting.transport import AccountingEncoder, AccountingDecoder
 | 
					from accounting.transport import AccountingEncoder, AccountingDecoder
 | 
				
			||||||
from accounting.models import Transaction, Posting, Amount
 | 
					from accounting.models import Transaction, Posting, Amount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
logging.basicConfig(level=logging.DEBUG)
 | 
					#logging.basicConfig(level=logging.DEBUG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTestCase(unittest.TestCase):
 | 
					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__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,8 @@ class AccountingEncoder(json.JSONEncoder):
 | 
				
			||||||
        elif isinstance(o, AccountingException):
 | 
					        elif isinstance(o, AccountingException):
 | 
				
			||||||
            return dict(
 | 
					            return dict(
 | 
				
			||||||
                type=o.__class__.__name__,
 | 
					                type=o.__class__.__name__,
 | 
				
			||||||
                message=o.message
 | 
					                message=o.message,
 | 
				
			||||||
 | 
					                transaction=getattr(o, 'transaction', None)
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return json.JSONEncoder.default(self, o)
 | 
					        return json.JSONEncoder.default(self, o)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue