def setUp(self): # Start dummy server util.baseUrl = 'http://*****:*****@test.com', 'pass': '******' } self.settings.investing = { 'minCash': 100, 'minPercent': 16.5, 'maxPercent': 19.0, 'portfolio': 'Existing Portfolio', 'filters': False } self.investor = AutoInvestor(settings=self.settings) self.investor.app_dir = base_dir self.investor.logger = logger
class TestInvestorFlow(unittest.TestCase): """ Tests the investor flow and communication with LendingClub """ server = None investor = None settings = None def startNode(self): """ Start the node server, if it's not already running """ # Check if it's running try: if urllib.urlopen('http://*****:*****@test.com', 'pass': '******' } self.settings.investing = { 'minCash': 100, 'minPercent': 16.5, 'maxPercent': 19.0, 'portfolio': 'Existing Portfolio', 'filters': False } self.investor = AutoInvestor(settings=self.settings) self.investor.app_dir = base_dir self.investor.logger = logger def tearDown(self): # Stop node if(self.server): self.server.kill() # Delete settings file if os.path.exists(self.settings.settings_dir): shutil.rmtree(self.settings.settings_dir) def set_default_filters(self): """ Sets all the filters to default valeus (True) """ self.settings.investing['filters'] = { 'exclude_existing': True, 'term36month': True, 'term60month': True, 'grades': { 'All': True, 'A': True, 'B': True, 'C': True, 'D': True, 'E': True, 'F': True, 'G': True } } def set_filters(self): """ Add advanced filtering to the investor settings """ self.set_default_filters() self.settings.investing['filters']['term36month'] = False self.settings.investing['filters']['grades']['All'] = False self.settings.investing['filters']['grades']['D'] = False self.settings.investing['filters']['grades']['E'] = False self.settings.investing['filters']['grades']['F'] = False self.settings.investing['filters']['grades']['G'] = False def test_login(self): self.assertTrue(self.investor.authenticate()) def test_invalid_login(self): self.settings.auth['email'] = '*****@*****.**' self.assertFalse(self.investor.authenticate()) def test_get_cash_balance(self): self.assertEqual(self.investor.get_cash_balance(), 216.02) def test_portfolios(self): portfolios = self.investor.get_portfolio_list() self.assertEquals(len(portfolios), 2) self.assertEquals(portfolios[0], 'Existing Portfolio') def test_investment_option(self): """ Match settings to investment options -- closest match should be 18.66 """ match = self.investor.get_investment_option(200) self.assertEqual(match['percentage'], 18.66) def test_investment_option_minimums(self): """ Test min percent: no investment options between 18.7 - 19.0 """ self.settings.investing['minPercent'] = 18.7 match = self.investor.get_investment_option(200) self.assertFalse(match) def test_investment_options_summary(self): """ Test the options summary output """ match = self.investor.get_investment_option(200) summary = self.investor.get_option_summary(match) expected = 'Investment portfolio summary: 8 loan notes. 13% in B, 38% in C, 13% in D, 13% in E, 25% in F.' self.assertEqual(summary, expected) def test_investment_option_filters_below_percent(self): """ Investment Options within below percent settings. With filters set, the fixture data will return options below the min/max percent settings """ self.set_filters() match = self.investor.get_investment_option(200) self.assertFalse(match) def test_investment_option_filters_break_server_grades(self): """ test_investment_option_filters_break_server_grades Test the server logic for checking grades. The server is expecting A,B,C and should raise an error if it sees anything else""" self.set_filters() self.settings.investing['filters']['grades']['All'] = True self.settings.investing['filters']['grades']['G'] = True match = self.investor.get_investment_option(200) # Check for error self.assertFalse(match) self.assertEqual(len(self.investor.logger.errors), 1) def test_investment_option_filters_break_server_json(self): """ test_investment_option_filters_break_server_json Test the server logic for parsing the JSON feed. The server should raise an error for invalid JSON""" # Create a request with bad JSON formerFilterFunc = util.get_filter_json util.get_filter_json = lambda settings: '{invalid json feed,,}' match = self.investor.get_investment_option(200) # Check for error self.assertFalse(match) self.assertEqual(len(self.investor.logger.errors), 1) # Reset util.get_filter_json = formerFilterFunc def test_investment_option_filters_within_percent(self): """ Investment Options within percent settings. Set min/max settings to be within options returned with filters """ self.set_filters() # Default min/max are 16.5 - 19.0, filtered results fixture only goes up to 15.03 self.settings.investing['minPercent'] = 13.0 self.settings.investing['maxPercent'] = 14.5 match = self.investor.get_investment_option(200) self.assertEqual(match['percentage'], 14.5) # should be a perfect match def test_investment_option_validate(self): """ test_investment_option_validate Test validating an option against advanced filters """ match = self.investor.get_investment_option(200) # Initial match should be True self.assertEqual(match['percentage'], 18.66) self.assertTrue(self.investor.validate_option(match)) # Set C to False, everything else true self.set_default_filters() self.assertTrue(self.investor.validate_option(match)) # defaults should be True self.settings.investing['filters']['grades']['All'] = False self.settings.investing['filters']['grades']['C'] = False self.assertFalse(self.investor.validate_option(match)) # False # Set 36 month to False, everything else true self.set_default_filters() self.assertTrue(self.investor.validate_option(match)) # defaults should be True self.settings.investing['filters']['term36month'] = False self.assertFalse(self.investor.validate_option(match)) # False # Set 60 month to False, everything else true self.set_default_filters() self.assertTrue(self.investor.validate_option(match)) # defaults should be True self.settings.investing['filters']['term60month'] = False self.assertFalse(self.investor.validate_option(match)) # False def test_prepare_order(self): investmentOption = self.investor.get_investment_option(200) strutToken = self.investor.prepare_investment_order(200, investmentOption) self.assertEqual(strutToken, 'abc123') def test_place_order(self): investmentOption = self.investor.get_investment_option(200) (orderID, loanIDs) = self.investor.place_order('abc123', 200, investmentOption) self.assertEqual(orderID, 123) self.assertEqual(loanIDs, [345]) def test_assign_to_porfolio_existing(self): """ Assign to an existing portfolio """ ret = self.investor.assign_to_portfolio(orderID=123, loanIDs=[456], returnJson=True) self.assertEqual(ret['result'], 'success') self.assertEqual(ret['portfolioName'], 'Existing Portfolio') # hard coded in the JSON response # Should have no errors or warnings self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_assign_to_porfolio_new(self): """ Assign to a new portfolio """ self.settings.investing['portfolio'] = 'New Porfolio' ret = self.investor.assign_to_portfolio(orderID=123, loanIDs=[456], returnJson=True) self.assertEqual(ret['result'], 'success') self.assertEqual(ret['portfolioName'], 'New Portfolio') # hard coded in the JSON response # Should have no errors or warnings self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_assign_to_porfolio_incorrect_assignment(self): """ Test warning if order is assigned to the wrong portfolio. The server responds with JSON containing the portfolio name your order was assigned to. There's no reason to think these would be difference, but if they are, assign_to_portfolio should still return True, but add a warning to the log. (easy to test, since the mock server returns hard coded JSON) """ self.settings.investing['portfolio'] = 'A Folio' # server will respond with 'New Portfolio' ret = self.investor.assign_to_portfolio(orderID=123, loanIDs=[456]) self.assertTrue(ret) # Should have 1 warnings and 0 errors self.assertEqual(len(self.investor.logger.warnings), 1) self.assertEqual(len(self.investor.logger.errors), 0) def test_assign_to_porfolio_no_order(self): """ Assigning to portfolio without an order ID """ ret = self.investor.assign_to_portfolio(loanIDs=[456]) self.assertFalse(ret) def test_assign_to_porfolio_no_loan(self): """ Assigning to portfolio without a loan ID """ ret = self.investor.assign_to_portfolio(orderID=123) self.assertFalse(ret) def test_assign_to_porfolio_no_portfolio(self): """ Test if not assigning to porfolio assign_to_portfolio() should return True """ self.settings.investing['portfolio'] = False ret = self.investor.assign_to_portfolio(orderID=123, loanIDs=[456]) self.assertTrue(ret) # Should be no errors or info self.assertEqual(len(self.investor.logger.infos), 0) self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_attempt_to_invest(self): """ test_attempt_to_invest() - Test end-to-end investment """ ret = self.investor.attempt_to_invest() self.assertTrue(ret) # Shouldn't be any errors or warnings self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_attempt_to_invest_no_folio(self): """ Test end-to-end investment without portfolio """ self.settings.investing['portfolio'] = False ret = self.investor.attempt_to_invest() self.assertTrue(ret) # Shouldn't be any errors or warnings self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_attempt_to_invest_not_enough_cash(self): """ Test end-to-end investment without portfolio """ self.settings.investing['minCash'] = 1000 ret = self.investor.attempt_to_invest() self.assertFalse(ret) # Shouldn't be any errors or warnings self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 0) def test_attempt_to_invest_no_option_match(self): """ Test end-to-end investment without investment option match """ # No options between 18.7 - 19.0 self.settings.investing['minPercent'] = 18.7 ret = self.investor.attempt_to_invest() self.assertFalse(ret) # Should be 0 errors and 1 warning self.assertEqual(len(self.investor.logger.errors), 0) self.assertEqual(len(self.investor.logger.warnings), 1)