1 import { ApiResult, Result } from '@proton/docs-shared'
2 import type { DocsApi } from '../Api/DocsApi'
3 import type { DecryptCommit } from './DecryptCommit'
4 import type { EncryptMessage } from './EncryptMessage'
5 import type { SquashAlgorithm } from './SquashAlgorithm'
6 import type { SquashDocumentDTO } from './SquashDocument'
7 import { SquashDocument } from './SquashDocument'
8 import type { VerifyCommit } from './VerifyCommit'
9 import { SquashVerificationObjectionDecision } from '../Types/SquashVerificationObjection'
10 import type { LoggerInterface } from '@proton/utils/logs'
12 jest.mock('@proton/docs-proto', () => ({
13 ...jest.requireActual('@proton/docs-proto'),
15 deserializeBinary: jest.fn().mockReturnValue({
18 documentUpdates: [{}],
26 describe('SquashDocument', () => {
27 let usecase: SquashDocument
29 let decryptCommit: DecryptCommit
30 let verifyCommit: VerifyCommit
31 let squashAlgorithm: SquashAlgorithm
32 let encryptMessage: EncryptMessage
33 let logger: LoggerInterface
35 const dto: SquashDocumentDTO = {
39 handleVerificationObjection: jest.fn(),
44 lockDocument: jest.fn().mockReturnValue(Result.ok({})),
45 squashCommit: jest.fn().mockReturnValue(Result.ok({})),
46 } as unknown as DocsApi
49 execute: jest.fn().mockReturnValue(
54 } as unknown as DecryptCommit
57 execute: jest.fn().mockReturnValue(Result.ok(true)),
58 } as unknown as VerifyCommit
61 execute: jest.fn().mockReturnValue(Result.ok({})),
62 } as unknown as EncryptMessage
65 execute: jest.fn().mockReturnValue(
67 updatesAsSquashed: new Uint8Array(),
68 unmodifiedUpdates: [],
71 } as unknown as SquashAlgorithm
75 } as unknown as LoggerInterface
77 usecase = new SquashDocument(docsApi, encryptMessage, decryptCommit, verifyCommit, squashAlgorithm, logger)
84 it('should lock document before doing anything else', async () => {
85 const lockDocumentSpy = jest.spyOn(docsApi, 'lockDocument')
87 decryptCommit.execute = jest.fn().mockResolvedValue(Result.fail('failed'))
88 const decryptCommitSpy = jest.spyOn(decryptCommit, 'execute')
90 await usecase.execute(dto)
92 expect(lockDocumentSpy).toHaveBeenCalled()
93 expect(decryptCommitSpy).toHaveBeenCalled()
95 expect(lockDocumentSpy.mock.invocationCallOrder[0]).toBeLessThan(decryptCommitSpy.mock.invocationCallOrder[0])
98 it('should fail if lock document fails', async () => {
99 docsApi.lockDocument = jest.fn().mockReturnValue(ApiResult.fail({ message: 'failed', code: 0 }))
101 const result = await usecase.execute(dto)
103 expect(result.isFailed()).toBe(true)
106 it('should verify signature of data', async () => {
107 const verifyCommitSpy = jest.spyOn(verifyCommit, 'execute')
109 await usecase.execute(dto)
111 expect(verifyCommitSpy).toHaveBeenCalled()
114 it('should issue objection is verification fails', async () => {
115 const verificationResult = Result.fail('failed')
116 verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
117 const verifyCommitSpy = jest.spyOn(verifyCommit, 'execute')
119 dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.AbortSquash)
121 await usecase.execute(dto)
123 expect(verifyCommitSpy).toHaveBeenCalled()
124 expect(dto.handleVerificationObjection).toHaveBeenCalled()
127 it('should abort squash if verification object decision is to abort', async () => {
128 const verificationResult = Result.fail('failed')
129 verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
131 dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.AbortSquash)
133 const squashTheCommitSpy = jest.spyOn(usecase, 'squashTheCommit')
135 const result = await usecase.execute(dto)
137 expect(result.isFailed()).toBe(true)
138 expect(squashTheCommitSpy).not.toHaveBeenCalled()
141 it('should continue squash if verification object decision is to continue', async () => {
142 const verificationResult = Result.fail('failed')
143 verifyCommit.execute = jest.fn().mockReturnValue(verificationResult)
145 dto.handleVerificationObjection = jest.fn().mockReturnValue(SquashVerificationObjectionDecision.ContinueSquash)
147 const squashTheCommitSpy = jest.spyOn(usecase, 'squashTheCommit')
149 await usecase.execute(dto)
151 expect(squashTheCommitSpy).toHaveBeenCalled()
154 it('should upload the squashed commit', async () => {
155 const commitResult = Result.ok({})
156 docsApi.squashCommit = jest.fn().mockReturnValue(commitResult)
158 await usecase.execute(dto)
160 expect(docsApi.squashCommit).toHaveBeenCalled()
163 describe('squashTheCommit', () => {
164 it('should encrypt the result', async () => {
165 decryptCommit.execute = jest.fn().mockResolvedValue(Result.ok({ updates: [{}] }))
167 const encryptSpy = jest.spyOn(usecase, 'encryptSquashResult')
169 await usecase.execute(dto)
171 expect(encryptSpy).toHaveBeenCalled()