@@ -814,3 +814,141 @@ def test_multiple_environments_within_timeseries(self):
814
814
"window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
815
815
}
816
816
assert not is_error_count_healthy (ethreshold = threshold_unhealthy , timeseries = timeseries )
817
+
818
+ def test_unordered_timeseries (self ):
819
+ """
820
+ construct a timeseries with:
821
+ - a single release
822
+ - a single project
823
+ - no environment
824
+ - multiple timestamps both before and after our threshold window
825
+ - all disorganized
826
+ """
827
+ now = datetime .utcnow ()
828
+ timeseries = [
829
+ {
830
+ "release" : self .release1 .version ,
831
+ "project_id" : self .project1 .id ,
832
+ "time" : (now - timedelta (minutes = 3 )).isoformat (),
833
+ "environment" : None ,
834
+ "count()" : 1 ,
835
+ },
836
+ {
837
+ "release" : self .release1 .version ,
838
+ "project_id" : self .project1 .id ,
839
+ "time" : now .isoformat (),
840
+ "environment" : None ,
841
+ "count()" : 1 ,
842
+ },
843
+ {
844
+ "release" : self .release1 .version ,
845
+ "project_id" : self .project1 .id ,
846
+ "time" : (now - timedelta (minutes = 1 )).isoformat (),
847
+ "environment" : None ,
848
+ "count()" : 1 ,
849
+ },
850
+ {
851
+ "release" : self .release1 .version ,
852
+ "project_id" : self .project1 .id ,
853
+ "time" : (now - timedelta (minutes = 2 )).isoformat (),
854
+ "environment" : None ,
855
+ "count()" : 1 ,
856
+ },
857
+ ]
858
+
859
+ # current threshold within series
860
+ current_threshold_healthy : EnrichedThreshold = {
861
+ "date" : now ,
862
+ "start" : now - timedelta (minutes = 1 ),
863
+ "end" : now ,
864
+ "environment" : None ,
865
+ "is_healthy" : False ,
866
+ "key" : "" ,
867
+ "project" : serialize (self .project1 ),
868
+ "project_id" : self .project1 .id ,
869
+ "project_slug" : self .project1 .slug ,
870
+ "release" : self .release1 .version ,
871
+ "threshold_type" : ReleaseThresholdType .TOTAL_ERROR_COUNT ,
872
+ "trigger_type" : TriggerType .OVER_STR ,
873
+ "value" : 4 , # error counts _not_ be over threshold value
874
+ "window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
875
+ }
876
+ assert is_error_count_healthy (ethreshold = current_threshold_healthy , timeseries = timeseries )
877
+
878
+ # threshold equal to count
879
+ threshold_at_limit_healthy : EnrichedThreshold = {
880
+ "date" : now ,
881
+ "start" : now - timedelta (minutes = 1 ),
882
+ "end" : now ,
883
+ "environment" : None ,
884
+ "is_healthy" : False ,
885
+ "key" : "" ,
886
+ "project" : serialize (self .project1 ),
887
+ "project_id" : self .project1 .id ,
888
+ "project_slug" : self .project1 .slug ,
889
+ "release" : self .release1 .version ,
890
+ "threshold_type" : ReleaseThresholdType .TOTAL_ERROR_COUNT ,
891
+ "trigger_type" : TriggerType .OVER_STR ,
892
+ "value" : 1 , # error counts equal to threshold limit value
893
+ "window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
894
+ }
895
+ assert is_error_count_healthy (ethreshold = threshold_at_limit_healthy , timeseries = timeseries )
896
+
897
+ # past healthy threshold within series
898
+ past_threshold_healthy : EnrichedThreshold = {
899
+ "date" : now ,
900
+ "start" : now - timedelta (minutes = 2 ),
901
+ "end" : now - timedelta (minutes = 1 ),
902
+ "environment" : None ,
903
+ "is_healthy" : False ,
904
+ "key" : "" ,
905
+ "project" : serialize (self .project1 ),
906
+ "project_id" : self .project1 .id ,
907
+ "project_slug" : self .project1 .slug ,
908
+ "release" : self .release1 .version ,
909
+ "threshold_type" : ReleaseThresholdType .TOTAL_ERROR_COUNT ,
910
+ "trigger_type" : TriggerType .OVER_STR ,
911
+ "value" : 2 ,
912
+ "window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
913
+ }
914
+ assert is_error_count_healthy (ethreshold = past_threshold_healthy , timeseries = timeseries )
915
+
916
+ # threshold within series but trigger is under
917
+ threshold_under_unhealthy : EnrichedThreshold = {
918
+ "date" : now ,
919
+ "start" : now - timedelta (minutes = 1 ),
920
+ "end" : now ,
921
+ "environment" : None ,
922
+ "is_healthy" : False ,
923
+ "key" : "" ,
924
+ "project" : serialize (self .project1 ),
925
+ "project_id" : self .project1 .id ,
926
+ "project_slug" : self .project1 .slug ,
927
+ "release" : self .release1 .version ,
928
+ "threshold_type" : ReleaseThresholdType .TOTAL_ERROR_COUNT ,
929
+ "trigger_type" : TriggerType .UNDER_STR ,
930
+ "value" : 4 ,
931
+ "window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
932
+ }
933
+ assert not is_error_count_healthy (
934
+ ethreshold = threshold_under_unhealthy , timeseries = timeseries
935
+ )
936
+
937
+ # threshold within series but end is in future
938
+ threshold_unfinished : EnrichedThreshold = {
939
+ "date" : now ,
940
+ "start" : now - timedelta (minutes = 1 ),
941
+ "end" : now + timedelta (minutes = 5 ),
942
+ "environment" : None ,
943
+ "is_healthy" : False ,
944
+ "key" : "" ,
945
+ "project" : serialize (self .project1 ),
946
+ "project_id" : self .project1 .id ,
947
+ "project_slug" : self .project1 .slug ,
948
+ "release" : self .release1 .version ,
949
+ "threshold_type" : ReleaseThresholdType .TOTAL_ERROR_COUNT ,
950
+ "trigger_type" : TriggerType .OVER_STR ,
951
+ "value" : 4 ,
952
+ "window_in_seconds" : 60 , # NOTE: window_in_seconds only used to determine start/end. Not utilized in validation method
953
+ }
954
+ assert is_error_count_healthy (ethreshold = threshold_unfinished , timeseries = timeseries )
0 commit comments