Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / docs-core / lib / Services / Websockets / AckLedger / AckLedger.spec.ts
blobcf259e7bcfcf260eb71d06b449fd9c3f324d6059
1 import type { LoggerInterface } from '@proton/utils/logs'
2 import { AckLedger } from './AckLedger'
3 import type { ClientMessageWithDocumentUpdates, ServerMessageWithMessageAcks } from '@proton/docs-proto'
4 import metrics from '@proton/metrics'
6 const mockMetric = jest.mocked(metrics.docs_document_updates_ack_error_total.increment)
8 describe('AckLedger', () => {
9   let ledger: AckLedger
11   const createService = (callback: () => void) =>
12     new AckLedger(
13       {
14         info: jest.fn(),
15       } as unknown as LoggerInterface,
16       callback,
17     )
19   beforeEach(() => {
20     ledger = createService(() => {})
21   })
23   afterEach(() => {
24     ledger.destroy()
25     mockMetric.mockClear()
26   })
28   describe('messagePosted', () => {
29     it('should add to unconfirmed messages', () => {
30       const message = {
31         updates: {
32           documentUpdates: [{ uuid: '1' }, { uuid: '2' }],
33         },
34       } as ClientMessageWithDocumentUpdates
36       ledger.messagePosted(message)
38       expect(ledger.unconfirmedMessages.size).toBe(2)
39     })
40   })
42   describe('getUnacknowledgedUpdates', () => {
43     it('should return unconfirmed messages', () => {
44       const message = {
45         updates: {
46           documentUpdates: [{ uuid: '1' }, { uuid: '2' }],
47         },
48       } as ClientMessageWithDocumentUpdates
50       ledger.messagePosted(message)
52       expect(ledger.getUnacknowledgedUpdates().length).toBe(2)
53     })
54   })
56   describe('messageAcknowledgementReceived', () => {
57     it('should remove from unconfirmed messages', () => {
58       const message = {
59         updates: {
60           documentUpdates: [{ uuid: '1' }, { uuid: '2' }],
61         },
62       } as ClientMessageWithDocumentUpdates
64       ledger.messagePosted(message)
66       const ackMessage = {
67         acks: [{ uuid: '1' }],
68       } as ServerMessageWithMessageAcks
69       ledger.messageAcknowledgementReceived(ackMessage)
71       expect(ledger.unconfirmedMessages.size).toBe(1)
72     })
74     it('should remove from concerning messages', () => {
75       const message = {
76         updates: {
77           documentUpdates: [{ uuid: '1' }, { uuid: '2' }],
78         },
79       } as ClientMessageWithDocumentUpdates
81       ledger.messagePosted(message)
82       ledger.concerningMessages.add('1')
84       const ackMessage = {
85         acks: [{ uuid: '1' }],
86       } as ServerMessageWithMessageAcks
87       ledger.messageAcknowledgementReceived(ackMessage)
89       expect(ledger.concerningMessages.size).toBe(0)
90     })
92     it('should remove from errored messages', () => {
93       const message = {
94         updates: {
95           documentUpdates: [{ uuid: '1' }, { uuid: '2' }],
96         },
97       } as ClientMessageWithDocumentUpdates
99       ledger.messagePosted(message)
100       ledger.erroredMessages.add('1')
102       const ackMessage = {
103         acks: [{ uuid: '1' }],
104       } as ServerMessageWithMessageAcks
105       ledger.messageAcknowledgementReceived(ackMessage)
107       expect(ledger.erroredMessages.size).toBe(0)
108     })
109   })
111   describe('checkForUnackedMessages', () => {
112     it('should add to concerning messages if concern threshold is passed', () => {
113       jest.useFakeTimers()
115       const message = {
116         updates: {
117           documentUpdates: [{ uuid: '1' }],
118         },
119       } as ClientMessageWithDocumentUpdates
121       ledger.messagePosted(message)
123       ledger.thresholdForConcern = () => 10
125       jest.advanceTimersByTime(11)
127       ledger.checkForUnackedMessages()
129       expect(ledger.concerningMessages.size).toBe(1)
130       expect(mockMetric).toHaveBeenCalledTimes(1)
131       expect(mockMetric).toHaveBeenCalledWith(
132         {
133           type: 'concern_threshold',
134         },
135         1,
136       )
137     })
139     it('should add to erorred messages if error threshold is passed', () => {
140       jest.useFakeTimers()
142       const message = {
143         updates: {
144           documentUpdates: [{ uuid: '1' }],
145         },
146       } as ClientMessageWithDocumentUpdates
148       ledger.messagePosted(message)
150       ledger.thresholdForError = () => 10
152       jest.advanceTimersByTime(11)
154       ledger.checkForUnackedMessages()
156       expect(ledger.erroredMessages.size).toBe(1)
157       expect(ledger.concerningMessages.size).toBe(0)
158       expect(mockMetric).toHaveBeenCalledTimes(1)
159       expect(mockMetric).toHaveBeenCalledWith(
160         {
161           type: 'error_threshold',
162         },
163         1,
164       )
165     })
167     it('should notify of status change if messages are added', () => {
168       jest.useFakeTimers()
170       const mock = (ledger.notifyOfStatusChange = jest.fn())
172       const message = {
173         updates: {
174           documentUpdates: [{ uuid: '1' }],
175         },
176       } as ClientMessageWithDocumentUpdates
178       ledger.messagePosted(message)
180       ledger.thresholdForConcern = () => 10
182       jest.advanceTimersByTime(11)
184       ledger.checkForUnackedMessages()
186       expect(mock).toHaveBeenCalled()
187     })
188   })