diff options
Diffstat (limited to 'tests/test_market.py')
-rw-r--r-- | tests/test_market.py | 192 |
1 files changed, 127 insertions, 65 deletions
diff --git a/tests/test_market.py b/tests/test_market.py index 14b23b5..e3482b8 100644 --- a/tests/test_market.py +++ b/tests/test_market.py | |||
@@ -530,23 +530,55 @@ class MarketTest(WebMockTestCase): | |||
530 | m.store_database_report(datetime.datetime(2018, 3, 24)) | 530 | m.store_database_report(datetime.datetime(2018, 3, 24)) |
531 | self.assertEqual(stdout_mock.getvalue(), "impossible to store report to database: Exception; Bouh\n") | 531 | self.assertEqual(stdout_mock.getvalue(), "impossible to store report to database: Exception; Bouh\n") |
532 | 532 | ||
533 | @mock.patch.object(market, "redis") | ||
534 | def test_store_redis_report(self, redis): | ||
535 | connect_mock = mock.Mock() | ||
536 | redis.Redis.return_value = connect_mock | ||
537 | |||
538 | m = market.Market(self.ccxt, self.market_args(), | ||
539 | redis_config={"config": "redis_config"}, market_id=1) | ||
540 | |||
541 | with self.subTest(error=False),\ | ||
542 | mock.patch.object(m, "report") as report: | ||
543 | report.to_json_redis.return_value = [ | ||
544 | ("type1", "payload1"), | ||
545 | ("type2", "payload2"), | ||
546 | ] | ||
547 | m.store_redis_report(datetime.datetime(2018, 3, 24)) | ||
548 | connect_mock.assert_has_calls([ | ||
549 | mock.call.set("/cryptoportfolio/1/2018-03-24T00:00:00/type1", "payload1", ex=31*24*60*60), | ||
550 | mock.call.set("/cryptoportfolio/1/latest/type1", "payload1"), | ||
551 | mock.call.set("/cryptoportfolio/1/2018-03-24T00:00:00/type2", "payload2", ex=31*24*60*60), | ||
552 | mock.call.set("/cryptoportfolio/1/latest/type2", "payload2"), | ||
553 | ]) | ||
554 | |||
555 | connect_mock.reset_mock() | ||
556 | with self.subTest(error=True),\ | ||
557 | mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock: | ||
558 | redis.Redis.side_effect = Exception("Bouh") | ||
559 | m.store_redis_report(datetime.datetime(2018, 3, 24)) | ||
560 | self.assertEqual(stdout_mock.getvalue(), "impossible to store report to redis: Exception; Bouh\n") | ||
561 | |||
533 | def test_store_report(self): | 562 | def test_store_report(self): |
534 | m = market.Market(self.ccxt, self.market_args(report_db=False), user_id=1) | 563 | m = market.Market(self.ccxt, self.market_args(report_db=False), user_id=1) |
535 | with self.subTest(file=None, pg_config=None),\ | 564 | with self.subTest(file=None, pg_config=None),\ |
536 | mock.patch.object(m, "report") as report,\ | 565 | mock.patch.object(m, "report") as report,\ |
537 | mock.patch.object(m, "store_database_report") as db_report,\ | 566 | mock.patch.object(m, "store_database_report") as db_report,\ |
567 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
538 | mock.patch.object(m, "store_file_report") as file_report: | 568 | mock.patch.object(m, "store_file_report") as file_report: |
539 | m.store_report() | 569 | m.store_report() |
540 | report.merge.assert_called_with(store.Portfolio.report) | 570 | report.merge.assert_called_with(store.Portfolio.report) |
541 | 571 | ||
542 | file_report.assert_not_called() | 572 | file_report.assert_not_called() |
543 | db_report.assert_not_called() | 573 | db_report.assert_not_called() |
574 | redis_report.assert_not_called() | ||
544 | 575 | ||
545 | report.reset_mock() | 576 | report.reset_mock() |
546 | m = market.Market(self.ccxt, self.market_args(report_db=False, report_path="present"), user_id=1) | 577 | m = market.Market(self.ccxt, self.market_args(report_db=False, report_path="present"), user_id=1) |
547 | with self.subTest(file="present", pg_config=None),\ | 578 | with self.subTest(file="present", pg_config=None),\ |
548 | mock.patch.object(m, "report") as report,\ | 579 | mock.patch.object(m, "report") as report,\ |
549 | mock.patch.object(m, "store_file_report") as file_report,\ | 580 | mock.patch.object(m, "store_file_report") as file_report,\ |
581 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
550 | mock.patch.object(m, "store_database_report") as db_report,\ | 582 | mock.patch.object(m, "store_database_report") as db_report,\ |
551 | mock.patch.object(market.datetime, "datetime") as time_mock: | 583 | mock.patch.object(market.datetime, "datetime") as time_mock: |
552 | 584 | ||
@@ -557,12 +589,14 @@ class MarketTest(WebMockTestCase): | |||
557 | report.merge.assert_called_with(store.Portfolio.report) | 589 | report.merge.assert_called_with(store.Portfolio.report) |
558 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | 590 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) |
559 | db_report.assert_not_called() | 591 | db_report.assert_not_called() |
592 | redis_report.assert_not_called() | ||
560 | 593 | ||
561 | report.reset_mock() | 594 | report.reset_mock() |
562 | m = market.Market(self.ccxt, self.market_args(report_db=True, report_path="present"), user_id=1) | 595 | m = market.Market(self.ccxt, self.market_args(report_db=True, report_path="present"), user_id=1) |
563 | with self.subTest(file="present", pg_config=None, report_db=True),\ | 596 | with self.subTest(file="present", pg_config=None, report_db=True),\ |
564 | mock.patch.object(m, "report") as report,\ | 597 | mock.patch.object(m, "report") as report,\ |
565 | mock.patch.object(m, "store_file_report") as file_report,\ | 598 | mock.patch.object(m, "store_file_report") as file_report,\ |
599 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
566 | mock.patch.object(m, "store_database_report") as db_report,\ | 600 | mock.patch.object(m, "store_database_report") as db_report,\ |
567 | mock.patch.object(market.datetime, "datetime") as time_mock: | 601 | mock.patch.object(market.datetime, "datetime") as time_mock: |
568 | 602 | ||
@@ -573,12 +607,14 @@ class MarketTest(WebMockTestCase): | |||
573 | report.merge.assert_called_with(store.Portfolio.report) | 607 | report.merge.assert_called_with(store.Portfolio.report) |
574 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | 608 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) |
575 | db_report.assert_not_called() | 609 | db_report.assert_not_called() |
610 | redis_report.assert_not_called() | ||
576 | 611 | ||
577 | report.reset_mock() | 612 | report.reset_mock() |
578 | m = market.Market(self.ccxt, self.market_args(report_db=True), pg_config="present", user_id=1) | 613 | m = market.Market(self.ccxt, self.market_args(report_db=True), pg_config="present", user_id=1) |
579 | with self.subTest(file=None, pg_config="present"),\ | 614 | with self.subTest(file=None, pg_config="present"),\ |
580 | mock.patch.object(m, "report") as report,\ | 615 | mock.patch.object(m, "report") as report,\ |
581 | mock.patch.object(m, "store_file_report") as file_report,\ | 616 | mock.patch.object(m, "store_file_report") as file_report,\ |
617 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
582 | mock.patch.object(m, "store_database_report") as db_report,\ | 618 | mock.patch.object(m, "store_database_report") as db_report,\ |
583 | mock.patch.object(market.datetime, "datetime") as time_mock: | 619 | mock.patch.object(market.datetime, "datetime") as time_mock: |
584 | 620 | ||
@@ -589,6 +625,7 @@ class MarketTest(WebMockTestCase): | |||
589 | report.merge.assert_called_with(store.Portfolio.report) | 625 | report.merge.assert_called_with(store.Portfolio.report) |
590 | file_report.assert_not_called() | 626 | file_report.assert_not_called() |
591 | db_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | 627 | db_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) |
628 | redis_report.assert_not_called() | ||
592 | 629 | ||
593 | report.reset_mock() | 630 | report.reset_mock() |
594 | m = market.Market(self.ccxt, self.market_args(report_db=True, report_path="present"), | 631 | m = market.Market(self.ccxt, self.market_args(report_db=True, report_path="present"), |
@@ -596,6 +633,7 @@ class MarketTest(WebMockTestCase): | |||
596 | with self.subTest(file="present", pg_config="present"),\ | 633 | with self.subTest(file="present", pg_config="present"),\ |
597 | mock.patch.object(m, "report") as report,\ | 634 | mock.patch.object(m, "report") as report,\ |
598 | mock.patch.object(m, "store_file_report") as file_report,\ | 635 | mock.patch.object(m, "store_file_report") as file_report,\ |
636 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
599 | mock.patch.object(m, "store_database_report") as db_report,\ | 637 | mock.patch.object(m, "store_database_report") as db_report,\ |
600 | mock.patch.object(market.datetime, "datetime") as time_mock: | 638 | mock.patch.object(market.datetime, "datetime") as time_mock: |
601 | 639 | ||
@@ -606,22 +644,54 @@ class MarketTest(WebMockTestCase): | |||
606 | report.merge.assert_called_with(store.Portfolio.report) | 644 | report.merge.assert_called_with(store.Portfolio.report) |
607 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | 645 | file_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) |
608 | db_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | 646 | db_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) |
647 | redis_report.assert_not_called() | ||
609 | 648 | ||
610 | def test_print_orders(self): | 649 | report.reset_mock() |
611 | m = market.Market(self.ccxt, self.market_args()) | 650 | m = market.Market(self.ccxt, self.market_args(report_redis=False), |
612 | with mock.patch.object(m.report, "log_stage") as log_stage,\ | 651 | redis_config="redis_config", user_id=1) |
613 | mock.patch.object(m.balances, "fetch_balances") as fetch_balances,\ | 652 | with self.subTest(redis_config="present", report_redis=False),\ |
614 | mock.patch.object(m, "prepare_trades") as prepare_trades,\ | 653 | mock.patch.object(m, "report") as report,\ |
615 | mock.patch.object(m.trades, "prepare_orders") as prepare_orders: | 654 | mock.patch.object(m, "store_file_report") as file_report,\ |
616 | m.print_orders() | 655 | mock.patch.object(m, "store_redis_report") as redis_report,\ |
656 | mock.patch.object(m, "store_database_report") as db_report,\ | ||
657 | mock.patch.object(market.datetime, "datetime") as time_mock: | ||
617 | 658 | ||
618 | log_stage.assert_called_with("print_orders") | 659 | time_mock.now.return_value = datetime.datetime(2018, 2, 25) |
619 | fetch_balances.assert_called_with(tag="print_orders") | ||
620 | prepare_trades.assert_called_with(base_currency="BTC", | ||
621 | compute_value="average") | ||
622 | prepare_orders.assert_called_with(compute_value="average") | ||
623 | 660 | ||
624 | def test_print_balances(self): | 661 | m.store_report() |
662 | redis_report.assert_not_called() | ||
663 | |||
664 | report.reset_mock() | ||
665 | m = market.Market(self.ccxt, self.market_args(report_redis=True), | ||
666 | user_id=1) | ||
667 | with self.subTest(redis_config="absent", report_redis=True),\ | ||
668 | mock.patch.object(m, "report") as report,\ | ||
669 | mock.patch.object(m, "store_file_report") as file_report,\ | ||
670 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
671 | mock.patch.object(m, "store_database_report") as db_report,\ | ||
672 | mock.patch.object(market.datetime, "datetime") as time_mock: | ||
673 | |||
674 | time_mock.now.return_value = datetime.datetime(2018, 2, 25) | ||
675 | |||
676 | m.store_report() | ||
677 | redis_report.assert_not_called() | ||
678 | |||
679 | report.reset_mock() | ||
680 | m = market.Market(self.ccxt, self.market_args(report_redis=True), | ||
681 | redis_config="redis_config", user_id=1) | ||
682 | with self.subTest(redis_config="present", report_redis=True),\ | ||
683 | mock.patch.object(m, "report") as report,\ | ||
684 | mock.patch.object(m, "store_file_report") as file_report,\ | ||
685 | mock.patch.object(m, "store_redis_report") as redis_report,\ | ||
686 | mock.patch.object(m, "store_database_report") as db_report,\ | ||
687 | mock.patch.object(market.datetime, "datetime") as time_mock: | ||
688 | |||
689 | time_mock.now.return_value = datetime.datetime(2018, 2, 25) | ||
690 | |||
691 | m.store_report() | ||
692 | redis_report.assert_called_once_with(datetime.datetime(2018, 2, 25)) | ||
693 | |||
694 | def test_print_tickers(self): | ||
625 | m = market.Market(self.ccxt, self.market_args()) | 695 | m = market.Market(self.ccxt, self.market_args()) |
626 | 696 | ||
627 | with mock.patch.object(m.balances, "in_currency") as in_currency,\ | 697 | with mock.patch.object(m.balances, "in_currency") as in_currency,\ |
@@ -634,10 +704,8 @@ class MarketTest(WebMockTestCase): | |||
634 | "ETH": portfolio.Amount("BTC", "0.3"), | 704 | "ETH": portfolio.Amount("BTC", "0.3"), |
635 | } | 705 | } |
636 | 706 | ||
637 | m.print_balances() | 707 | m.print_tickers() |
638 | 708 | ||
639 | log_stage.assert_called_once_with("print_balances") | ||
640 | fetch_balances.assert_called_with() | ||
641 | print_log.assert_has_calls([ | 709 | print_log.assert_has_calls([ |
642 | mock.call("total:"), | 710 | mock.call("total:"), |
643 | mock.call(portfolio.Amount("BTC", "0.95")), | 711 | mock.call(portfolio.Amount("BTC", "0.95")), |
@@ -648,8 +716,8 @@ class MarketTest(WebMockTestCase): | |||
648 | @mock.patch("market.Market.store_report") | 716 | @mock.patch("market.Market.store_report") |
649 | def test_process(self, store_report, log_error, process): | 717 | def test_process(self, store_report, log_error, process): |
650 | m = market.Market(self.ccxt, self.market_args()) | 718 | m = market.Market(self.ccxt, self.market_args()) |
651 | with self.subTest(before=False, after=False): | 719 | with self.subTest(actions=[], before=False, after=False): |
652 | m.process(None) | 720 | m.process([]) |
653 | 721 | ||
654 | process.assert_not_called() | 722 | process.assert_not_called() |
655 | store_report.assert_called_once() | 723 | store_report.assert_called_once() |
@@ -659,9 +727,9 @@ class MarketTest(WebMockTestCase): | |||
659 | log_error.reset_mock() | 727 | log_error.reset_mock() |
660 | store_report.reset_mock() | 728 | store_report.reset_mock() |
661 | with self.subTest(before=True, after=False): | 729 | with self.subTest(before=True, after=False): |
662 | m.process(None, before=True) | 730 | m.process(["foo"], before=True) |
663 | 731 | ||
664 | process.assert_called_once_with("sell_all", steps="before") | 732 | process.assert_called_once_with("foo", steps="before") |
665 | store_report.assert_called_once() | 733 | store_report.assert_called_once() |
666 | log_error.assert_not_called() | 734 | log_error.assert_not_called() |
667 | 735 | ||
@@ -669,7 +737,7 @@ class MarketTest(WebMockTestCase): | |||
669 | log_error.reset_mock() | 737 | log_error.reset_mock() |
670 | store_report.reset_mock() | 738 | store_report.reset_mock() |
671 | with self.subTest(before=False, after=True): | 739 | with self.subTest(before=False, after=True): |
672 | m.process(None, after=True) | 740 | m.process(["sell_all"], after=True) |
673 | 741 | ||
674 | process.assert_called_once_with("sell_all", steps="after") | 742 | process.assert_called_once_with("sell_all", steps="after") |
675 | store_report.assert_called_once() | 743 | store_report.assert_called_once() |
@@ -678,54 +746,30 @@ class MarketTest(WebMockTestCase): | |||
678 | process.reset_mock() | 746 | process.reset_mock() |
679 | log_error.reset_mock() | 747 | log_error.reset_mock() |
680 | store_report.reset_mock() | 748 | store_report.reset_mock() |
681 | with self.subTest(before=True, after=True): | 749 | with self.subTest(before=False, after=False): |
682 | m.process(None, before=True, after=True) | 750 | m.process(["foo"]) |
683 | 751 | ||
684 | process.assert_has_calls([ | 752 | process.assert_called_once_with("foo", steps="all") |
685 | mock.call("sell_all", steps="before"), | ||
686 | mock.call("sell_all", steps="after"), | ||
687 | ]) | ||
688 | store_report.assert_called_once() | 753 | store_report.assert_called_once() |
689 | log_error.assert_not_called() | 754 | log_error.assert_not_called() |
690 | 755 | ||
691 | process.reset_mock() | 756 | process.reset_mock() |
692 | log_error.reset_mock() | 757 | log_error.reset_mock() |
693 | store_report.reset_mock() | 758 | store_report.reset_mock() |
694 | with self.subTest(action="print_balances"),\ | 759 | with self.subTest(before=True, after=True): |
695 | mock.patch.object(m, "print_balances") as print_balances: | 760 | m.process(["sell_all"], before=True, after=True) |
696 | m.process(["print_balances"]) | ||
697 | 761 | ||
698 | process.assert_not_called() | 762 | process.assert_called_once_with("sell_all", steps="all") |
699 | log_error.assert_not_called() | ||
700 | store_report.assert_called_once() | 763 | store_report.assert_called_once() |
701 | print_balances.assert_called_once_with() | ||
702 | |||
703 | log_error.reset_mock() | ||
704 | store_report.reset_mock() | ||
705 | with self.subTest(action="print_orders"),\ | ||
706 | mock.patch.object(m, "print_orders") as print_orders,\ | ||
707 | mock.patch.object(m, "print_balances") as print_balances: | ||
708 | m.process(["print_orders", "print_balances"]) | ||
709 | |||
710 | process.assert_not_called() | ||
711 | log_error.assert_not_called() | 764 | log_error.assert_not_called() |
712 | store_report.assert_called_once() | ||
713 | print_orders.assert_called_once_with() | ||
714 | print_balances.assert_called_once_with() | ||
715 | |||
716 | log_error.reset_mock() | ||
717 | store_report.reset_mock() | ||
718 | with self.subTest(action="unknown"): | ||
719 | m.process(["unknown"]) | ||
720 | log_error.assert_called_once_with("market_process", message="Unknown action unknown") | ||
721 | store_report.assert_called_once() | ||
722 | 765 | ||
766 | process.reset_mock() | ||
723 | log_error.reset_mock() | 767 | log_error.reset_mock() |
724 | store_report.reset_mock() | 768 | store_report.reset_mock() |
725 | with self.subTest(unhandled_exception=True): | 769 | with self.subTest(unhandled_exception=True): |
726 | process.side_effect = Exception("bouh") | 770 | process.side_effect = Exception("bouh") |
727 | 771 | ||
728 | m.process(None, before=True) | 772 | m.process(["some_action"], before=True) |
729 | log_error.assert_called_with("market_process", exception=mock.ANY) | 773 | log_error.assert_called_with("market_process", exception=mock.ANY) |
730 | store_report.assert_called_once() | 774 | store_report.assert_called_once() |
731 | 775 | ||
@@ -768,24 +812,39 @@ class ProcessorTest(WebMockTestCase): | |||
768 | with self.assertRaises(TypeError): | 812 | with self.assertRaises(TypeError): |
769 | processor.select_steps(scenario, ["wait"]) | 813 | processor.select_steps(scenario, ["wait"]) |
770 | 814 | ||
815 | def test_can_process(self): | ||
816 | processor = market.Processor(self.m) | ||
817 | |||
818 | with self.subTest(True): | ||
819 | self.assertTrue(processor.can_process("sell_all")) | ||
820 | |||
821 | with self.subTest(False): | ||
822 | self.assertFalse(processor.can_process("unknown_action")) | ||
823 | |||
771 | @mock.patch("market.Processor.process_step") | 824 | @mock.patch("market.Processor.process_step") |
772 | def test_process(self, process_step): | 825 | def test_process(self, process_step): |
773 | processor = market.Processor(self.m) | 826 | with self.subTest("unknown action"): |
827 | processor = market.Processor(self.m) | ||
828 | with self.assertRaises(TypeError): | ||
829 | processor.process("unknown_action") | ||
774 | 830 | ||
775 | processor.process("sell_all", foo="bar") | 831 | with self.subTest("nominal case"): |
776 | self.assertEqual(3, process_step.call_count) | 832 | processor = market.Processor(self.m) |
777 | 833 | ||
778 | steps = list(map(lambda x: x[1][1]["name"], process_step.mock_calls)) | 834 | processor.process("sell_all", foo="bar") |
779 | scenario_names = list(map(lambda x: x[1][0], process_step.mock_calls)) | 835 | self.assertEqual(3, process_step.call_count) |
780 | kwargs = list(map(lambda x: x[1][2], process_step.mock_calls)) | ||
781 | self.assertEqual(["all_sell", "wait", "all_buy"], steps) | ||
782 | self.assertEqual(["sell_all", "sell_all", "sell_all"], scenario_names) | ||
783 | self.assertEqual([{"foo":"bar"}, {"foo":"bar"}, {"foo":"bar"}], kwargs) | ||
784 | 836 | ||
785 | process_step.reset_mock() | 837 | steps = list(map(lambda x: x[1][1]["name"], process_step.mock_calls)) |
838 | scenario_names = list(map(lambda x: x[1][0], process_step.mock_calls)) | ||
839 | kwargs = list(map(lambda x: x[1][2], process_step.mock_calls)) | ||
840 | self.assertEqual(["all_sell", "wait", "all_buy"], steps) | ||
841 | self.assertEqual(["sell_all", "sell_all", "sell_all"], scenario_names) | ||
842 | self.assertEqual([{"foo":"bar"}, {"foo":"bar"}, {"foo":"bar"}], kwargs) | ||
786 | 843 | ||
787 | processor.process("sell_needed", steps=["before", "after"]) | 844 | process_step.reset_mock() |
788 | self.assertEqual(3, process_step.call_count) | 845 | |
846 | processor.process("sell_needed", steps=["before", "after"]) | ||
847 | self.assertEqual(3, process_step.call_count) | ||
789 | 848 | ||
790 | def test_method_arguments(self): | 849 | def test_method_arguments(self): |
791 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) | 850 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) |
@@ -816,6 +875,9 @@ class ProcessorTest(WebMockTestCase): | |||
816 | method, arguments = processor.method_arguments("close_trades") | 875 | method, arguments = processor.method_arguments("close_trades") |
817 | self.assertEqual(m.trades.close_trades, method) | 876 | self.assertEqual(m.trades.close_trades, method) |
818 | 877 | ||
878 | method, arguments = processor.method_arguments("print_tickers") | ||
879 | self.assertEqual(m.print_tickers, method) | ||
880 | |||
819 | def test_process_step(self): | 881 | def test_process_step(self): |
820 | processor = market.Processor(self.m) | 882 | processor = market.Processor(self.m) |
821 | 883 | ||