@protontech/drive-sdk 0.0.12 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.js +3 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/memoryCache.d.ts +1 -1
- package/dist/cache/nullCache.d.ts +14 -0
- package/dist/cache/nullCache.js +37 -0
- package/dist/cache/nullCache.js.map +1 -0
- package/dist/config.d.ts +16 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/crypto/openPGPCrypto.js +2 -0
- package/dist/crypto/openPGPCrypto.js.map +1 -1
- package/dist/diagnostic/eventsGenerator.d.ts +14 -0
- package/dist/diagnostic/eventsGenerator.js +49 -0
- package/dist/diagnostic/eventsGenerator.js.map +1 -0
- package/dist/diagnostic/httpClient.d.ts +16 -0
- package/dist/diagnostic/httpClient.js +81 -0
- package/dist/diagnostic/httpClient.js.map +1 -0
- package/dist/diagnostic/index.d.ts +10 -0
- package/dist/diagnostic/index.js +35 -0
- package/dist/diagnostic/index.js.map +1 -0
- package/dist/diagnostic/integrityVerificationStream.d.ts +21 -0
- package/dist/diagnostic/integrityVerificationStream.js +56 -0
- package/dist/diagnostic/integrityVerificationStream.js.map +1 -0
- package/dist/diagnostic/interface.d.ts +102 -0
- package/dist/diagnostic/interface.js +3 -0
- package/dist/diagnostic/interface.js.map +1 -0
- package/dist/diagnostic/sdkDiagnostic.d.ts +22 -0
- package/dist/diagnostic/sdkDiagnostic.js +216 -0
- package/dist/diagnostic/sdkDiagnostic.js.map +1 -0
- package/dist/diagnostic/sdkDiagnosticFull.d.ts +18 -0
- package/dist/diagnostic/sdkDiagnosticFull.js +35 -0
- package/dist/diagnostic/sdkDiagnosticFull.js.map +1 -0
- package/dist/diagnostic/telemetry.d.ts +25 -0
- package/dist/diagnostic/telemetry.js +70 -0
- package/dist/diagnostic/telemetry.js.map +1 -0
- package/dist/diagnostic/zipGenerators.d.ts +9 -0
- package/dist/diagnostic/zipGenerators.js +64 -0
- package/dist/diagnostic/zipGenerators.js.map +1 -0
- package/dist/diagnostic/zipGenerators.test.js +144 -0
- package/dist/diagnostic/zipGenerators.test.js.map +1 -0
- package/dist/errors.d.ts +8 -3
- package/dist/errors.js +11 -4
- package/dist/errors.js.map +1 -1
- package/dist/interface/config.d.ts +26 -0
- package/dist/interface/config.js +3 -0
- package/dist/interface/config.js.map +1 -0
- package/dist/interface/download.d.ts +2 -2
- package/dist/interface/events.d.ts +60 -20
- package/dist/interface/events.js +11 -1
- package/dist/interface/events.js.map +1 -1
- package/dist/interface/httpClient.d.ts +0 -14
- package/dist/interface/index.d.ts +9 -5
- package/dist/interface/index.js +2 -1
- package/dist/interface/index.js.map +1 -1
- package/dist/interface/nodes.d.ts +21 -1
- package/dist/interface/nodes.js +11 -0
- package/dist/interface/nodes.js.map +1 -1
- package/dist/interface/sharing.d.ts +1 -0
- package/dist/interface/upload.d.ts +57 -3
- package/dist/internal/apiService/driveTypes.d.ts +1341 -465
- package/dist/internal/apiService/errors.js +2 -2
- package/dist/internal/apiService/errors.js.map +1 -1
- package/dist/internal/apiService/transformers.js +2 -0
- package/dist/internal/apiService/transformers.js.map +1 -1
- package/dist/internal/asyncIteratorMap.d.ts +15 -0
- package/dist/internal/asyncIteratorMap.js +59 -0
- package/dist/internal/asyncIteratorMap.js.map +1 -0
- package/dist/internal/asyncIteratorMap.test.js +120 -0
- package/dist/internal/asyncIteratorMap.test.js.map +1 -0
- package/dist/internal/download/apiService.js +32 -31
- package/dist/internal/download/apiService.js.map +1 -1
- package/dist/internal/download/fileDownloader.d.ts +2 -2
- package/dist/internal/download/fileDownloader.js.map +1 -1
- package/dist/internal/events/apiService.d.ts +4 -6
- package/dist/internal/events/apiService.js +15 -22
- package/dist/internal/events/apiService.js.map +1 -1
- package/dist/internal/events/coreEventManager.d.ts +7 -10
- package/dist/internal/events/coreEventManager.js +19 -36
- package/dist/internal/events/coreEventManager.js.map +1 -1
- package/dist/internal/events/coreEventManager.test.d.ts +1 -0
- package/dist/internal/events/coreEventManager.test.js +87 -0
- package/dist/internal/events/coreEventManager.test.js.map +1 -0
- package/dist/internal/events/eventManager.d.ts +11 -36
- package/dist/internal/events/eventManager.js +59 -105
- package/dist/internal/events/eventManager.js.map +1 -1
- package/dist/internal/events/eventManager.test.js +167 -82
- package/dist/internal/events/eventManager.test.js.map +1 -1
- package/dist/internal/events/index.d.ts +13 -33
- package/dist/internal/events/index.js +56 -72
- package/dist/internal/events/index.js.map +1 -1
- package/dist/internal/events/interface.d.ts +59 -14
- package/dist/internal/events/interface.js +13 -3
- package/dist/internal/events/interface.js.map +1 -1
- package/dist/internal/events/volumeEventManager.d.ts +7 -17
- package/dist/internal/events/volumeEventManager.js +58 -45
- package/dist/internal/events/volumeEventManager.js.map +1 -1
- package/dist/internal/events/volumeEventManager.test.d.ts +1 -0
- package/dist/internal/events/volumeEventManager.test.js +203 -0
- package/dist/internal/events/volumeEventManager.test.js.map +1 -0
- package/dist/internal/nodes/apiService.d.ts +2 -2
- package/dist/internal/nodes/apiService.js +16 -6
- package/dist/internal/nodes/apiService.js.map +1 -1
- package/dist/internal/nodes/apiService.test.js +30 -8
- package/dist/internal/nodes/apiService.test.js.map +1 -1
- package/dist/internal/nodes/cache.d.ts +10 -1
- package/dist/internal/nodes/cache.js +18 -0
- package/dist/internal/nodes/cache.js.map +1 -1
- package/dist/internal/nodes/cache.test.js +1 -0
- package/dist/internal/nodes/cache.test.js.map +1 -1
- package/dist/internal/nodes/cryptoService.d.ts +1 -1
- package/dist/internal/nodes/cryptoService.js.map +1 -1
- package/dist/internal/nodes/cryptoService.test.js +34 -0
- package/dist/internal/nodes/cryptoService.test.js.map +1 -1
- package/dist/internal/nodes/events.d.ts +7 -83
- package/dist/internal/nodes/events.js +43 -217
- package/dist/internal/nodes/events.js.map +1 -1
- package/dist/internal/nodes/events.test.js +27 -277
- package/dist/internal/nodes/events.test.js.map +1 -1
- package/dist/internal/nodes/index.d.ts +3 -4
- package/dist/internal/nodes/index.js +5 -5
- package/dist/internal/nodes/index.js.map +1 -1
- package/dist/internal/nodes/interface.d.ts +3 -1
- package/dist/internal/nodes/nodesAccess.d.ts +15 -0
- package/dist/internal/nodes/nodesAccess.js +65 -7
- package/dist/internal/nodes/nodesAccess.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.test.js +132 -93
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.d.ts +1 -3
- package/dist/internal/nodes/nodesManagement.js +12 -26
- package/dist/internal/nodes/nodesManagement.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.test.js +35 -14
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
- package/dist/internal/shares/cache.d.ts +2 -0
- package/dist/internal/shares/cache.js +2 -0
- package/dist/internal/shares/cache.js.map +1 -1
- package/dist/internal/shares/manager.d.ts +1 -0
- package/dist/internal/shares/manager.js +3 -0
- package/dist/internal/shares/manager.js.map +1 -1
- package/dist/internal/sharing/apiService.js +20 -2
- package/dist/internal/sharing/apiService.js.map +1 -1
- package/dist/internal/sharing/cryptoService.js +1 -0
- package/dist/internal/sharing/cryptoService.js.map +1 -1
- package/dist/internal/sharing/events.d.ts +23 -55
- package/dist/internal/sharing/events.js +46 -138
- package/dist/internal/sharing/events.js.map +1 -1
- package/dist/internal/sharing/events.test.js +77 -180
- package/dist/internal/sharing/events.test.js.map +1 -1
- package/dist/internal/sharing/index.d.ts +4 -5
- package/dist/internal/sharing/index.js +5 -5
- package/dist/internal/sharing/index.js.map +1 -1
- package/dist/internal/sharing/interface.d.ts +3 -0
- package/dist/internal/sharing/sharingManagement.d.ts +2 -3
- package/dist/internal/sharing/sharingManagement.js +7 -9
- package/dist/internal/sharing/sharingManagement.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.test.js +9 -39
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
- package/dist/internal/upload/apiService.d.ts +2 -3
- package/dist/internal/upload/apiService.js +7 -4
- package/dist/internal/upload/apiService.js.map +1 -1
- package/dist/internal/upload/fileUploader.d.ts +49 -53
- package/dist/internal/upload/fileUploader.js +91 -395
- package/dist/internal/upload/fileUploader.js.map +1 -1
- package/dist/internal/upload/fileUploader.test.js +38 -292
- package/dist/internal/upload/fileUploader.test.js.map +1 -1
- package/dist/internal/upload/index.d.ts +5 -5
- package/dist/internal/upload/index.js +23 -44
- package/dist/internal/upload/index.js.map +1 -1
- package/dist/internal/upload/interface.d.ts +2 -0
- package/dist/internal/upload/manager.d.ts +6 -6
- package/dist/internal/upload/manager.js +32 -66
- package/dist/internal/upload/manager.js.map +1 -1
- package/dist/internal/upload/manager.test.js +100 -117
- package/dist/internal/upload/manager.test.js.map +1 -1
- package/dist/internal/upload/streamUploader.d.ts +62 -0
- package/dist/internal/upload/streamUploader.js +440 -0
- package/dist/internal/upload/streamUploader.js.map +1 -0
- package/dist/internal/upload/streamUploader.test.d.ts +1 -0
- package/dist/internal/upload/streamUploader.test.js +358 -0
- package/dist/internal/upload/streamUploader.test.js.map +1 -0
- package/dist/protonDriveClient.d.ts +22 -165
- package/dist/protonDriveClient.js +27 -191
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePhotosClient.js +3 -2
- package/dist/protonDrivePhotosClient.js.map +1 -1
- package/package.json +4 -4
- package/src/cache/index.ts +1 -0
- package/src/cache/memoryCache.ts +1 -1
- package/src/cache/nullCache.ts +38 -0
- package/src/config.ts +17 -2
- package/src/crypto/openPGPCrypto.ts +2 -0
- package/src/diagnostic/eventsGenerator.ts +48 -0
- package/src/diagnostic/httpClient.ts +80 -0
- package/src/diagnostic/index.ts +38 -0
- package/src/diagnostic/integrityVerificationStream.ts +56 -0
- package/src/diagnostic/interface.ts +158 -0
- package/src/diagnostic/sdkDiagnostic.ts +238 -0
- package/src/diagnostic/sdkDiagnosticFull.ts +40 -0
- package/src/diagnostic/telemetry.ts +71 -0
- package/src/diagnostic/zipGenerators.test.ts +177 -0
- package/src/diagnostic/zipGenerators.ts +70 -0
- package/src/errors.ts +13 -4
- package/src/interface/config.ts +28 -0
- package/src/interface/download.ts +2 -2
- package/src/interface/events.ts +66 -21
- package/src/interface/httpClient.ts +0 -16
- package/src/interface/index.ts +9 -5
- package/src/interface/nodes.ts +32 -12
- package/src/interface/sharing.ts +1 -0
- package/src/interface/upload.ts +59 -3
- package/src/internal/apiService/driveTypes.ts +1341 -465
- package/src/internal/apiService/errors.ts +3 -2
- package/src/internal/apiService/transformers.ts +2 -0
- package/src/internal/asyncIteratorMap.test.ts +150 -0
- package/src/internal/asyncIteratorMap.ts +64 -0
- package/src/internal/download/apiService.ts +11 -8
- package/src/internal/download/fileDownloader.ts +2 -2
- package/src/internal/events/apiService.ts +25 -28
- package/src/internal/events/coreEventManager.test.ts +101 -0
- package/src/internal/events/coreEventManager.ts +20 -45
- package/src/internal/events/eventManager.test.ts +201 -88
- package/src/internal/events/eventManager.ts +69 -115
- package/src/internal/events/index.ts +54 -84
- package/src/internal/events/interface.ts +70 -15
- package/src/internal/events/volumeEventManager.test.ts +243 -0
- package/src/internal/events/volumeEventManager.ts +55 -53
- package/src/internal/nodes/apiService.test.ts +36 -7
- package/src/internal/nodes/apiService.ts +19 -7
- package/src/internal/nodes/cache.test.ts +1 -0
- package/src/internal/nodes/cache.ts +21 -2
- package/src/internal/nodes/cryptoService.test.ts +38 -0
- package/src/internal/nodes/cryptoService.ts +1 -1
- package/src/internal/nodes/events.test.ts +29 -335
- package/src/internal/nodes/events.ts +45 -253
- package/src/internal/nodes/index.ts +6 -8
- package/src/internal/nodes/interface.ts +6 -3
- package/src/internal/nodes/nodesAccess.test.ts +133 -91
- package/src/internal/nodes/nodesAccess.ts +70 -8
- package/src/internal/nodes/nodesManagement.test.ts +39 -15
- package/src/internal/nodes/nodesManagement.ts +12 -30
- package/src/internal/shares/cache.ts +4 -2
- package/src/internal/shares/manager.ts +9 -5
- package/src/internal/sharing/apiService.ts +25 -2
- package/src/internal/sharing/cache.ts +1 -1
- package/src/internal/sharing/cryptoService.ts +1 -0
- package/src/internal/sharing/events.test.ts +89 -195
- package/src/internal/sharing/events.ts +42 -156
- package/src/internal/sharing/index.ts +6 -9
- package/src/internal/sharing/interface.ts +6 -2
- package/src/internal/sharing/sharingManagement.test.ts +10 -40
- package/src/internal/sharing/sharingManagement.ts +7 -11
- package/src/internal/upload/apiService.ts +5 -6
- package/src/internal/upload/fileUploader.test.ts +46 -376
- package/src/internal/upload/fileUploader.ts +114 -494
- package/src/internal/upload/index.ts +30 -54
- package/src/internal/upload/interface.ts +2 -0
- package/src/internal/upload/manager.test.ts +107 -124
- package/src/internal/upload/manager.ts +48 -80
- package/src/internal/upload/streamUploader.test.ts +468 -0
- package/src/internal/upload/streamUploader.ts +550 -0
- package/src/protonDriveClient.ts +80 -248
- package/src/protonDrivePhotosClient.ts +4 -3
- package/dist/internal/events/cache.d.ts +0 -28
- package/dist/internal/events/cache.js +0 -67
- package/dist/internal/events/cache.js.map +0 -1
- package/dist/internal/events/cache.test.js +0 -43
- package/dist/internal/events/cache.test.js.map +0 -1
- package/dist/internal/nodes/index.test.js +0 -112
- package/dist/internal/nodes/index.test.js.map +0 -1
- package/src/internal/events/cache.test.ts +0 -47
- package/src/internal/events/cache.ts +0 -80
- package/src/internal/nodes/index.test.ts +0 -135
- /package/dist/{internal/events/cache.test.d.ts → diagnostic/zipGenerators.test.d.ts} +0 -0
- /package/dist/internal/{nodes/index.test.d.ts → asyncIteratorMap.test.d.ts} +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Thumbnail,
|
|
2
|
-
import {
|
|
3
|
-
import { FILE_CHUNK_SIZE, Fileuploader } from './fileUploader';
|
|
1
|
+
import { Thumbnail, UploadMetadata } from '../../interface';
|
|
2
|
+
import { FileUploader } from './fileUploader';
|
|
4
3
|
import { UploadTelemetry } from './telemetry';
|
|
5
4
|
import { UploadAPIService } from './apiService';
|
|
6
5
|
import { UploadCryptoService } from './cryptoService';
|
|
@@ -8,7 +7,6 @@ import { UploadController } from './controller';
|
|
|
8
7
|
import { BlockVerifier } from './blockVerifier';
|
|
9
8
|
import { NodeRevisionDraft } from './interface';
|
|
10
9
|
import { UploadManager } from './manager';
|
|
11
|
-
import { IntegrityError } from '../../errors';
|
|
12
10
|
|
|
13
11
|
const BLOCK_ENCRYPTION_OVERHEAD = 10000;
|
|
14
12
|
|
|
@@ -41,7 +39,9 @@ describe('FileUploader', () => {
|
|
|
41
39
|
let onFinish: () => Promise<void>;
|
|
42
40
|
let abortController: AbortController;
|
|
43
41
|
|
|
44
|
-
let uploader:
|
|
42
|
+
let uploader: FileUploader;
|
|
43
|
+
|
|
44
|
+
let startUploadSpy: jest.SpyInstance;
|
|
45
45
|
|
|
46
46
|
beforeEach(() => {
|
|
47
47
|
// @ts-expect-error No need to implement all methods for mocking
|
|
@@ -103,411 +103,81 @@ describe('FileUploader', () => {
|
|
|
103
103
|
},
|
|
104
104
|
} as NodeRevisionDraft;
|
|
105
105
|
|
|
106
|
-
metadata = {
|
|
107
|
-
// 3 blocks: 4 + 4 + 2 MB
|
|
108
|
-
expectedSize: 10 * 1024 * 1024,
|
|
109
|
-
} as UploadMetadata;
|
|
106
|
+
metadata = {} as UploadMetadata;
|
|
110
107
|
|
|
111
108
|
controller = new UploadController();
|
|
112
109
|
onFinish = jest.fn();
|
|
113
110
|
abortController = new AbortController();
|
|
114
111
|
|
|
115
|
-
uploader = new
|
|
112
|
+
uploader = new FileUploader(
|
|
116
113
|
telemetry,
|
|
117
114
|
apiService,
|
|
118
115
|
cryptoService,
|
|
119
116
|
uploadManager,
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
'parentFolderUid',
|
|
118
|
+
'name',
|
|
122
119
|
metadata,
|
|
123
120
|
onFinish,
|
|
124
121
|
abortController.signal,
|
|
125
122
|
);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe('writeFile', () => {
|
|
129
|
-
it('should set modification time if not set', () => {
|
|
130
|
-
// @ts-expect-error Ignore mocking File
|
|
131
|
-
const file = {
|
|
132
|
-
lastModified: 123456789,
|
|
133
|
-
stream: jest.fn().mockReturnValue('stream'),
|
|
134
|
-
} as File;
|
|
135
|
-
const thumbnails: Thumbnail[] = [];
|
|
136
|
-
const onProgress = jest.fn();
|
|
137
|
-
|
|
138
|
-
const writeStreamSpy = jest.spyOn(uploader, 'writeStream').mockReturnValue(controller);
|
|
139
|
-
|
|
140
|
-
uploader.writeFile(file, thumbnails, onProgress);
|
|
141
|
-
|
|
142
|
-
expect(metadata.modificationTime).toEqual(new Date(123456789));
|
|
143
|
-
expect(writeStreamSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('writeStream', () => {
|
|
148
|
-
let uploadStreamSpy: jest.SpyInstance;
|
|
149
|
-
beforeEach(() => {
|
|
150
|
-
uploadStreamSpy = jest.spyOn(uploader as any, 'uploadStream').mockResolvedValue('revisionUid');
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('should throw an error if upload already started', () => {
|
|
154
|
-
uploader.writeStream(new ReadableStream(), [], jest.fn());
|
|
155
|
-
|
|
156
|
-
expect(() => {
|
|
157
|
-
uploader.writeStream(new ReadableStream(), [], jest.fn());
|
|
158
|
-
}).toThrow('Upload already started');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it('should start the upload process', async () => {
|
|
162
|
-
const stream = new ReadableStream();
|
|
163
|
-
const thumbnails: Thumbnail[] = [];
|
|
164
|
-
const onProgress = jest.fn();
|
|
165
123
|
|
|
166
|
-
|
|
167
|
-
expect(uploadStreamSpy).toHaveBeenCalledWith(stream, thumbnails, onProgress);
|
|
168
|
-
});
|
|
124
|
+
startUploadSpy = jest.spyOn(uploader as any, 'startUpload').mockReturnValue(Promise.resolve('revisionUid'));
|
|
169
125
|
});
|
|
170
126
|
|
|
171
|
-
describe('
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const numberOfExpectedBlocks = Math.ceil(metadata.expectedSize / FILE_CHUNK_SIZE);
|
|
183
|
-
expect(uploadManager.commitDraft).toHaveBeenCalledTimes(1);
|
|
184
|
-
expect(uploadManager.commitDraft).toHaveBeenCalledWith(
|
|
185
|
-
revisionDraft,
|
|
186
|
-
expect.anything(),
|
|
187
|
-
metadata,
|
|
188
|
-
{
|
|
189
|
-
size: metadata.expectedSize,
|
|
190
|
-
blockSizes: metadata.expectedSize ? [
|
|
191
|
-
...Array(numberOfExpectedBlocks - 1).fill(FILE_CHUNK_SIZE),
|
|
192
|
-
metadata.expectedSize % FILE_CHUNK_SIZE
|
|
193
|
-
] : [],
|
|
194
|
-
modificationTime: undefined,
|
|
195
|
-
digests: {
|
|
196
|
-
sha1: expect.anything(),
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
metadata.expectedSize + numberOfExpectedBlocks * BLOCK_ENCRYPTION_OVERHEAD,
|
|
200
|
-
);
|
|
201
|
-
expect(telemetry.uploadFinished).toHaveBeenCalledTimes(1);
|
|
202
|
-
expect(telemetry.uploadFinished).toHaveBeenCalledWith('revisionUid', metadata.expectedSize + thumbnailSize);
|
|
203
|
-
expect(telemetry.uploadFailed).not.toHaveBeenCalled();
|
|
204
|
-
expect(onFinish).toHaveBeenCalledTimes(1);
|
|
205
|
-
expect(onFinish).toHaveBeenCalledWith(false);
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const verifyFailure = async (error: string, uploadedBytes: number | undefined, expectedSize = metadata.expectedSize) => {
|
|
209
|
-
const controller = uploader.writeStream(stream, thumbnails, onProgress);
|
|
210
|
-
await expect(controller.completion()).rejects.toThrow(error);
|
|
211
|
-
|
|
212
|
-
expect(telemetry.uploadFinished).not.toHaveBeenCalled();
|
|
213
|
-
expect(telemetry.uploadFailed).toHaveBeenCalledTimes(1);
|
|
214
|
-
expect(telemetry.uploadFailed).toHaveBeenCalledWith(
|
|
215
|
-
'revisionUid',
|
|
216
|
-
new Error(error),
|
|
217
|
-
uploadedBytes === undefined ? expect.anything() : uploadedBytes,
|
|
218
|
-
expectedSize,
|
|
219
|
-
);
|
|
220
|
-
expect(onFinish).toHaveBeenCalledTimes(1);
|
|
221
|
-
expect(onFinish).toHaveBeenCalledWith(true);
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const verifyOnProgress = async (uploadedBytes: number[]) => {
|
|
225
|
-
expect(onProgress).toHaveBeenCalledTimes(uploadedBytes.length);
|
|
226
|
-
for (let i = 0; i < uploadedBytes.length; i++) {
|
|
227
|
-
expect(onProgress).toHaveBeenNthCalledWith(i + 1, uploadedBytes[i]);
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
beforeEach(() => {
|
|
232
|
-
onProgress = jest.fn();
|
|
233
|
-
thumbnails = [
|
|
234
|
-
{
|
|
235
|
-
type: ThumbnailType.Type1,
|
|
236
|
-
thumbnail: new Uint8Array(1024),
|
|
237
|
-
}
|
|
238
|
-
];
|
|
239
|
-
thumbnailSize = thumbnails.reduce((acc, thumbnail) => acc + thumbnail.thumbnail.length, 0);
|
|
240
|
-
stream = new ReadableStream({
|
|
241
|
-
start(controller) {
|
|
242
|
-
const chunkSize = 1024;
|
|
243
|
-
const chunkCount = metadata.expectedSize / chunkSize;
|
|
244
|
-
for (let i = 1; i <= chunkCount; i++) {
|
|
245
|
-
controller.enqueue(new Uint8Array(chunkSize));
|
|
246
|
-
}
|
|
247
|
-
controller.close();
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it("should upload successfully", async () => {
|
|
253
|
-
await verifySuccess();
|
|
254
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
|
|
255
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(4); // 3 blocks + 1 thumbnail
|
|
256
|
-
expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(3); // 3 blocks
|
|
257
|
-
expect(telemetry.logBlockVerificationError).not.toHaveBeenCalled();
|
|
258
|
-
await verifyOnProgress([thumbnailSize, 4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024]);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it("should upload successfully empty file without thumbnail", async () => {
|
|
262
|
-
metadata = {
|
|
263
|
-
expectedSize: 0,
|
|
264
|
-
} as UploadMetadata;
|
|
265
|
-
stream = new ReadableStream({
|
|
266
|
-
start(controller) {
|
|
267
|
-
controller.close();
|
|
268
|
-
},
|
|
269
|
-
});
|
|
270
|
-
thumbnails = [];
|
|
271
|
-
thumbnailSize = 0;
|
|
272
|
-
uploader = new Fileuploader(
|
|
273
|
-
telemetry,
|
|
274
|
-
apiService,
|
|
275
|
-
cryptoService,
|
|
276
|
-
uploadManager,
|
|
277
|
-
blockVerifier,
|
|
278
|
-
revisionDraft,
|
|
279
|
-
metadata,
|
|
280
|
-
onFinish,
|
|
281
|
-
);
|
|
282
|
-
|
|
283
|
-
await verifySuccess();
|
|
284
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(0);
|
|
285
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(0);
|
|
286
|
-
expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(0);
|
|
287
|
-
await verifyOnProgress([]);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it("should upload successfully empty file with thumbnail", async () => {
|
|
291
|
-
metadata = {
|
|
292
|
-
expectedSize: 0,
|
|
293
|
-
} as UploadMetadata;
|
|
294
|
-
stream = new ReadableStream({
|
|
295
|
-
start(controller) {
|
|
296
|
-
controller.close();
|
|
297
|
-
},
|
|
298
|
-
});
|
|
299
|
-
uploader = new Fileuploader(
|
|
300
|
-
telemetry,
|
|
301
|
-
apiService,
|
|
302
|
-
cryptoService,
|
|
303
|
-
uploadManager,
|
|
304
|
-
blockVerifier,
|
|
305
|
-
revisionDraft,
|
|
306
|
-
metadata,
|
|
307
|
-
onFinish,
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
await verifySuccess();
|
|
311
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
|
|
312
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(1);
|
|
313
|
-
expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(0);
|
|
314
|
-
await verifyOnProgress([thumbnailSize]);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('should handle failure when encrypting thumbnails', async () => {
|
|
318
|
-
cryptoService.encryptThumbnail = jest.fn().mockImplementation(async function () {
|
|
319
|
-
throw new Error('Failed to encrypt thumbnail');
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
await verifyFailure('Failed to encrypt thumbnail', 0);
|
|
323
|
-
expect(cryptoService.encryptThumbnail).toHaveBeenCalledTimes(1);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('should handle failure when encrypting block', async () => {
|
|
327
|
-
cryptoService.encryptBlock = jest.fn().mockImplementation(async function () {
|
|
328
|
-
throw new Error('Failed to encrypt block');
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// Encrypting thumbnails is before blocks, thus it can be uploaded before failure.
|
|
332
|
-
await verifyFailure('Failed to encrypt block', 1024);
|
|
333
|
-
// 1 block + 1 retry, others are skipped
|
|
334
|
-
expect(cryptoService.encryptBlock).toHaveBeenCalledTimes(2);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
it('should handle one time-off failure when encrypting block', async () => {
|
|
338
|
-
let count = 0;
|
|
339
|
-
cryptoService.encryptBlock = jest.fn().mockImplementation(async function (verifyBlock, keys, block, index) {
|
|
340
|
-
if (count === 0) {
|
|
341
|
-
count++;
|
|
342
|
-
throw new Error('Failed to encrypt block');
|
|
343
|
-
}
|
|
344
|
-
return mockEncryptBlock(verifyBlock, keys, block, index);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
await verifySuccess();
|
|
348
|
-
// 1 block + 1 retry + 2 other blocks without retry
|
|
349
|
-
expect(cryptoService.encryptBlock).toHaveBeenCalledTimes(4);
|
|
350
|
-
await verifyOnProgress([thumbnailSize, 4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024]);
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it('should handle failure when requesting tokens', async () => {
|
|
354
|
-
apiService.requestBlockUpload = jest.fn().mockImplementation(async function () {
|
|
355
|
-
throw new Error('Failed to request tokens');
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
await verifyFailure('Failed to request tokens', 0);
|
|
359
|
-
});
|
|
127
|
+
describe('writeFile', () => {
|
|
128
|
+
// @ts-expect-error Ignore mocking File
|
|
129
|
+
const file = {
|
|
130
|
+
type: 'image/png',
|
|
131
|
+
size: 1000,
|
|
132
|
+
lastModified: 123456789,
|
|
133
|
+
stream: jest.fn().mockReturnValue('stream'),
|
|
134
|
+
} as File;
|
|
135
|
+
const thumbnails: Thumbnail[] = [];
|
|
136
|
+
const onProgress = jest.fn();
|
|
360
137
|
|
|
361
|
-
it('should
|
|
362
|
-
|
|
363
|
-
if (token === 'token/thumbnail:1') {
|
|
364
|
-
throw new Error('Failed to upload thumbnail');
|
|
365
|
-
}
|
|
366
|
-
return mockUploadBlock(bareUrl, token, block, onProgress);
|
|
367
|
-
});
|
|
138
|
+
it('should set media type if not set', async () => {
|
|
139
|
+
await uploader.writeFile(file, thumbnails, onProgress);
|
|
368
140
|
|
|
369
|
-
|
|
370
|
-
|
|
141
|
+
expect(metadata.mediaType).toEqual('image/png');
|
|
142
|
+
expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
|
|
371
143
|
});
|
|
372
144
|
|
|
373
|
-
it('should
|
|
374
|
-
|
|
375
|
-
apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
|
|
376
|
-
if (token === 'token/thumbnail:1' && count === 0) {
|
|
377
|
-
count++;
|
|
378
|
-
throw new Error('Failed to upload thumbnail');
|
|
379
|
-
}
|
|
380
|
-
return mockUploadBlock(bareUrl, token, block, onProgress);
|
|
381
|
-
});
|
|
145
|
+
it('should set expected size if not set', async () => {
|
|
146
|
+
await uploader.writeFile(file, thumbnails, onProgress);
|
|
382
147
|
|
|
383
|
-
|
|
384
|
-
expect(
|
|
385
|
-
// 3 blocks + 1 retry + 1 thumbnail
|
|
386
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
|
|
387
|
-
await verifyOnProgress([4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 1024]);
|
|
148
|
+
expect(metadata.expectedSize).toEqual(file.size);
|
|
149
|
+
expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
|
|
388
150
|
});
|
|
389
151
|
|
|
390
|
-
it('should
|
|
391
|
-
|
|
392
|
-
if (token === 'token/block:3') {
|
|
393
|
-
throw new Error('Failed to upload block');
|
|
394
|
-
}
|
|
395
|
-
return mockUploadBlock(bareUrl, token, block, onProgress);
|
|
396
|
-
});
|
|
152
|
+
it('should set modification time if not set', async () => {
|
|
153
|
+
await uploader.writeFile(file, thumbnails, onProgress);
|
|
397
154
|
|
|
398
|
-
|
|
399
|
-
|
|
155
|
+
expect(metadata.modificationTime).toEqual(new Date(123456789));
|
|
156
|
+
expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
|
|
400
157
|
});
|
|
401
158
|
|
|
402
|
-
it('should
|
|
403
|
-
|
|
404
|
-
apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
|
|
405
|
-
if (token === 'token/block:2' && count === 0) {
|
|
406
|
-
count++;
|
|
407
|
-
throw new Error('Failed to upload block');
|
|
408
|
-
}
|
|
409
|
-
return mockUploadBlock(bareUrl, token, block, onProgress);
|
|
410
|
-
});
|
|
159
|
+
it('should throw an error if upload already started', async () => {
|
|
160
|
+
await uploader.writeFile(file, thumbnails, onProgress);
|
|
411
161
|
|
|
412
|
-
await
|
|
413
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
|
|
414
|
-
// 3 blocks + 1 retry + 1 thumbnail
|
|
415
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
|
|
416
|
-
await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
|
|
162
|
+
await expect(uploader.writeFile(file, thumbnails, onProgress)).rejects.toThrow('Upload already started');
|
|
417
163
|
});
|
|
164
|
+
});
|
|
418
165
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
count++;
|
|
424
|
-
throw new APIHTTPError('Expired token', HTTPErrorCode.NOT_FOUND);
|
|
425
|
-
}
|
|
426
|
-
return mockUploadBlock(bareUrl, token, block, onProgress);
|
|
427
|
-
});
|
|
166
|
+
describe('writeStream', () => {
|
|
167
|
+
const stream = new ReadableStream();
|
|
168
|
+
const thumbnails: Thumbnail[] = [];
|
|
169
|
+
const onProgress = jest.fn();
|
|
428
170
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(2);
|
|
432
|
-
expect(apiService.requestBlockUpload).toHaveBeenCalledWith(
|
|
433
|
-
revisionDraft.nodeRevisionUid,
|
|
434
|
-
revisionDraft.nodeKeys.signatureAddress.addressId,
|
|
435
|
-
{
|
|
436
|
-
contentBlocks: [
|
|
437
|
-
{
|
|
438
|
-
index: 2,
|
|
439
|
-
encryptedSize: 4 * 1024 * 1024 + 10000,
|
|
440
|
-
hash: 'blockHash',
|
|
441
|
-
armoredSignature: 'signature',
|
|
442
|
-
verificationToken: 'verificationToken',
|
|
443
|
-
}
|
|
444
|
-
],
|
|
445
|
-
},
|
|
446
|
-
);
|
|
447
|
-
// 3 blocks + 1 retry + 1 thumbnail
|
|
448
|
-
expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
|
|
449
|
-
await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
|
|
450
|
-
});
|
|
171
|
+
it('should start the upload process', async () => {
|
|
172
|
+
await uploader.writeStream(stream, thumbnails, onProgress);
|
|
451
173
|
|
|
452
|
-
|
|
453
|
-
const error = new Error('Aborted');
|
|
454
|
-
const controller = uploader.writeStream(stream, thumbnails, onProgress);
|
|
455
|
-
abortController.abort(error);
|
|
456
|
-
await controller.completion();
|
|
457
|
-
expect(apiService.uploadBlock.mock.calls[0][4]?.aborted).toBe(true);
|
|
174
|
+
expect(startUploadSpy).toHaveBeenCalledWith(stream, thumbnails, onProgress);
|
|
458
175
|
});
|
|
459
176
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
blockVerifier.verifyBlock = jest.fn().mockRejectedValue(new IntegrityError('Block verification error'));
|
|
463
|
-
await verifyFailure('Block verification error', 1024);
|
|
464
|
-
expect(telemetry.logBlockVerificationError).toHaveBeenCalledWith(false);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
it('should report block verification error when retry helped', async () => {
|
|
468
|
-
blockVerifier.verifyBlock = jest.fn().mockRejectedValueOnce(new IntegrityError('Block verification error')).mockResolvedValue({
|
|
469
|
-
verificationToken: new Uint8Array(),
|
|
470
|
-
});
|
|
471
|
-
await verifySuccess();
|
|
472
|
-
expect(telemetry.logBlockVerificationError).toHaveBeenCalledWith(true);
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
it('should throw an error if block count does not match', async () => {
|
|
476
|
-
uploader = new Fileuploader(
|
|
477
|
-
telemetry,
|
|
478
|
-
apiService,
|
|
479
|
-
cryptoService,
|
|
480
|
-
uploadManager,
|
|
481
|
-
blockVerifier,
|
|
482
|
-
revisionDraft,
|
|
483
|
-
{
|
|
484
|
-
// Fake expected size to break verification
|
|
485
|
-
expectedSize: 1 * 1024 * 1024 + 1024,
|
|
486
|
-
mediaType: '',
|
|
487
|
-
},
|
|
488
|
-
onFinish,
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
await verifyFailure(
|
|
492
|
-
'Some file parts failed to upload',
|
|
493
|
-
10 * 1024 * 1024 + 1024,
|
|
494
|
-
1 * 1024 * 1024 + 1024,
|
|
495
|
-
);
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
it('should throw an error if file size does not match', async () => {
|
|
499
|
-
cryptoService.encryptBlock = jest.fn().mockImplementation(async (_, __, block, index) => ({
|
|
500
|
-
index,
|
|
501
|
-
encryptedData: block,
|
|
502
|
-
armoredSignature: 'signature',
|
|
503
|
-
verificationToken: 'verificationToken',
|
|
504
|
-
originalSize: 0, // Fake original size to break verification
|
|
505
|
-
encryptedSize: block.length + 10000,
|
|
506
|
-
hash: 'blockHash',
|
|
507
|
-
}));
|
|
177
|
+
it('should throw an error if upload already started', async () => {
|
|
178
|
+
await uploader.writeStream(stream, thumbnails, onProgress);
|
|
508
179
|
|
|
509
|
-
|
|
510
|
-
});
|
|
180
|
+
await expect(uploader.writeStream(stream, thumbnails, onProgress)).rejects.toThrow('Upload already started');
|
|
511
181
|
});
|
|
512
182
|
});
|
|
513
183
|
});
|