refactor: tests (#25987)

This commit is contained in:
Jason Rasmussen
2026-02-06 18:47:54 -05:00
committed by GitHub
parent b3820c259e
commit e3e243fa2b
14 changed files with 415 additions and 765 deletions

View File

@@ -0,0 +1,38 @@
import { Selectable } from 'kysely';
import { AssetEditAction } from 'src/dtos/editing.dto';
import { AssetEditTable } from 'src/schema/tables/asset-edit.table';
import { AssetFactory } from 'test/factories/asset.factory';
import { build } from 'test/factories/builder.factory';
import { AssetEditLike, AssetLike, FactoryBuilder } from 'test/factories/types';
import { newUuid } from 'test/small.factory';
export class AssetEditFactory {
private constructor(private readonly value: Selectable<AssetEditTable>) {}
static create(dto: AssetEditLike = {}) {
return AssetEditFactory.from(dto).build();
}
static from(dto: AssetEditLike = {}) {
const id = dto.id ?? newUuid();
return new AssetEditFactory({
id,
assetId: newUuid(),
action: AssetEditAction.Crop,
parameters: { x: 5, y: 6, width: 200, height: 100 },
sequence: 1,
...dto,
});
}
asset(dto: AssetLike = {}, builder?: FactoryBuilder<AssetFactory>) {
const asset = build(AssetFactory.from(dto), builder);
this.value.assetId = asset.build().id;
return this;
}
build() {
return { ...this.value } as Selectable<AssetEditTable<AssetEditAction.Crop>>;
}
}

View File

@@ -0,0 +1,43 @@
import { Selectable } from 'kysely';
import { AssetFileType } from 'src/enum';
import { AssetFileTable } from 'src/schema/tables/asset-file.table';
import { AssetFactory } from 'test/factories/asset.factory';
import { build } from 'test/factories/builder.factory';
import { AssetFileLike, AssetLike, FactoryBuilder } from 'test/factories/types';
import { newDate, newUuid, newUuidV7 } from 'test/small.factory';
export class AssetFileFactory {
private constructor(private readonly value: Selectable<AssetFileTable>) {}
static create(dto: AssetFileLike = {}) {
return AssetFileFactory.from(dto).build();
}
static from(dto: AssetFileLike = {}) {
const id = dto.id ?? newUuid();
const isEdited = dto.isEdited ?? false;
return new AssetFileFactory({
id,
assetId: newUuid(),
createdAt: newDate(),
updatedAt: newDate(),
type: AssetFileType.Thumbnail,
path: `/data/12/34/thumbs/${id.slice(0, 2)}/${id.slice(2, 4)}/${id}${isEdited ? '_edited' : ''}.jpg`,
updateId: newUuidV7(),
isProgressive: false,
isEdited,
...dto,
});
}
asset(dto: AssetLike = {}, builder?: FactoryBuilder<AssetFactory>) {
const asset = build(AssetFactory.from(dto), builder);
this.value.assetId = asset.build().id;
return this;
}
build() {
return { ...this.value };
}
}

View File

@@ -1,15 +1,20 @@
import { Selectable } from 'kysely';
import { AssetStatus, AssetType, AssetVisibility } from 'src/enum';
import { AssetFileType, AssetStatus, AssetType, AssetVisibility } from 'src/enum';
import { AssetFaceTable } from 'src/schema/tables/asset-face.table';
import { AssetTable } from 'src/schema/tables/asset.table';
import { AssetEditFactory } from 'test/factories/asset-edit.factory';
import { AssetExifFactory } from 'test/factories/asset-exif.factory';
import { AssetFileFactory } from 'test/factories/asset-file.factory';
import { build } from 'test/factories/builder.factory';
import { AssetExifLike, AssetLike, FactoryBuilder, UserLike } from 'test/factories/types';
import { AssetEditLike, AssetExifLike, AssetFileLike, AssetLike, FactoryBuilder, UserLike } from 'test/factories/types';
import { UserFactory } from 'test/factories/user.factory';
import { factory, newDate, newSha1, newUuid, newUuidV7 } from 'test/small.factory';
import { newDate, newSha1, newUuid, newUuidV7 } from 'test/small.factory';
export class AssetFactory {
#assetExif?: AssetExifFactory;
#owner!: UserFactory;
#assetExif?: AssetExifFactory;
#files: AssetFileFactory[] = [];
#edits: AssetEditFactory[] = [];
private constructor(private readonly value: Selectable<AssetTable>) {
value.ownerId ??= newUuid();
@@ -21,8 +26,12 @@ export class AssetFactory {
}
static from(dto: AssetLike = {}) {
const id = dto.id ?? newUuid();
const originalFileName = dto.originalFileName ?? `IMG_${id}.jpg`;
return new AssetFactory({
id: factory.uuid(),
id,
createdAt: newDate(),
updatedAt: newDate(),
deletedAt: null,
@@ -42,8 +51,8 @@ export class AssetFactory {
libraryId: null,
livePhotoVideoId: null,
localDateTime: newDate(),
originalFileName: 'IMG_123.jpg',
originalPath: `/data/12/34/IMG_123.jpg`,
originalFileName,
originalPath: `/data/library/${originalFileName}`,
ownerId: newUuid(),
stackId: null,
thumbhash: null,
@@ -67,13 +76,51 @@ export class AssetFactory {
return this;
}
edit(dto: AssetEditLike = {}, builder?: FactoryBuilder<AssetEditFactory>) {
this.#edits.push(build(AssetEditFactory.from(dto).asset(this.value), builder));
this.value.isEdited = true;
return this;
}
file(dto: AssetFileLike = {}, builder?: FactoryBuilder<AssetFileFactory>) {
this.#files.push(build(AssetFileFactory.from(dto).asset(this.value), builder));
return this;
}
files(dto?: 'edits'): AssetFactory;
files(items: AssetFileLike[], builder?: FactoryBuilder<AssetFileFactory>): AssetFactory;
files(items: AssetFileType[], builder?: FactoryBuilder<AssetFileFactory>): AssetFactory;
files(dto?: 'edits' | AssetFileLike[] | AssetFileType[], builder?: FactoryBuilder<AssetFileFactory>): AssetFactory {
const items: AssetFileLike[] = [];
if (dto === undefined || dto === 'edits') {
items.push(...Object.values(AssetFileType).map((type) => ({ type })));
if (dto === 'edits') {
items.push(...Object.values(AssetFileType).map((type) => ({ type, isEdited: true })));
}
} else {
for (const item of dto) {
items.push(typeof item === 'string' ? { type: item as AssetFileType } : item);
}
}
for (const item of items) {
this.file(item, builder);
}
return this;
}
build() {
const exif = this.#assetExif?.build();
return {
...this.value,
exifInfo: exif as NonNullable<typeof exif>,
owner: this.#owner.build(),
exifInfo: exif as NonNullable<typeof exif>,
files: this.#files.map((file) => file.build()),
edits: this.#edits.map((edit) => edit.build()),
faces: [] as Selectable<AssetFaceTable>[],
};
}
}

View File

@@ -1,7 +1,9 @@
import { Selectable } from 'kysely';
import { AlbumUserTable } from 'src/schema/tables/album-user.table';
import { AlbumTable } from 'src/schema/tables/album.table';
import { AssetEditTable } from 'src/schema/tables/asset-edit.table';
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
import { AssetFileTable } from 'src/schema/tables/asset-file.table';
import { AssetTable } from 'src/schema/tables/asset.table';
import { SharedLinkTable } from 'src/schema/tables/shared-link.table';
import { UserTable } from 'src/schema/tables/user.table';
@@ -10,6 +12,8 @@ export type FactoryBuilder<T, R extends T = T> = (builder: T) => R;
export type AssetLike = Partial<Selectable<AssetTable>>;
export type AssetExifLike = Partial<Selectable<AssetExifTable>>;
export type AssetEditLike = Partial<Selectable<AssetEditTable>>;
export type AssetFileLike = Partial<Selectable<AssetFileTable>>;
export type AlbumLike = Partial<Selectable<AlbumTable>>;
export type AlbumUserLike = Partial<Selectable<AlbumUserTable>>;
export type SharedLinkLike = Partial<Selectable<SharedLinkTable>>;

View File

@@ -45,56 +45,6 @@ export const albumStub = {
order: AssetOrder.Desc,
updateId: '42',
}),
sharedWithMultiple: Object.freeze({
id: 'album-3',
albumName: 'Empty album shared with users',
description: '',
ownerId: authStub.admin.user.id,
owner: userStub.admin,
assets: [],
albumThumbnailAsset: null,
albumThumbnailAssetId: null,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
albumUsers: [
{
user: userStub.user1,
role: AlbumUserRole.Editor,
},
{
user: userStub.user2,
role: AlbumUserRole.Editor,
},
],
isActivityEnabled: true,
order: AssetOrder.Desc,
updateId: '42',
}),
sharedWithAdmin: Object.freeze({
id: 'album-3',
albumName: 'Empty album shared with admin',
description: '',
ownerId: authStub.user1.user.id,
owner: userStub.user1,
assets: [],
albumThumbnailAsset: null,
albumThumbnailAssetId: null,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
albumUsers: [
{
user: userStub.admin,
role: AlbumUserRole.Editor,
},
],
isActivityEnabled: true,
order: AssetOrder.Desc,
updateId: '42',
}),
oneAsset: Object.freeze({
id: 'album-4',
albumName: 'Album with one asset',
@@ -113,24 +63,6 @@ export const albumStub = {
order: AssetOrder.Desc,
updateId: '42',
}),
twoAssets: Object.freeze({
id: 'album-4a',
albumName: 'Album with two assets',
description: '',
ownerId: authStub.admin.user.id,
owner: userStub.admin,
assets: [assetStub.image, assetStub.withLocation],
albumThumbnailAsset: assetStub.image,
albumThumbnailAssetId: assetStub.image.id,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.Desc,
updateId: '42',
}),
emptyWithValidThumbnail: Object.freeze({
id: 'album-5',
albumName: 'Empty album with valid thumbnail',

View File

@@ -20,45 +20,8 @@ const fullsizeFile = factory.assetFile({
path: '/uploads/user-id/fullsize/path.webp',
});
const sidecarFileWithExt = factory.assetFile({
type: AssetFileType.Sidecar,
path: '/original/path.ext.xmp',
});
const sidecarFileWithoutExt = factory.assetFile({
type: AssetFileType.Sidecar,
path: '/original/path.xmp',
});
const editedPreviewFile = factory.assetFile({
type: AssetFileType.Preview,
path: '/uploads/user-id/preview/path_edited.jpg',
isEdited: true,
});
const editedThumbnailFile = factory.assetFile({
type: AssetFileType.Thumbnail,
path: '/uploads/user-id/thumbnail/path_edited.jpg',
isEdited: true,
});
const editedFullsizeFile = factory.assetFile({
type: AssetFileType.FullSize,
path: '/uploads/user-id/fullsize/path_edited.jpg',
isEdited: true,
});
const files = [fullsizeFile, previewFile, thumbnailFile];
const editedFiles = [
fullsizeFile,
previewFile,
thumbnailFile,
editedFullsizeFile,
editedPreviewFile,
editedThumbnailFile,
];
export const stackStub = (stackId: string, assets: (MapAsset & { exifInfo: Exif })[]) => {
return {
id: stackId,
@@ -132,87 +95,6 @@ export const assetStub = {
isEdited: false,
}),
noWebpPath: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/data/library/IMG_456.jpg',
files: [previewFile],
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
duration: null,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'IMG_456.jpg',
faces: [],
isExternal: false,
exifInfo: {
fileSizeInByte: 123_000,
} as Exif,
deletedAt: null,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
noThumbhash: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
files,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
thumbhash: null,
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
duration: null,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
deletedAt: null,
duplicateId: null,
isOffline: false,
libraryId: null,
stackId: null,
updateId: '42',
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
primaryImage: Object.freeze({
id: 'primary-asset-id',
status: AssetStatus.Active,
@@ -526,48 +408,6 @@ export const assetStub = {
isEdited: false,
}),
imageFrom2015: Object.freeze({
id: 'asset-id-2015',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2015-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2015-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
files,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2015-02-23T05:06:29.716Z'),
updatedAt: new Date('2015-02-23T05:06:29.716Z'),
localDateTime: new Date('2015-02-23T05:06:29.716Z'),
isFavorite: true,
isExternal: false,
duration: null,
livePhotoVideo: null,
livePhotoVideoId: null,
updateId: 'foo',
libraryId: null,
stackId: null,
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
exifInfo: {
fileSizeInByte: 5000,
} as Exif,
deletedAt: null,
duplicateId: null,
isOffline: false,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
video: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
@@ -736,81 +576,6 @@ export const assetStub = {
isEdited: false,
}),
sidecar: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
thumbhash: null,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
files: [previewFile, sidecarFileWithExt],
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
isExternal: false,
duration: null,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
deletedAt: null,
duplicateId: null,
isOffline: false,
updateId: 'foo',
libraryId: null,
stackId: null,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
sidecarWithoutExt: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
thumbhash: null,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
files: [previewFile, sidecarFileWithoutExt],
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
isExternal: false,
duration: null,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
deletedAt: null,
duplicateId: null,
isOffline: false,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
hasEncodedVideo: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
@@ -854,46 +619,6 @@ export const assetStub = {
isEdited: false,
}),
hasFileExtension: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/data/user1/photo.jpg',
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
files,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
isExternal: true,
duration: null,
livePhotoVideo: null,
livePhotoVideoId: null,
libraryId: 'library-id',
sharedLinks: [],
originalFileName: 'photo.jpg',
faces: [],
deletedAt: null,
exifInfo: {
fileSizeInByte: 5000,
} as Exif,
duplicateId: null,
isOffline: false,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
imageDng: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
@@ -938,93 +663,6 @@ export const assetStub = {
isEdited: false,
}),
imageHif: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.hif',
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
files,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
duration: null,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'asset-id.hif',
faces: [],
deletedAt: null,
exifInfo: {
fileSizeInByte: 5000,
profileDescription: 'Adobe RGB',
bitsPerSample: 14,
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
isEdited: false,
}),
panoramaTif: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.tif',
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
files,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
isFavorite: true,
duration: null,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
sharedLinks: [],
originalFileName: 'asset-id.tif',
faces: [],
deletedAt: null,
sidecarPath: null,
exifInfo: {
fileSizeInByte: 5000,
projectionType: 'EQUIRECTANGULAR',
} as Exif,
duplicateId: null,
isOffline: false,
updateId: '42',
libraryId: null,
stackId: null,
visibility: AssetVisibility.Timeline,
width: null,
height: null,
edits: [],
}),
withCropEdit: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
@@ -1082,52 +720,4 @@ export const assetStub = {
] as AssetEditActionItem[],
isEdited: true,
}),
withoutEdits: Object.freeze({
id: 'asset-id',
status: AssetStatus.Active,
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.jpg',
files: editedFiles,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.Image,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
localDateTime: new Date('2025-01-01T01:02:03.456Z'),
isFavorite: true,
duration: null,
isExternal: false,
livePhotoVideo: null,
livePhotoVideoId: null,
updateId: 'foo',
libraryId: null,
stackId: null,
sharedLinks: [],
originalFileName: 'asset-id.jpg',
faces: [],
deletedAt: null,
sidecarPath: null,
exifInfo: {
fileSizeInByte: 5000,
exifImageHeight: 3840,
exifImageWidth: 2160,
} as Exif,
duplicateId: null,
isOffline: false,
stack: null,
orientation: '',
projectionType: null,
height: 3840,
width: 2160,
visibility: AssetVisibility.Timeline,
edits: [],
isEdited: false,
}),
};

View File

@@ -38,21 +38,4 @@ export const userStub = {
quotaSizeInBytes: null,
quotaUsageInBytes: 0,
},
user2: <UserAdmin>{
...authStub.user2.user,
status: UserStatus.Active,
profileChangedAt: new Date('2021-01-01'),
metadata: [],
name: 'immich_name',
storageLabel: null,
oauthId: '',
shouldChangePassword: false,
avatarColor: null,
profileImagePath: '',
createdAt: new Date('2021-01-01'),
deletedAt: null,
updatedAt: new Date('2021-01-01'),
quotaSizeInBytes: null,
quotaUsageInBytes: 0,
},
};