1
1
import logging
2
2
import zipfile
3
- from contextlib import closing
3
+ from contextlib import closing , contextmanager
4
4
from datetime import datetime , timedelta
5
5
from io import BytesIO
6
6
from pathlib import Path
@@ -339,7 +339,7 @@ def report_table_call(processor):
339
339
result = report ._process_table (mock_table )
340
340
341
341
assert result .table_key == "test-table"
342
- assert result .filename == "palace-test_table_id -default-2024-01-01T12-00-00.csv"
342
+ assert result .filename == "palace-test-table -default-2024-01-01T12-00-00.csv"
343
343
assert result .row_count == 2
344
344
assert hasattr (result .content_stream , "read" )
345
345
@@ -494,7 +494,7 @@ def test_store_package_failure(
494
494
495
495
with pytest .raises (
496
496
IntegrationException ,
497
- match = r"Failed to store report 'test_report ' for library 'default' \(default\) to S3." ,
497
+ match = r"Failed to store report 'test-report ' for library 'default' \(default\) to S3." ,
498
498
):
499
499
report ._store_package (package )
500
500
@@ -592,25 +592,18 @@ def test_initialize_tables(
592
592
)
593
593
594
594
595
- class IntegrationLibraryCollectionReportFixture (LibraryCollectionReportFixture ):
595
+ class LibraryCollectionReportRunFixture (LibraryCollectionReportFixture ):
596
+
596
597
class MockLibraryCollectionReport (LibraryCollectionReport ):
597
598
KEY = "test-report"
598
599
TITLE = "Test Report"
600
+ # Note: No _run_report override - uses real implementation
599
601
602
+ def __init__ (self , db : DatabaseTransactionFixture ):
603
+ super ().__init__ (db )
600
604
601
- @pytest .fixture
602
- def integration_report_fixture (
603
- db : DatabaseTransactionFixture ,
604
- ) -> LibraryCollectionReportFixture :
605
- return IntegrationLibraryCollectionReportFixture (db )
606
-
607
-
608
- class TestLibraryCollectionRun :
609
-
610
- def test_run_success (
611
- self ,
612
- integration_report_fixture : LibraryCollectionReportFixture ,
613
- ):
605
+ def create_mock_table (self , * , should_fail : bool = False ):
606
+ """Create a mock table class and instance for testing."""
614
607
mock_table_class = MagicMock ()
615
608
mock_table_instance = MagicMock (spec = ReportTable )
616
609
mock_definition = MagicMock (
@@ -622,42 +615,62 @@ def test_run_success(
622
615
return_value = mock_definition
623
616
)
624
617
625
- def table_call (processor ):
626
- test_rows = [("header1" , "header2" ), ("data1" , "data2" )]
627
- counted_rows , _ = processor (rows = test_rows [1 :], headings = test_rows [0 ])
628
- return counted_rows , None
618
+ if should_fail :
619
+ exception = ValueError ("Table processing failed" )
620
+ mock_table_instance .side_effect = exception
621
+ else :
622
+
623
+ def table_call (processor ):
624
+ test_rows = [("data1" , "data2" ), ("data3" , "data4" )]
625
+ headings = ["col1" , "col2" ]
626
+ counted_rows , _ = processor (rows = test_rows , headings = headings )
627
+ return counted_rows , None
628
+
629
+ mock_table_instance .side_effect = table_call
629
630
630
- mock_table_instance .side_effect = table_call
631
631
mock_table_class .return_value = mock_table_instance
632
+ return mock_table_class
633
+
634
+ @contextmanager
635
+ def with_mock_table (self , * , should_fail : bool = False ):
636
+ """Context manager that sets up a mock table and patches TABLE_CLASSES."""
637
+ mock_table_class = self .create_mock_table (should_fail = should_fail )
632
638
633
639
with patch .object (
634
- integration_report_fixture .MockLibraryCollectionReport ,
640
+ self .MockLibraryCollectionReport ,
635
641
"TABLE_CLASSES" ,
636
642
[mock_table_class ],
637
643
):
638
- report = integration_report_fixture . report
644
+ yield mock_table_class
639
645
640
- expected_url = "https://s3.example.com/reports/test-report.zip"
641
- integration_report_fixture .s3_service .store_stream .return_value = (
642
- expected_url
643
- )
644
646
645
- success = report .run (session = integration_report_fixture .db .session )
647
+ @pytest .fixture
648
+ def report_run_fixture (
649
+ db : DatabaseTransactionFixture ,
650
+ ) -> LibraryCollectionReportRunFixture :
651
+ return LibraryCollectionReportRunFixture (db )
646
652
647
- assert success is True
648
653
649
- assert report .library == integration_report_fixture .db .default_library ()
654
+ class TestLibraryCollectionRun :
655
+
656
+ def test_run_full_integration (
657
+ self ,
658
+ report_run_fixture : LibraryCollectionReportRunFixture ,
659
+ ):
660
+ with report_run_fixture .with_mock_table ():
661
+ report = report_run_fixture .report
662
+ expected_url = "https://s3.example.com/reports/test-report.zip"
663
+ report_run_fixture .s3_service .store_stream .return_value = expected_url
664
+ success = report .run (session = report_run_fixture .db .session )
665
+
666
+ assert success is True
667
+ assert report .library == report_run_fixture .db .default_library ()
650
668
assert report .timestamp is not None
651
669
652
- mock_table_class .assert_called_once_with (
653
- session = integration_report_fixture .db .session ,
654
- library_id = integration_report_fixture .db .default_library ().id ,
655
- collection_ids = None ,
656
- )
670
+ report_run_fixture .s3_service .store_stream .assert_called_once ()
671
+ report_run_fixture .send_email .assert_called_once ()
657
672
658
- integration_report_fixture .s3_service .store_stream .assert_called_once ()
659
- integration_report_fixture .send_email .assert_called_once ()
660
- email_args = integration_report_fixture .send_email .call_args [1 ]
673
+ email_args = report_run_fixture .send_email .call_args [1 ]
661
674
assert email_args ["receivers" ] == report .email_address
662
675
assert (
663
676
"Palace report 'Test Report' for library 'default'"
@@ -668,36 +681,18 @@ def table_call(processor):
668
681
669
682
def test_run_table_processing_failure (
670
683
self ,
671
- integration_report_fixture : LibraryCollectionReportFixture ,
684
+ report_run_fixture : LibraryCollectionReportRunFixture ,
672
685
caplog : pytest .LogCaptureFixture ,
673
686
):
674
687
caplog .set_level (logging .ERROR )
675
688
676
- mock_table_class = MagicMock ()
677
- mock_table_instance = MagicMock (spec = ReportTable )
678
- mock_definition = MagicMock (
679
- spec = TabularQueryDefinition ,
680
- key = "test-table" ,
681
- title = "Test Table" ,
682
- )
683
- type(mock_table_instance ).definition = PropertyMock (
684
- return_value = mock_definition
685
- )
686
- mock_table_instance .side_effect = ValueError ("Table processing failed" )
687
- mock_table_class .return_value = mock_table_instance
688
-
689
- with patch .object (
690
- integration_report_fixture .MockLibraryCollectionReport ,
691
- "TABLE_CLASSES" ,
692
- [mock_table_class ],
693
- ):
694
-
695
- report = integration_report_fixture .report
696
- success = report .run (session = integration_report_fixture .db .session )
689
+ with report_run_fixture .with_mock_table (should_fail = True ):
690
+ report = report_run_fixture .report
691
+ success = report .run (session = report_run_fixture .db .session )
697
692
698
693
assert success is False
699
- integration_report_fixture .send_email .assert_called_once ()
700
- email_args = integration_report_fixture .send_email .call_args [1 ]
694
+ report_run_fixture .send_email .assert_called_once ()
695
+ email_args = report_run_fixture .send_email .call_args [1 ]
701
696
assert report .email_address == email_args ["receivers" ]
702
697
assert (
703
698
"Palace report 'Test Report' for library 'default'"
@@ -711,45 +706,20 @@ def test_run_table_processing_failure(
711
706
712
707
def test_run_packaging_failure (
713
708
self ,
714
- integration_report_fixture : LibraryCollectionReportFixture ,
709
+ report_run_fixture : LibraryCollectionReportRunFixture ,
715
710
caplog : pytest .LogCaptureFixture ,
716
711
):
717
712
caplog .set_level (logging .ERROR )
718
713
719
- mock_table_class = MagicMock ()
720
- mock_table_instance = MagicMock (spec = ReportTable )
721
- mock_definition = MagicMock (
722
- spec = TabularQueryDefinition ,
723
- key = "test-table" ,
724
- title = "Test Table" ,
725
- )
726
- type(mock_table_instance ).definition = PropertyMock (
727
- return_value = mock_definition
728
- )
729
-
730
- def table_call (processor ):
731
- counted_rows , _ = processor (
732
- rows = [("data1" , "data2" )], headings = ["col1" , "col2" ]
733
- )
734
- return counted_rows , None
735
-
736
- mock_table_instance .side_effect = table_call
737
- mock_table_class .return_value = mock_table_instance
738
-
739
- with patch .object (
740
- integration_report_fixture .MockLibraryCollectionReport ,
741
- "TABLE_CLASSES" ,
742
- [mock_table_class ],
743
- ):
744
- report = integration_report_fixture .report
745
-
746
- with patch .object (report , "_package_results" ) as mock_store_package :
747
- mock_store_package .side_effect = ValueError ("It didn't work." )
748
- success = report .run (session = integration_report_fixture .db .session )
714
+ with report_run_fixture .with_mock_table ():
715
+ report = report_run_fixture .report
716
+ with patch .object (report , "_package_results" ) as mock_packaging :
717
+ mock_packaging .side_effect = ValueError ("Packaging failed" )
718
+ success = report .run (session = report_run_fixture .db .session )
749
719
750
720
assert success is False
751
- integration_report_fixture .send_email .assert_called_once ()
752
- email_args = integration_report_fixture .send_email .call_args [1 ]
721
+ report_run_fixture .send_email .assert_called_once ()
722
+ email_args = report_run_fixture .send_email .call_args [1 ]
753
723
assert report .email_address == email_args ["receivers" ]
754
724
assert (
755
725
"Palace report 'Test Report' for library 'default'"
@@ -763,46 +733,19 @@ def table_call(processor):
763
733
764
734
def test_run_s3_storage_failure (
765
735
self ,
766
- integration_report_fixture : LibraryCollectionReportFixture ,
736
+ report_run_fixture : LibraryCollectionReportRunFixture ,
767
737
caplog : pytest .LogCaptureFixture ,
768
738
):
769
739
caplog .set_level (logging .ERROR )
770
740
771
- mock_table_class = MagicMock ()
772
- mock_table_instance = MagicMock (spec = ReportTable )
773
- mock_definition = MagicMock (
774
- spec = TabularQueryDefinition ,
775
- key = "test-table" ,
776
- title = "Test Table" ,
777
- )
778
- type(mock_table_instance ).definition = PropertyMock (
779
- return_value = mock_definition
780
- )
781
-
782
- def table_call (processor ):
783
- counted_rows , _ = processor (
784
- rows = [("data1" , "data2" )], headings = ["col1" , "col2" ]
785
- )
786
- return counted_rows , None
787
-
788
- mock_table_instance .side_effect = table_call
789
- mock_table_class .return_value = mock_table_instance
790
-
791
- with patch .object (
792
- integration_report_fixture .MockLibraryCollectionReport ,
793
- "TABLE_CLASSES" ,
794
- [mock_table_class ],
795
- ):
796
- report = integration_report_fixture .report
797
-
798
- integration_report_fixture .s3_service .store_stream .return_value = None
799
-
800
- success = report .run (session = integration_report_fixture .db .session )
741
+ with report_run_fixture .with_mock_table ():
742
+ report = report_run_fixture .report
743
+ report_run_fixture .s3_service .store_stream .return_value = None
744
+ success = report .run (session = report_run_fixture .db .session )
801
745
802
746
assert success is False
803
-
804
- integration_report_fixture .send_email .assert_called_once ()
805
- email_args = integration_report_fixture .send_email .call_args [1 ]
747
+ report_run_fixture .send_email .assert_called_once ()
748
+ email_args = report_run_fixture .send_email .call_args [1 ]
806
749
assert report .email_address == email_args ["receivers" ]
807
750
assert (
808
751
"Palace report 'Test Report' for library 'default'"
@@ -819,25 +762,23 @@ def table_call(processor):
819
762
820
763
def test_run_library_not_found (
821
764
self ,
822
- integration_report_fixture : LibraryCollectionReportFixture ,
765
+ report_run_fixture : LibraryCollectionReportRunFixture ,
823
766
caplog : pytest .LogCaptureFixture ,
824
767
):
825
768
caplog .set_level (logging .ERROR )
826
769
827
- report = integration_report_fixture .MockLibraryCollectionReport (
828
- send_email = integration_report_fixture .send_email ,
829
- s3_service = integration_report_fixture .s3_service ,
770
+ report = report_run_fixture .MockLibraryCollectionReport (
771
+ send_email = report_run_fixture .send_email ,
772
+ s3_service = report_run_fixture .s3_service ,
830
773
request_id = "test_request_id" ,
831
774
library_id = 999999 ,
832
775
email_address = "[email protected] " ,
833
776
)
834
-
835
- success = report .run (session = integration_report_fixture .db .session )
777
+ success = report .run (session = report_run_fixture .db .session )
836
778
837
779
assert success is False
838
-
839
- integration_report_fixture .send_email .assert_called_once ()
840
- email_args = integration_report_fixture .send_email .call_args [1 ]
780
+ report_run_fixture .send_email .assert_called_once ()
781
+ email_args = report_run_fixture .send_email .call_args [1 ]
841
782
assert report .email_address == email_args ["receivers" ]
842
783
assert (
843
784
"Palace report 'Test Report' for an unknown library"
@@ -855,52 +796,30 @@ def test_run_library_not_found(
855
796
856
797
def test_run_with_collection_ids (
857
798
self ,
858
- integration_report_fixture : LibraryCollectionReportFixture ,
799
+ report_run_fixture : LibraryCollectionReportRunFixture ,
859
800
):
860
- collection1 = integration_report_fixture .db .collection ()
861
- collection2 = integration_report_fixture .db .collection ()
801
+ collection1 = report_run_fixture .db .collection ()
802
+ collection2 = report_run_fixture .db .collection ()
862
803
collection_ids = [collection1 .id , collection2 .id ]
863
804
864
- report = integration_report_fixture .MockLibraryCollectionReport (
865
- send_email = integration_report_fixture .send_email ,
866
- s3_service = integration_report_fixture .s3_service ,
805
+ report = report_run_fixture .MockLibraryCollectionReport (
806
+ send_email = report_run_fixture .send_email ,
807
+ s3_service = report_run_fixture .s3_service ,
867
808
request_id = "test_request_id" ,
868
- library_id = integration_report_fixture .db .default_library ().id ,
809
+ library_id = report_run_fixture .db .default_library ().id ,
869
810
collection_ids = collection_ids ,
870
811
email_address = "[email protected] " ,
871
812
)
872
813
873
- mock_table_class = MagicMock ()
874
- mock_table_instance = MagicMock (spec = ReportTable )
875
- mock_definition = MagicMock (
876
- spec = TabularQueryDefinition , key = "test-table" , title = "Test Table"
877
- )
878
- type(mock_table_instance ).definition = PropertyMock (
879
- return_value = mock_definition
880
- )
881
-
882
- def table_call (processor ):
883
- counted_rows , _ = processor (rows = [("data" ,)], headings = ["col1" ])
884
- return counted_rows , None
885
-
886
- mock_table_instance .side_effect = table_call
887
- mock_table_class .return_value = mock_table_instance
888
-
889
- with patch .object (
890
- integration_report_fixture .MockLibraryCollectionReport ,
891
- "TABLE_CLASSES" ,
892
- [mock_table_class ],
893
- ):
894
- integration_report_fixture .s3_service .store_stream .return_value = (
814
+ with report_run_fixture .with_mock_table () as mock_table_class :
815
+ report_run_fixture .s3_service .store_stream .return_value = (
895
816
"https://s3.example.com/test.zip"
896
817
)
897
-
898
- success = report .run (session = integration_report_fixture .db .session )
818
+ success = report .run (session = report_run_fixture .db .session )
899
819
900
820
assert success is True
901
-
902
821
mock_table_class .assert_called_once_with (
903
- session = integration_report_fixture .db .session ,
904
- library_id = integration_report_fixture .db .default_library ().id ,
822
+ session = report_run_fixture .db .session ,
823
+ library_id = report_run_fixture .db .default_library ().id ,
905
824
collection_ids = collection_ids ,
906
825
)
0 commit comments