[tests] Added tests and updated storage.ledgercli
- [ledgercli] Log info messages for operations such as add, delete, update transactions
This commit is contained in:
		
							parent
							
								
									0108548b4b
								
							
						
					
					
						commit
						3620d97f9d
					
				
					 3 changed files with 284 additions and 0 deletions
				
			
		|  | @ -211,6 +211,8 @@ 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) | ||||||
| 
 | 
 | ||||||
|  |         _log.info('Added transaction %s', transaction.id) | ||||||
|  | 
 | ||||||
|         _log.debug('written to file: %s', output) |         _log.debug('written to file: %s', output) | ||||||
| 
 | 
 | ||||||
|         return transaction.id |         return transaction.id | ||||||
|  | @ -419,6 +421,11 @@ class Ledger(Storage): | ||||||
|             # Delete the preceding line to make the file |             # Delete the preceding line to make the file | ||||||
|             del_start -= 1 |             del_start -= 1 | ||||||
| 
 | 
 | ||||||
|  |         _log.info('Removing transaction with ID: %s (lines %d-%d)', | ||||||
|  |                    transaction_id, | ||||||
|  |                    del_start, | ||||||
|  |                    semantic_lines['next_transaction_or_eof']) | ||||||
|  | 
 | ||||||
|         del lines[del_start:semantic_lines['next_transaction_or_eof']] |         del lines[del_start:semantic_lines['next_transaction_or_eof']] | ||||||
| 
 | 
 | ||||||
|         with open(self.ledger_file, 'w') as f: |         with open(self.ledger_file, 'w') as f: | ||||||
|  | @ -444,6 +451,7 @@ class Ledger(Storage): | ||||||
| 
 | 
 | ||||||
|         self.add_transaction(transaction) |         self.add_transaction(transaction) | ||||||
| 
 | 
 | ||||||
|  |         _log.info('Updated transaction %s', transaction.id) | ||||||
|         _log.debug('Updated transaction from: %s to: %s', old_transaction, |         _log.debug('Updated transaction from: %s to: %s', old_transaction, | ||||||
|                    transaction) |                    transaction) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								accounting/tests/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								accounting/tests/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										276
									
								
								accounting/tests/test_transactions.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								accounting/tests/test_transactions.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,276 @@ | ||||||
|  | ''' | ||||||
|  | Tests for accounting-api | ||||||
|  | ''' | ||||||
|  | import os | ||||||
|  | import unittest | ||||||
|  | import tempfile | ||||||
|  | import logging | ||||||
|  | import copy | ||||||
|  | import uuid | ||||||
|  | 
 | ||||||
|  | from datetime import datetime | ||||||
|  | 
 | ||||||
|  | from flask import json | ||||||
|  | 
 | ||||||
|  | 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) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TransactionTestCase(unittest.TestCase): | ||||||
|  |     def setUp(self): | ||||||
|  |         self.app = app.test_client() | ||||||
|  |         self.fd, app.config['LEDGER_FILE'] = tempfile.mkstemp() | ||||||
|  |         init_ledger() | ||||||
|  |         self.simple_transaction = Transaction( | ||||||
|  |             date=datetime.today(), | ||||||
|  |             payee='Joar', | ||||||
|  |             postings=[ | ||||||
|  |                 Posting('Assets:Checking', Amount('-133.7', 'USD')), | ||||||
|  |                 Posting('Expenses:Foo', Amount('133.7', 'USD')) | ||||||
|  |             ] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def tearDown(self): | ||||||
|  |         os.close(self.fd) | ||||||
|  |         os.unlink(app.config['LEDGER_FILE']) | ||||||
|  | 
 | ||||||
|  |     def test_get_transactions(self): | ||||||
|  |         open(app.config['LEDGER_FILE'], 'w').write( | ||||||
|  |             '1400-12-21 Old stuff\n' | ||||||
|  |             '  ;Id: foo\n' | ||||||
|  |             '  Assets:Checking  -100 USD\n' | ||||||
|  |             '  Expenses:Tax  100 USD\n') | ||||||
|  |         rv = self.app.get('/transaction') | ||||||
|  | 
 | ||||||
|  |         json_transaction = ( | ||||||
|  |             b'{\n' | ||||||
|  |             b'  "transactions": [\n' | ||||||
|  |             b'    {\n' | ||||||
|  |             b'      "__type__": "Transaction", \n' | ||||||
|  |             b'      "date": "1400-12-21", \n' | ||||||
|  |             b'      "id": "foo", \n' | ||||||
|  |             b'      "metadata": {}, \n' | ||||||
|  |             b'      "payee": "Old stuff", \n' | ||||||
|  |             b'      "postings": [\n' | ||||||
|  |             b'        {\n' | ||||||
|  |             b'          "__type__": "Posting", \n' | ||||||
|  |             b'          "account": "Assets:Checking", \n' | ||||||
|  |             b'          "amount": {\n' | ||||||
|  |             b'            "__type__": "Amount", \n' | ||||||
|  |             b'            "amount": "-100", \n' | ||||||
|  |             b'            "symbol": "USD"\n' | ||||||
|  |             b'          }, \n' | ||||||
|  |             b'          "metadata": {}\n' | ||||||
|  |             b'        }, \n' | ||||||
|  |             b'        {\n' | ||||||
|  |             b'          "__type__": "Posting", \n' | ||||||
|  |             b'          "account": "Expenses:Tax", \n' | ||||||
|  |             b'          "amount": {\n' | ||||||
|  |             b'            "__type__": "Amount", \n' | ||||||
|  |             b'            "amount": "100", \n' | ||||||
|  |             b'            "symbol": "USD"\n' | ||||||
|  |             b'          }, \n' | ||||||
|  |             b'          "metadata": {}\n' | ||||||
|  |             b'        }\n' | ||||||
|  |             b'      ]\n' | ||||||
|  |             b'    }\n' | ||||||
|  |             b'  ]\n' | ||||||
|  |             b'}') | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(rv.get_data(), json_transaction) | ||||||
|  | 
 | ||||||
|  |     def _post_json(self, path, data, expect=200, **kw): | ||||||
|  |         response = self.app.post( | ||||||
|  |             path, | ||||||
|  |             content_type='application/json', | ||||||
|  |             data=json.dumps(data, cls=AccountingEncoder), | ||||||
|  |             **kw | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response.status_code, expect) | ||||||
|  | 
 | ||||||
|  |         return self._decode_response(response) | ||||||
|  | 
 | ||||||
|  |     def _decode_response(self, response): | ||||||
|  |         return json.loads(response.data, cls=AccountingDecoder) | ||||||
|  | 
 | ||||||
|  |     def _get_json(self, path, expect=200, **kw): | ||||||
|  |         response = self.app.get(path, **kw) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response.status_code, expect) | ||||||
|  | 
 | ||||||
|  |         return self._decode_response(response) | ||||||
|  | 
 | ||||||
|  |     def _open_json(self, method, path, expect=200, **kw): | ||||||
|  |         response = self.app.open( | ||||||
|  |             path, | ||||||
|  |             method=method.upper(), | ||||||
|  |             **kw | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response.status_code, expect) | ||||||
|  | 
 | ||||||
|  |         return self._decode_response(response) | ||||||
|  | 
 | ||||||
|  |     def _add_simple_transaction(self, transaction_id=None): | ||||||
|  |         if transaction_id is None: | ||||||
|  |             transaction_id = str(uuid.uuid4()) | ||||||
|  | 
 | ||||||
|  |         transaction = copy.deepcopy(self.simple_transaction) | ||||||
|  |         transaction.id = transaction_id | ||||||
|  | 
 | ||||||
|  |         response = self._post_json('/transaction', transaction) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(len(response['transaction_ids']), 1) | ||||||
|  |         self.assertEqual(response['status'], 'OK') | ||||||
|  | 
 | ||||||
|  |         response = self._get_json('/transaction/' + transaction.id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(transaction_id, response['transaction'].id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response['transaction'], transaction) | ||||||
|  | 
 | ||||||
|  |         return transaction | ||||||
|  | 
 | ||||||
|  |     def test_post_transaction_without_id(self): | ||||||
|  |         transaction = copy.deepcopy(self.simple_transaction) | ||||||
|  | 
 | ||||||
|  |         response = self._post_json('/transaction', transaction) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(len(response['transaction_ids']), 1) | ||||||
|  |         self.assertEqual(response['status'], 'OK') | ||||||
|  | 
 | ||||||
|  |         transaction.id = response['transaction_ids'][0] | ||||||
|  | 
 | ||||||
|  |         response = self._get_json('/transaction/' + transaction.id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response['transaction'], transaction) | ||||||
|  | 
 | ||||||
|  |     def test_delete_transaction(self): | ||||||
|  |         transaction = copy.deepcopy(self.simple_transaction) | ||||||
|  | 
 | ||||||
|  |         response = self._post_json('/transaction', transaction) | ||||||
|  | 
 | ||||||
|  |         transaction_id = response['transaction_ids'][0] | ||||||
|  | 
 | ||||||
|  |         self.assertIsNotNone(transaction_id) | ||||||
|  | 
 | ||||||
|  |         response = self._open_json('DELETE', | ||||||
|  |                                   '/transaction/' + transaction_id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(response['status'], 'OK') | ||||||
|  | 
 | ||||||
|  |         with self.assertRaises(ValueError): | ||||||
|  |             # ValueError thrown because the response does not contain any JSON | ||||||
|  |             response = self._get_json('/transaction/' + transaction_id, 404) | ||||||
|  | 
 | ||||||
|  |     def test_post_multiple_transactions(self): | ||||||
|  |         transactions = [ | ||||||
|  |             Transaction( | ||||||
|  |                 date=datetime.today(), | ||||||
|  |                 payee='Rent', | ||||||
|  |                 postings=[ | ||||||
|  |                     Posting( | ||||||
|  |                         account='Assets:Checking', | ||||||
|  |                         amount=Amount(amount='-4600.00', symbol='SEK') | ||||||
|  |                     ), | ||||||
|  |                     Posting( | ||||||
|  |                         account='Expenses:Rent', | ||||||
|  |                         amount=Amount(amount='4600.00', symbol='SEK') | ||||||
|  |                     ) | ||||||
|  |                 ] | ||||||
|  |             ), | ||||||
|  |             Transaction( | ||||||
|  |                 date=datetime.today(), | ||||||
|  |                 payee='Hosting', | ||||||
|  |                 postings=[ | ||||||
|  |                     Posting( | ||||||
|  |                         account='Assets:Checking', | ||||||
|  |                         amount=Amount(amount='-700.00', symbol='SEK') | ||||||
|  |                     ), | ||||||
|  |                     Posting( | ||||||
|  |                         account='Expenses:Hosting', | ||||||
|  |                         amount=Amount(amount='700.00', symbol='SEK') | ||||||
|  |                     ) | ||||||
|  |                 ] | ||||||
|  |             ) | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|  |         response = self._post_json('/transaction', | ||||||
|  |                                   {'transactions': transactions}) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(len(response['transaction_ids']), 2) | ||||||
|  | 
 | ||||||
|  |         transactions[0].id = response['transaction_ids'][0] | ||||||
|  |         transactions[1].id = response['transaction_ids'][1] | ||||||
|  | 
 | ||||||
|  |         response = self._get_json('/transaction/' + transactions[0].id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(transactions[0], response['transaction']) | ||||||
|  | 
 | ||||||
|  |         response = self._get_json('/transaction/' + transactions[1].id) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(transactions[1], response['transaction']) | ||||||
|  | 
 | ||||||
|  |     def test_update_transaction_payee(self): | ||||||
|  |         transaction = self._add_simple_transaction() | ||||||
|  | 
 | ||||||
|  |         transaction.payee = 'not Joar' | ||||||
|  | 
 | ||||||
|  |         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_update_transaction_postings(self): | ||||||
|  |         transaction = self._add_simple_transaction() | ||||||
|  | 
 | ||||||
|  |         postings = [ | ||||||
|  |             Posting(account='Assets:Checking', | ||||||
|  |                     amount=Amount(amount='-733.10', symbol='SEK')), | ||||||
|  |             Posting(account='Expenses:Bar', | ||||||
|  |                     amount=Amount(amount='733.10', symbol='SEK')) | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|  |         transaction.postings = postings | ||||||
|  | 
 | ||||||
|  |         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_post_unbalanced_transaction(self): | ||||||
|  |         transaction = Transaction( | ||||||
|  |             date=datetime.today(), | ||||||
|  |             payee='Unbalanced Transaction', | ||||||
|  |             postings=[ | ||||||
|  |                 Posting(account='Assets:Checking', | ||||||
|  |                         amount=Amount(amount='100.00', symbol='USD')), | ||||||
|  |                 Posting(account='Income:Foo', | ||||||
|  |                         amount=Amount(amount='-100.01', symbol='USD')) | ||||||
|  |             ] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         self._post_json('/transaction', transaction) | ||||||
|  | 
 | ||||||
|  |         response = self._get_json('/transaction') | ||||||
|  | 
 | ||||||
|  |         import pdb; pdb.set_trace() | ||||||
|  | 
 | ||||||
|  |     def test_update_transaction_amounts(self): pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     unittest.main() | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Joar Wandborg
						Joar Wandborg