Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 201 lines 6.2 kB view raw
1import { type Dependencies } from '../../iocContainer/index.js'; 2import { type MockedFn } from '../../test/mockHelpers/jestMocks.js'; 3import makeGetRuleAnomalyDetectionStatistics from './getRuleAnomalyDetectionStatistics.js'; 4 5/** 6 * @fileoverview The testing strategy here is to just snapshot the queries 7 * that our service function is generating, and run those manually to verify 8 * that they work. If we update the warehouse structure, we can update the 9 * snapshots and manually re-run the new queries. But having these snapshots at 10 * least makes sure we can't change inadvertently change the generated queries. 11 */ 12describe('getRuleAnomalyDetectionStatistics', () => { 13 let queryMock: MockedFn< 14 ( 15 query: string, 16 tracer: any, 17 binds?: readonly unknown[], 18 ) => Promise<unknown[]> 19 >; 20 let getRulePassStatistics: Dependencies['getRuleAnomalyDetectionStatistics']; 21 22 beforeAll(() => { 23 const queryResult = [ 24 { 25 RULE_ID: 'a', 26 NUM_PASSES: 2, 27 NUM_DISTINCT_USERS: 1, 28 NUM_RUNS: 4, 29 TS_START_INCLUSIVE: '2022-05-07 23:00:00.00', 30 RULE_VERSION: '2022-05-01T12:10:00.00305Z', 31 }, 32 ]; 33 34 // Scope of this is just the test suite, so mutation should be ok. 35 36 queryMock = jest.fn() as any; 37 queryMock.mockResolvedValue(queryResult); 38 39 const dataWarehouseMock = { 40 query: queryMock, 41 transaction: jest.fn(), 42 start: jest.fn(), 43 close: jest.fn(), 44 getProvider: () => 'clickhouse' as const, 45 }; 46 47 // Scope of this is just the test suite, so mutation should be ok. 48 49 getRulePassStatistics = makeGetRuleAnomalyDetectionStatistics( 50 dataWarehouseMock, 51 {} as any, 52 ); 53 }); 54 55 beforeEach(() => { 56 // This is only safe while we're not running tests concurrently. 57 // Consider using the `makeTestWithFixture` helper instead to make 58 // a local copy of this state for each test. 59 queryMock.mockClear(); 60 }); 61 62 test('should return the result from the warehouse, properly formatted', async () => { 63 const result = await getRulePassStatistics(); 64 expect(result).toEqual([ 65 { 66 ruleId: 'a', 67 passCount: 2, 68 runsCount: 4, 69 passingUsersCount: 1, 70 windowStart: new Date('2022-05-07 23:00:00.00'), 71 approxRuleVersion: new Date('2022-05-01T12:10:00.00305Z'), 72 }, 73 ]); 74 }); 75 76 test('should generate the proper query when given no filters', async () => { 77 await getRulePassStatistics(); 78 79 expect(queryMock).toHaveBeenCalledTimes(1); 80 expect(queryMock.mock.calls[0]).toMatchInlineSnapshot(` 81 [ 82 " 83 SELECT 84 rule_id, 85 rule_version, 86 num_passes, 87 num_runs, 88 array_size(passes_distinct_user_ids) as num_distinct_users, 89 ts_start_inclusive 90 FROM RULE_ANOMALY_DETECTION_SERVICE.RULE_EXECUTION_STATISTICS 91 WHERE ts_end_exclusive <= SYSDATE() 92 ORDER BY ts_start_inclusive DESC;", 93 {}, 94 [], 95 ] 96 `); 97 }); 98 99 test('should generate the proper query when given a start time filter', async () => { 100 await getRulePassStatistics({ startTime: new Date('2022-05-02') }); 101 102 expect(queryMock).toHaveBeenCalledTimes(1); 103 expect(queryMock.mock.calls[0]).toMatchInlineSnapshot(` 104 [ 105 " 106 SELECT 107 rule_id, 108 rule_version, 109 num_passes, 110 num_runs, 111 array_size(passes_distinct_user_ids) as num_distinct_users, 112 ts_start_inclusive 113 FROM RULE_ANOMALY_DETECTION_SERVICE.RULE_EXECUTION_STATISTICS 114 WHERE ts_end_exclusive <= SYSDATE() AND ts_start_inclusive >= ? 115 ORDER BY ts_start_inclusive DESC;", 116 {}, 117 [ 118 2022-05-02T00:00:00.000Z, 119 ], 120 ] 121 `); 122 }); 123 124 test('should generate the proper query when given a ruleIds filter', async () => { 125 await getRulePassStatistics({ ruleIds: ['1', '2'] }); 126 127 expect(queryMock).toHaveBeenCalledTimes(1); 128 expect(queryMock.mock.calls[0]).toMatchInlineSnapshot(` 129 [ 130 " 131 SELECT 132 rule_id, 133 rule_version, 134 num_passes, 135 num_runs, 136 array_size(passes_distinct_user_ids) as num_distinct_users, 137 ts_start_inclusive 138 FROM RULE_ANOMALY_DETECTION_SERVICE.RULE_EXECUTION_STATISTICS 139 WHERE ts_end_exclusive <= SYSDATE() AND rule_id IN (?,?) 140 ORDER BY ts_start_inclusive DESC;", 141 {}, 142 [ 143 "1", 144 "2", 145 ], 146 ] 147 `); 148 await getRulePassStatistics({ ruleIds: ['1'] }); 149 150 expect(queryMock).toHaveBeenCalledTimes(2); 151 expect(queryMock.mock.calls[1]).toMatchInlineSnapshot(` 152 [ 153 " 154 SELECT 155 rule_id, 156 rule_version, 157 num_passes, 158 num_runs, 159 array_size(passes_distinct_user_ids) as num_distinct_users, 160 ts_start_inclusive 161 FROM RULE_ANOMALY_DETECTION_SERVICE.RULE_EXECUTION_STATISTICS 162 WHERE ts_end_exclusive <= SYSDATE() AND rule_id IN (?) 163 ORDER BY ts_start_inclusive DESC;", 164 {}, 165 [ 166 "1", 167 ], 168 ] 169 `); 170 }); 171 172 test('should generate the proper query when given both filters', async () => { 173 await getRulePassStatistics({ 174 ruleIds: ['1', '2'], 175 startTime: new Date('2022-05-02 23:00:00.00-04'), 176 }); 177 178 expect(queryMock).toHaveBeenCalledTimes(1); 179 expect(queryMock.mock.calls[0]).toMatchInlineSnapshot(` 180 [ 181 " 182 SELECT 183 rule_id, 184 rule_version, 185 num_passes, 186 num_runs, 187 array_size(passes_distinct_user_ids) as num_distinct_users, 188 ts_start_inclusive 189 FROM RULE_ANOMALY_DETECTION_SERVICE.RULE_EXECUTION_STATISTICS 190 WHERE ts_end_exclusive <= SYSDATE() AND ts_start_inclusive >= ? AND rule_id IN (?,?) 191 ORDER BY ts_start_inclusive DESC;", 192 {}, 193 [ 194 2022-05-03T03:00:00.000Z, 195 "1", 196 "2", 197 ], 198 ] 199 `); 200 }); 201});