@@ -5,8 +5,10 @@ import type { WorkflowEntity } from '@n8n/db';
5
5
import type { IWorkflowDb } from '@n8n/db' ;
6
6
import type { WorkflowExecuteAfterContext } from '@n8n/decorators' ;
7
7
import { Container } from '@n8n/di' ;
8
+ import type { MockProxy } from 'jest-mock-extended' ;
8
9
import { mock } from 'jest-mock-extended' ;
9
10
import { DateTime } from 'luxon' ;
11
+ import type { InstanceSettings } from 'n8n-core' ;
10
12
import type { IRun } from 'n8n-workflow' ;
11
13
12
14
import { mockLogger } from '@test/mocking' ;
@@ -47,6 +49,84 @@ afterAll(async () => {
47
49
await testDb . terminate ( ) ;
48
50
} ) ;
49
51
52
+ describe ( 'startTimers' , ( ) => {
53
+ let insightsService : InsightsService ;
54
+ let compactionService : InsightsCompactionService ;
55
+ let collectionService : InsightsCollectionService ;
56
+ let pruningService : InsightsPruningService ;
57
+ let instanceSettings : MockProxy < InstanceSettings > ;
58
+
59
+ beforeEach ( ( ) => {
60
+ compactionService = mock < InsightsCompactionService > ( ) ;
61
+ collectionService = mock < InsightsCollectionService > ( ) ;
62
+ pruningService = mock < InsightsPruningService > ( ) ;
63
+ instanceSettings = mock < InstanceSettings > ( {
64
+ instanceType : 'main' ,
65
+ } ) ;
66
+ insightsService = new InsightsService (
67
+ mock < InsightsByPeriodRepository > ( ) ,
68
+ compactionService ,
69
+ collectionService ,
70
+ pruningService ,
71
+ mock < LicenseState > ( ) ,
72
+ instanceSettings ,
73
+ mockLogger ( ) ,
74
+ ) ;
75
+
76
+ jest . clearAllMocks ( ) ;
77
+ } ) ;
78
+
79
+ const setupMocks = (
80
+ instanceType : string ,
81
+ isLeader : boolean = false ,
82
+ isPruningEnabled : boolean = false ,
83
+ ) => {
84
+ ( instanceSettings as any ) . instanceType = instanceType ;
85
+ Object . defineProperty ( instanceSettings , 'isLeader' , {
86
+ get : jest . fn ( ( ) => isLeader ) ,
87
+ } ) ;
88
+ Object . defineProperty ( pruningService , 'isPruningEnabled' , {
89
+ get : jest . fn ( ( ) => isPruningEnabled ) ,
90
+ } ) ;
91
+ } ;
92
+
93
+ test ( 'starts flushing timer for main instance' , ( ) => {
94
+ setupMocks ( 'main' , false , false ) ;
95
+ insightsService . startTimers ( ) ;
96
+
97
+ expect ( collectionService . startFlushingTimer ) . toHaveBeenCalled ( ) ;
98
+ expect ( compactionService . startCompactionTimer ) . not . toHaveBeenCalled ( ) ;
99
+ expect ( pruningService . startPruningTimer ) . not . toHaveBeenCalled ( ) ;
100
+ } ) ;
101
+
102
+ test ( 'starts compaction and flushing timers for main leader instances' , ( ) => {
103
+ setupMocks ( 'main' , true , false ) ;
104
+ insightsService . startTimers ( ) ;
105
+
106
+ expect ( collectionService . startFlushingTimer ) . toHaveBeenCalled ( ) ;
107
+ expect ( compactionService . startCompactionTimer ) . toHaveBeenCalled ( ) ;
108
+ expect ( pruningService . startPruningTimer ) . not . toHaveBeenCalled ( ) ;
109
+ } ) ;
110
+
111
+ test ( 'starts compaction, flushing and pruning timers for main leader instance with pruning enabled' , ( ) => {
112
+ setupMocks ( 'main' , true , true ) ;
113
+ insightsService . startTimers ( ) ;
114
+
115
+ expect ( collectionService . startFlushingTimer ) . toHaveBeenCalled ( ) ;
116
+ expect ( compactionService . startCompactionTimer ) . toHaveBeenCalled ( ) ;
117
+ expect ( pruningService . startPruningTimer ) . toHaveBeenCalled ( ) ;
118
+ } ) ;
119
+
120
+ test ( 'starts only collection flushing timer for webhook instance' , ( ) => {
121
+ setupMocks ( 'webhook' , false , false ) ;
122
+ insightsService . startTimers ( ) ;
123
+
124
+ expect ( collectionService . startFlushingTimer ) . toHaveBeenCalled ( ) ;
125
+ expect ( compactionService . startCompactionTimer ) . not . toHaveBeenCalled ( ) ;
126
+ expect ( pruningService . startPruningTimer ) . not . toHaveBeenCalled ( ) ;
127
+ } ) ;
128
+ } ) ;
129
+
50
130
describe ( 'getInsightsSummary' , ( ) => {
51
131
let insightsService : InsightsService ;
52
132
beforeAll ( async ( ) => {
@@ -512,6 +592,7 @@ describe('getAvailableDateRanges', () => {
512
592
mock < InsightsCollectionService > ( ) ,
513
593
mock < InsightsPruningService > ( ) ,
514
594
licenseMock ,
595
+ mock < InstanceSettings > ( ) ,
515
596
mockLogger ( ) ,
516
597
) ;
517
598
} ) ;
@@ -614,6 +695,7 @@ describe('getMaxAgeInDaysAndGranularity', () => {
614
695
mock < InsightsCollectionService > ( ) ,
615
696
mock < InsightsPruningService > ( ) ,
616
697
licenseMock ,
698
+ mock < InstanceSettings > ( ) ,
617
699
mockLogger ( ) ,
618
700
) ;
619
701
} ) ;
@@ -702,6 +784,7 @@ describe('shutdown', () => {
702
784
mockCollectionService ,
703
785
mockPruningService ,
704
786
mock < LicenseState > ( ) ,
787
+ mock < InstanceSettings > ( ) ,
705
788
mockLogger ( ) ,
706
789
) ;
707
790
} ) ;
@@ -717,74 +800,6 @@ describe('shutdown', () => {
717
800
} ) ;
718
801
} ) ;
719
802
720
- describe ( 'timers' , ( ) => {
721
- let insightsService : InsightsService ;
722
-
723
- const mockCollectionService = mock < InsightsCollectionService > ( {
724
- startFlushingTimer : jest . fn ( ) ,
725
- stopFlushingTimer : jest . fn ( ) ,
726
- } ) ;
727
-
728
- const mockCompactionService = mock < InsightsCompactionService > ( {
729
- startCompactionTimer : jest . fn ( ) ,
730
- stopCompactionTimer : jest . fn ( ) ,
731
- } ) ;
732
-
733
- const mockPruningService = mock < InsightsPruningService > ( {
734
- startPruningTimer : jest . fn ( ) ,
735
- stopPruningTimer : jest . fn ( ) ,
736
- isPruningEnabled : false ,
737
- } ) ;
738
-
739
- const mockedLogger = mockLogger ( ) ;
740
- const mockedConfig = mock < InsightsConfig > ( {
741
- maxAgeDays : - 1 ,
742
- } ) ;
743
-
744
- beforeAll ( ( ) => {
745
- insightsService = new InsightsService (
746
- mock < InsightsByPeriodRepository > ( ) ,
747
- mockCompactionService ,
748
- mockCollectionService ,
749
- mockPruningService ,
750
- mock < LicenseState > ( ) ,
751
- mockedLogger ,
752
- ) ;
753
- } ) ;
754
-
755
- test ( 'startTimers starts timers except pruning' , ( ) => {
756
- // ACT
757
- insightsService . startTimers ( ) ;
758
-
759
- // ASSERT
760
- expect ( mockCompactionService . startCompactionTimer ) . toHaveBeenCalled ( ) ;
761
- expect ( mockCollectionService . startFlushingTimer ) . toHaveBeenCalled ( ) ;
762
- expect ( mockPruningService . startPruningTimer ) . not . toHaveBeenCalled ( ) ;
763
- } ) ;
764
-
765
- test ( 'startTimers starts pruning timer' , ( ) => {
766
- // ARRANGE
767
- mockedConfig . maxAgeDays = 30 ;
768
- Object . defineProperty ( mockPruningService , 'isPruningEnabled' , { value : true } ) ;
769
-
770
- // ACT
771
- insightsService . startTimers ( ) ;
772
-
773
- // ASSERT
774
- expect ( mockPruningService . startPruningTimer ) . toHaveBeenCalled ( ) ;
775
- } ) ;
776
-
777
- test ( 'stopTimers stops timers' , ( ) => {
778
- // ACT
779
- insightsService . stopTimers ( ) ;
780
-
781
- // ASSERT
782
- expect ( mockCompactionService . stopCompactionTimer ) . toHaveBeenCalled ( ) ;
783
- expect ( mockCollectionService . stopFlushingTimer ) . toHaveBeenCalled ( ) ;
784
- expect ( mockPruningService . stopPruningTimer ) . toHaveBeenCalled ( ) ;
785
- } ) ;
786
- } ) ;
787
-
788
803
describe ( 'legacy sqlite (without pooling) handles concurrent insights db process without throwing' , ( ) => {
789
804
let initialFlushBatchSize : number ;
790
805
let insightsConfig : InsightsConfig ;
0 commit comments