Repository: internxt/drive-desktop
Pull request #719: Implementation of Retry Logic in Usage Service and Refactoring
Author: login: ArceDanielShok
Created: 2025-04-14T12:10:10Z | Merged: 2025-04-14T15:05:31Z

This Pull Request introduces improvements to the resilience of the usage service and performs code cleanup.

- Retry Logic in Usage Service:
  - A retry logic has been implemented in the usage service. In case of failures, the service will attempt the operation again after a short sleep period, thus avoiding overloading the system with immediate requests after an error.
- Test Addition:
  - Unit tests have been added for the new retry logic in the usage service, ensuring its correct functionality and robustness.
- Removal of Unused Code:
  - Code that was no longer used in the project has been identified and removed, simplifying the codebase and improving its maintainability.


Diff:
diff --git a/src/apps/backups/dependency-injection/BackupsDependencyContainerFactory.ts b/src/apps/backups/dependency-injection/BackupsDependencyContainerFactory.ts
index d20dbe1ea7..8402b58768 100644
--- a/src/apps/backups/dependency-injection/BackupsDependencyContainerFactory.ts
+++ b/src/apps/backups/dependency-injection/BackupsDependencyContainerFactory.ts
@@ -7,7 +7,6 @@ import { registerLocalFileServices } from './local/registerLocalFileServices';
 import { Backup } from '../Backups';
 import { registerLocalTreeServices } from './local/registerLocalTreeServices';
 import { registerRemoteTreeServices } from './virtual-drive/registerRemoteTreeServices';
-import { registerUserUsageServices } from './user/registerUsageServices';
 
 export class BackupsDependencyContainerFactory {
   static async build(): Promise<Container> {
@@ -32,9 +31,6 @@ export class BackupsDependencyContainerFactory {
       Logger.info('[BackupsDependencyContainerFactory] Registering local tree services.');
       await registerLocalTreeServices(builder);
 
-      Logger.info('[BackupsDependencyContainerFactory] Registering user usage services.');
-      await registerUserUsageServices(builder);
-
       Logger.info('[BackupsDependencyContainerFactory] Registering Backup service.');
       await builder.registerAndUse(Backup);
       const container = builder.build();
diff --git a/src/apps/backups/dependency-injection/user/registerUsageServices.ts b/src/apps/backups/dependency-injection/user/registerUsageServices.ts
deleted file mode 100644
index 4ca461e93d..0000000000
--- a/src/apps/backups/dependency-injection/user/registerUsageServices.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ContainerBuilder } from 'diod';
-import { IpcUserUsageRepository } from '../../../../context/user/usage/infrastrucutre/IpcUserUsageRepository';
-
-export async function registerUserUsageServices(builder: ContainerBuilder) {
-  // Infra
-  builder.register(IpcUserUsageRepository).useClass(IpcUserUsageRepository).private();
-}
diff --git a/src/apps/main/usage/handlers.ts b/src/apps/main/usage/handlers.ts
index 4eb3c1db79..8c54f640c2 100644
--- a/src/apps/main/usage/handlers.ts
+++ b/src/apps/main/usage/handlers.ts
@@ -1,8 +1,6 @@
-import Logger from 'electron-log';
 import { ipcMain } from 'electron';
 import { buildUsageService } from './serviceBuilder';
 import { UserUsageService } from './service';
-import { AccountIpcMain } from '../../shared/IPC/events/account/AccountIpcMain';
 
 let service: UserUsageService | null = null;
 
@@ -13,19 +11,4 @@ export function registerUsageHandlers() {
     }
     return service.calculateUsage();
   });
-
-  AccountIpcMain.handle('account.get-usage', async () => {
-    try {
-      if (!service) {
-        service = buildUsageService();
-      }
-
-      const raw = await service.raw();
-
-      return raw;
-    } catch (error) {
-      Logger.error('Error getting usage', error);
-      throw error;
-    }
-  });
 }
diff --git a/src/apps/main/usage/service.test.ts b/src/apps/main/usage/service.test.ts
new file mode 100644
index 0000000000..0344e6ad5b
--- /dev/null
+++ b/src/apps/main/usage/service.test.ts
@@ -0,0 +1,76 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { UserUsageService } from './service';
+import { DriveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
+import { mockDeep } from 'vitest-mock-extended';
+
+const driveServerWipModule = mockDeep<DriveServerWipModule>();
+
+describe('UserUsageService', () => {
+  let service: UserUsageService;
+
+  beforeEach(() => {
+    service = new UserUsageService(driveServerWipModule);
+    vi.clearAllMocks();
+  });
+
+  it('should calculate usage correctly', async () => {
+    vi.mocked(driveServerWipModule.user.getUsage).mockResolvedValue({ data: { drive: 5000 }, error: undefined });
+    vi.mocked(driveServerWipModule.user.getLimit).mockResolvedValue({ data: { maxSpaceBytes: 10000 }, error: undefined });
+
+    const result = await service.calculateUsage();
+
+    expect(result).toEqual({
+      usageInBytes: 5000,
+      limitInBytes: 10000,
+      isInfinite: false,
+      offerUpgrade: true,
+    });
+    expect(driveServerWipModule.user.getUsage).toHaveBeenCalledTimes(1);
+    expect(driveServerWipModule.user.getLimit).toHaveBeenCalledTimes(1);
+  });
+
+  it('should handle infinite space threshold', async () => {
+    driveServerWipModule.user.getUsage.mockResolvedValue({ data: { drive: 5000 }, error: undefined });
+    driveServerWipModule.user.getLimit.mockResolvedValue({ data: { maxSpaceBytes: 108851651149824 }, error: undefined });
+
+    const result = await service.calculateUsage();
+
+    expect(result.isInfinite).toBe(true);
+    expect(result.offerUpgrade).toBe(false);
+  });
+
+  it('should retry on failure and succeed', async () => {
+    let attempts = 0;
+    driveServerWipModule.user.getUsage.mockImplementation(async () => {
+      attempts++;
+      if (attempts < 3) throw new Error('Temporary error');
+      return await { data: { drive: 5000 }, error: undefined };
+    });
+    driveServerWipModule.user.getLimit.mockResolvedValue({ data: { maxSpaceBytes: 10000 }, error: undefined });
+
+    const result = await service.calculateUsage();
+
+    expect(result.usageInBytes).toBe(5000);
+    expect(attempts).toBe(3);
+  });
+
+  it('should throw an error after max retries', async () => {
+    driveServerWipModule.user.getUsage.mockRejectedValue(new Error('Permanent error'));
+    driveServerWipModule.user.getLimit.mockResolvedValue({ data: { maxSpaceBytes: 10000 }, error: undefined });
+
+    await expect(service.calculateUsage()).rejects.toThrow('Permanent error');
+    expect(driveServerWipModule.user.getUsage).toHaveBeenCalledTimes(3);
+  });
+
+  it('should return raw usage data', async () => {
+    driveServerWipModule.user.getUsage.mockResolvedValue({ data: { drive: 7000 }, error: undefined });
+    driveServerWipModule.user.getLimit.mockResolvedValue({ data: { maxSpaceBytes: 15000 }, error: undefined });
+
+    const result = await service.raw();
+
+    expect(result).toEqual({
+      driveUsage: 7000,
+      limitInBytes: 15000,
+    });
+  });
+});
diff --git a/src/apps/main/usage/service.ts b/src/apps/main/usage/service.ts
index ce720e3894..01c56ca6ce 100644
--- a/src/apps/main/usage/service.ts
+++ b/src/apps/main/usage/service.ts
@@ -1,3 +1,4 @@
+import { sleep } from '../util';
 import { Usage } from './Usage';
 import { driveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
 
@@ -5,16 +6,36 @@ const INFINITE_SPACE_TRHESHOLD = 108851651149824;
 const OFFER_UPGRADE_TRHESHOLD = 2199023255552;
 
 export class UserUsageService {
+  constructor(private driveServerWip = driveServerWipModule) {}
+  private async retry<T>(fn: () => Promise<T>, retries = 3, delay = 1000): Promise<T> {
+    let attempts = 0;
+    while (attempts < retries) {
+      try {
+        return await fn();
+      } catch (error) {
+        attempts++;
+        if (attempts >= retries) throw error;
+        await sleep(delay);
+        delay *= 2;
+      }
+    }
+    throw new Error('Max retries reached');
+  }
+
   private async getDriveUsage(): Promise<number> {
-    const res = await driveServerWipModule.user.getUsage();
-    if (res.error) throw res.error;
-    return res.data.drive;
+    return await this.retry(async () => {
+      const res = await this.driveServerWip.user.getUsage();
+      if (res.error) throw res.error;
+      return res.data.drive;
+    });
   }
 
   private async getLimit(): Promise<number> {
-    const res = await driveServerWipModule.user.getLimit();
-    if (res.error) throw res.error;
-    return res.data.maxSpaceBytes;
+    return await this.retry(async () => {
+      const res = await this.driveServerWip.user.getLimit();
+      if (res.error) throw res.error;
+      return res.data.maxSpaceBytes;
+    });
   }
 
   async calculateUsage(): Promise<Usage> {
diff --git a/src/apps/shared/IPC/events/account/AccountIpcMain.ts b/src/apps/shared/IPC/events/account/AccountIpcMain.ts
deleted file mode 100644
index 104b525200..0000000000
--- a/src/apps/shared/IPC/events/account/AccountIpcMain.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { ipcMain } from 'electron';
-import { TypedIPC } from '../../TypedIPC';
-import { BackgroundProcessAccountMessages } from './BackgroundProcessAccountMessages';
-import { MainProcessAccountMessages } from './MainProcessAccountMessages';
-
-export type TAccountIpcMain = TypedIPC<BackgroundProcessAccountMessages, MainProcessAccountMessages>;
-
-export const AccountIpcMain = ipcMain as unknown as TAccountIpcMain;
diff --git a/src/apps/shared/IPC/events/account/AccountIpcRenderer.ts b/src/apps/shared/IPC/events/account/AccountIpcRenderer.ts
deleted file mode 100644
index 44d5271739..0000000000
--- a/src/apps/shared/IPC/events/account/AccountIpcRenderer.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { ipcRenderer } from 'electron';
-import { TypedIPC } from '../../TypedIPC';
-import { BackgroundProcessAccountMessages } from './BackgroundProcessAccountMessages';
-import { MainProcessAccountMessages } from './MainProcessAccountMessages';
-
-export type TAccountIpcRenderer = TypedIPC<MainProcessAccountMessages, BackgroundProcessAccountMessages>;
-
-export const AccountIpcRenderer = ipcRenderer as unknown as TAccountIpcRenderer;
diff --git a/src/apps/shared/IPC/events/account/BackgroundProcessAccountMessages.ts b/src/apps/shared/IPC/events/account/BackgroundProcessAccountMessages.ts
deleted file mode 100644
index 13dde7c2b0..0000000000
--- a/src/apps/shared/IPC/events/account/BackgroundProcessAccountMessages.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type BackgroundProcessAccountMessages = {
-  placeholder: () => void;
-};
diff --git a/src/apps/shared/IPC/events/account/MainProcessAccountMessages.ts b/src/apps/shared/IPC/events/account/MainProcessAccountMessages.ts
deleted file mode 100644
index 74d6d9f7ec..0000000000
--- a/src/apps/shared/IPC/events/account/MainProcessAccountMessages.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { RawUsage } from '../../../../main/usage/Usage';
-
-export type MainProcessAccountMessages = {
-  'account.get-usage': () => Promise<RawUsage>;
-};
diff --git a/src/context/user/usage/infrastrucutre/IpcUserUsageRepository.ts b/src/context/user/usage/infrastrucutre/IpcUserUsageRepository.ts
deleted file mode 100644
index e200742a0c..0000000000
--- a/src/context/user/usage/infrastrucutre/IpcUserUsageRepository.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Service } from 'diod';
-import { UserUsage } from '../domain/UserUsage';
-import { AccountIpcRenderer } from '../../../../apps/shared/IPC/events/account/AccountIpcRenderer';
-
-@Service()
-export class IpcUserUsageRepository {
-  async getUsage(): Promise<UserUsage> {
-    const usage = await AccountIpcRenderer.invoke('account.get-usage');
-
-    return UserUsage.from({
-      drive: usage.driveUsage,
-      photos: usage.photosUsage,
-      limit: usage.limitInBytes,
-    });
-  }
-}
diff --git a/src/context/virtual-drive/files/domain/File.ts b/src/context/virtual-drive/files/domain/File.ts
index 6a3ef271f7..b1a2cda457 100644
--- a/src/context/virtual-drive/files/domain/File.ts
+++ b/src/context/virtual-drive/files/domain/File.ts
@@ -4,7 +4,6 @@ import { Folder } from '../../folders/domain/Folder';
 import { FilePath } from './FilePath';
 import { FileSize } from './FileSize';
 import { FileCreatedDomainEvent } from './events/FileCreatedDomainEvent';
-import { FileCannotBeMovedToTheOriginalFolderError } from './errors/FileCannotBeMovedToTheOriginalFolderError';
 import { FileActionOnlyCanAffectOneLevelError } from './errors/FileActionOnlyCanAffectOneLevelError';
 import { FileNameShouldDifferFromOriginalError } from './errors/FileNameShouldDifferFromOriginalError';
 import { FileActionCannotModifyExtension } from './errors/FileActionCannotModifyExtension';
diff --git a/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts b/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts
index 6e6eb3d6a2..87224c820d 100644
--- a/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts
+++ b/src/context/virtual-drive/files/infrastructure/InMemoryFileRepository.ts
@@ -13,7 +13,7 @@ export class InMemoryFileRepository {
     this.files = new Map();
   }
 
-  async searchByContentsIds(contentsIds: File['contentsId'][]): Promise<Array<File>> {
+  searchByContentsIds(contentsIds: File['contentsId'][]): Array<File> {
     const files = contentsIds
       .map((contentsId) => {
         const file = this.files.get(contentsId);
@@ -45,7 +45,7 @@ export class InMemoryFileRepository {
 
     return undefined;
   }
-  async delete(id: File['contentsId']): Promise<void> {
+  delete(id: File['contentsId']): void {
     const deleted = this.files.delete(id);
 
     if (!deleted) {
@@ -53,7 +53,7 @@ export class InMemoryFileRepository {
     }
   }
 
-  async add(file: File): Promise<void> {
+  add(file: File): void {
     this.files.set(file.contentsId, {
       id: file.id,
       uuid: file.uuid,
@@ -69,7 +69,7 @@ export class InMemoryFileRepository {
     });
   }
 
-  async update(file: File): Promise<void> {
+  update(file: File): void {
     if (!this.files.has(file.contentsId)) {
       throw new Error('File not found');
     }
@@ -77,7 +77,7 @@ export class InMemoryFileRepository {
     return this.add(file);
   }
 
-  async updateContentsAndSize(file: File, newContentsId: File['contentsId'], newSize: File['size']): Promise<File> {
+  updateContentsAndSize(file: File, newContentsId: File['contentsId'], newSize: File['size']): File {
     if (!this.files.has(file.contentsId)) {
       throw new Error('File not found');
     }
diff --git a/src/context/virtual-drive/files/infrastructure/NodeWinLocalFileSystem.ts b/src/context/virtual-drive/files/infrastructure/NodeWinLocalFileSystem.ts
index 9c6c7629a7..ceff5cf866 100644
--- a/src/context/virtual-drive/files/infrastructure/NodeWinLocalFileSystem.ts
+++ b/src/context/virtual-drive/files/infrastructure/NodeWinLocalFileSystem.ts
@@ -21,7 +21,7 @@ export class NodeWinLocalFileSystem {
     return `${dev}-${ino}`;
   }
 
-  async createPlaceHolder(file: File): Promise<void> {
+  createPlaceHolder(file: File): void {
     if (!file.hasStatus(FileStatuses.EXISTS)) {
       return;
     }
@@ -29,19 +29,19 @@ export class NodeWinLocalFileSystem {
     this.virtualDrive.createFileByPath(file.path, file.placeholderId, file.size, file.createdAt.getTime(), file.updatedAt.getTime());
   }
 
-  async getFileIdentity(path: File['path']): Promise<string> {
+  getFileIdentity(path: File['path']): string {
     return this.virtualDrive.getFileIdentity(path);
   }
   async deleteFileSyncRoot(path: File['path']): Promise<void> {
     await this.virtualDrive.deleteFileSyncRoot(path);
   }
 
-  async updateSyncStatus(file: File, status = true) {
+  updateSyncStatus(file: File, status = true) {
     const win32AbsolutePath = this.relativePathToAbsoluteConverter.run(file.path);
     return this.virtualDrive.updateSyncStatus(win32AbsolutePath, false, status);
   }
 
-  async convertToPlaceholder(file: File) {
+  convertToPlaceholder(file: File) {
     const win32AbsolutePath = this.relativePathToAbsoluteConverter.run(file.path);
 
     return this.virtualDrive.convertToPlaceholder(win32AbsolutePath, file.placeholderId);
@@ -51,7 +51,7 @@ export class NodeWinLocalFileSystem {
     return this.virtualDrive.getPlaceholderState(relativePath);
   }
 
-  async updateFileIdentity(path: string, newIdentity: `FILE:${string}`): Promise<void> {
+  updateFileIdentity(path: string, newIdentity: `FILE:${string}`): void {
     const isNotDirectory = true;
     return this.virtualDrive.updateFileIdentity(path, newIdentity, isNotDirectory);
   }
diff --git a/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts b/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts
index 37890182b5..5e5bbf970d 100644
--- a/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts
+++ b/src/context/virtual-drive/folders/application/Offline/OfflineFolderMover.ts
@@ -10,7 +10,7 @@ export class OfflineFolderMover {
     private readonly folderFinder: FolderFinder,
   ) {}
 
-  async run(folder: OfflineFolder, destination: FolderPath) {
+  run(folder: OfflineFolder, destination: FolderPath) {
     const resultFolder = this.offlineFolderRepository.searchByPartial({
       path: destination.value,
     });
diff --git a/src/context/virtual-drive/folders/application/create/SimpleFolderCreator.ts b/src/context/virtual-drive/folders/application/create/SimpleFolderCreator.ts
index 2fb0d1f7b2..8a82a842d5 100644
--- a/src/context/virtual-drive/folders/application/create/SimpleFolderCreator.ts
+++ b/src/context/virtual-drive/folders/application/create/SimpleFolderCreator.ts
@@ -7,7 +7,6 @@ import { FolderCreatedAt } from '../../domain/FolderCreatedAt';
 import { FolderUpdatedAt } from '../../domain/FolderUpdatedAt';
 import Logger from 'electron-log';
 import { HttpRemoteFolderSystem } from '../../infrastructure/HttpRemoteFolderSystem';
-import { OfflineFolder } from '../../domain/OfflineFolder';
 
 @Service()
 export class SimpleFolderCreator {
diff --git a/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts b/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts
index 5c83800600..4dc788fcd3 100644
--- a/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts
+++ b/src/context/virtual-drive/folders/infrastructure/InMemoryFolderRepository.ts
@@ -27,11 +27,11 @@ export class InMemoryFolderRepository {
     return undefined;
   }
 
-  async add(folder: Folder): Promise<void> {
+  add(folder: Folder): void {
     this.folders.set(folder.id, folder.attributes());
   }
 
-  async delete(id: number): Promise<void> {
+  delete(id: number): void {
     const deleted = this.folders.delete(id);
 
     if (!deleted) {
@@ -39,7 +39,7 @@ export class InMemoryFolderRepository {
     }
   }
 
-  async update(folder: Folder): Promise<void> {
+  update(folder: Folder): void {
     if (!this.folders.has(folder.id)) {
       throw new Error('Folder not found');
     }
diff --git a/src/context/virtual-drive/folders/infrastructure/NodeWinLocalFolderSystem.ts b/src/context/virtual-drive/folders/infrastructure/NodeWinLocalFolderSystem.ts
index a77dbde71e..218baab558 100644
--- a/src/context/virtual-drive/folders/infrastructure/NodeWinLocalFolderSystem.ts
+++ b/src/context/virtual-drive/folders/infrastructure/NodeWinLocalFolderSystem.ts
@@ -9,7 +9,7 @@ export class NodeWinLocalFolderSystem {
     private readonly relativePathToAbsoluteConverter: RelativePathToAbsoluteConverter,
   ) {}
 
-  async createPlaceHolder(folder: Folder): Promise<void> {
+  createPlaceHolder(folder: Folder) {
     if (!folder.hasStatus(FolderStatuses.EXISTS)) {
       return;
     }
@@ -19,21 +19,21 @@ export class NodeWinLocalFolderSystem {
     this.virtualDrive.createFolderByPath(folderPath, folder.placeholderId, 0, folder.createdAt.getTime(), folder.updatedAt.getTime());
   }
 
-  async updateSyncStatus(folder: Folder, status = true) {
+  updateSyncStatus(folder: Folder, status = true) {
     const folderPath = `${folder.path}/`;
     const win32AbsolutePath = this.relativePathToAbsoluteConverter.run(folderPath);
 
     return this.virtualDrive.updateSyncStatus(win32AbsolutePath, true, status);
   }
 
-  async getFileIdentity(path: Folder['path']) {
+  getFileIdentity(path: Folder['path']) {
     return this.virtualDrive.getFileIdentity(path);
   }
   async deleteFileSyncRoot(path: Folder['path']) {
     await this.virtualDrive.deleteFileSyncRoot(path);
   }
 
-  async convertToPlaceholder(folder: Folder) {
+  convertToPlaceholder(folder: Folder) {
     const folderPath = `${folder.path}/`;
 
     const win32AbsolutePath = this.relativePathToAbsoluteConverter.run(folderPath);
diff --git a/src/context/virtual-drive/items/application/Traverser.test.ts b/src/context/virtual-drive/items/application/Traverser.test.ts
index d0e027ea9d..5c0307835f 100644
--- a/src/context/virtual-drive/items/application/Traverser.test.ts
+++ b/src/context/virtual-drive/items/application/Traverser.test.ts
@@ -1,6 +1,6 @@
 import { mockDeep } from 'vitest-mock-extended';
-import { ServerFile, ServerFileStatus } from '../../../../../src/context/shared/domain/ServerFile';
-import { ServerFolderStatus, ServerFolder } from '../../../../../src/context/shared/domain/ServerFolder';
+import { ServerFile } from '../../../../../src/context/shared/domain/ServerFile';
+import { ServerFolder } from '../../../../../src/context/shared/domain/ServerFolder';
 import { v4 } from 'uuid';
 import { ContentsIdMother } from 'tests/context/virtual-drive/contents/domain/ContentsIdMother';
 import { CryptoJsNameDecrypt } from '../infrastructure/CryptoJsNameDecrypt';
diff --git a/src/context/virtual-drive/shared/domain/DangledFilesManager.ts b/src/context/virtual-drive/shared/domain/DangledFilesManager.ts
index 816dca771f..5a291b6e96 100644
--- a/src/context/virtual-drive/shared/domain/DangledFilesManager.ts
+++ b/src/context/virtual-drive/shared/domain/DangledFilesManager.ts
@@ -5,6 +5,7 @@ type PushAndCleanInput = {
   toDeleteContentsIds: string[];
 };
 class DangledFilesManager {
+  // eslint-disable-next-line no-use-before-define
   private static instance: DangledFilesManager;
   private accumulate: Record<string, string> = {};
   private toDelete: string[] = [];
diff --git a/src/context/virtual-drive/shared/infrastructure/NodeJsEventBus.ts b/src/context/virtual-drive/shared/infrastructure/NodeJsEventBus.ts
index ef30cc7bbc..9a5c04c28d 100644
--- a/src/context/virtual-drive/shared/infrastructure/NodeJsEventBus.ts
+++ b/src/context/virtual-drive/shared/infrastructure/NodeJsEventBus.ts
@@ -3,7 +3,7 @@ import { DomainEvent } from '../../../shared/domain/DomainEvent';
 import { DomainEventSubscriber } from '@/context/shared/domain/DomainEventSubscriber';
 
 export class NodeJsEventBus extends EventEmitter {
-  async publish(events: Array<DomainEvent>): Promise<void> {
+  publish(events: Array<DomainEvent>) {
     events.forEach((event) => {
       this.emit(event.eventName, event);
     });
diff --git a/src/infra/drive-server-wip/services/backup.service.ts b/src/infra/drive-server-wip/services/backup.service.ts
index c3de57a65f..82886c801d 100644
--- a/src/infra/drive-server-wip/services/backup.service.ts
+++ b/src/infra/drive-server-wip/services/backup.service.ts
@@ -4,7 +4,7 @@ import { ClientWrapperService } from '../in/client-wrapper.service';
 export class BackupService {
   constructor(private readonly clientWrapper = new ClientWrapperService()) {}
 
-  async getDevices() {
+  getDevices() {
     const promise = client.GET('/backup/deviceAsFolder');
 
     return this.clientWrapper.run({
@@ -19,7 +19,7 @@ export class BackupService {
     });
   }
 
-  async getDevice({ deviceUuid }: { deviceUuid: string }) {
+  getDevice({ deviceUuid }: { deviceUuid: string }) {
     const promise = client.GET('/backup/deviceAsFolder/{uuid}', {
       params: { path: { uuid: deviceUuid } },
     });
@@ -39,7 +39,7 @@ export class BackupService {
     });
   }
 
-  async createDevice({ deviceName }: { deviceName: string }) {
+  createDevice({ deviceName }: { deviceName: string }) {
     const promise = client.POST('/backup/deviceAsFolder', {
       body: { deviceName },
     });
@@ -59,7 +59,7 @@ export class BackupService {
     });
   }
 
-  async updateDevice({ deviceUuid, deviceName }: { deviceUuid: string; deviceName: string }) {
+  updateDevice({ deviceUuid, deviceName }: { deviceUuid: string; deviceName: string }) {
     const promise = client.PATCH('/backup/deviceAsFolder/{uuid}', {
       params: { path: { uuid: deviceUuid } },
       body: { deviceName },
diff --git a/src/infra/drive-server-wip/services/files.service.ts b/src/infra/drive-server-wip/services/files.service.ts
index 568cd6caa3..cabd3bbea2 100644
--- a/src/infra/drive-server-wip/services/files.service.ts
+++ b/src/infra/drive-server-wip/services/files.service.ts
@@ -9,7 +9,7 @@ type TCreateThumnailBody = paths['/files/thumbnail']['post']['requestBody']['con
 export class FilesService {
   constructor(private readonly clientWrapper = new ClientWrapperService()) {}
 
-  async getFiles(context: { query: TGetFilesQuery }) {
+  getFiles(context: { query: TGetFilesQuery }) {
     const promise = client.GET('/files', {
       params: { query: context.query },
     });
@@ -27,7 +27,7 @@ export class FilesService {
     });
   }
 
-  async moveFile(context: { uuid: string; parentUuid: string }) {
+  moveFile(context: { uuid: string; parentUuid: string }) {
     const promise = client.PATCH('/files/{uuid}', {
       body: { destinationFolder: context.parentUuid },
       params: { path: { uuid: context.uuid } },
@@ -46,7 +46,7 @@ export class FilesService {
     });
   }
 
-  async renameFile(context: { uuid: string; name: string; type: string }) {
+  renameFile(context: { uuid: string; name: string; type: string }) {
     const promise = client.PUT('/files/{uuid}/meta', {
       body: { plainName: context.name, type: context.type },
       params: { path: { uuid: context.uuid } },
@@ -65,7 +65,7 @@ export class FilesService {
     });
   }
 
-  async replaceFile(context: { uuid: string; newContentId: string; newSize: number }) {
+  replaceFile(context: { uuid: string; newContentId: string; newSize: number }) {
     const promise = client.PUT('/files/{uuid}', {
       body: { fileId: context.newContentId, size: context.newSize },
       params: { path: { uuid: context.uuid } },
@@ -84,7 +84,7 @@ export class FilesService {
     });
   }
 
-  async createThumbnail(context: { body: TCreateThumnailBody }) {
+  createThumbnail(context: { body: TCreateThumnailBody }) {
     const promise = client.POST('/files/thumbnail', {
       body: context.body,
     });
@@ -102,7 +102,7 @@ export class FilesService {
     });
   }
 
-  async deleteContentFromBucket(context: { bucketId: string; contentId: string }) {
+  deleteContentFromBucket(context: { bucketId: string; contentId: string }) {
     const promise = noContentWrapper({
       request: client.DELETE('/files/{bucketId}/{fileId}', {
         params: { path: { bucketId: context.bucketId, fileId: context.contentId } },
diff --git a/src/infra/drive-server-wip/services/folders.service.ts b/src/infra/drive-server-wip/services/folders.service.ts
index 053725a60f..45f558e539 100644
--- a/src/infra/drive-server-wip/services/folders.service.ts
+++ b/src/infra/drive-server-wip/services/folders.service.ts
@@ -9,7 +9,7 @@ type TGetFilesByFolderQuery = paths['/folders/content/{uuid}/files']['get']['par
 export class FoldersService {
   constructor(private readonly clientWrapper = new ClientWrapperService()) {}
 
-  async getMetadata({ folderId }: { folderId: number }) {
+  getMetadata({ folderId }: { folderId: number }) {
     const promise = client.GET('/folders/{id}/metadata', {
       params: { path: { id: folderId } },
     });
@@ -29,7 +29,7 @@ export class FoldersService {
     });
   }
 
-  async getMetadataWithUuid({ uuid }: { uuid: string }) {
+  getMetadataWithUuid({ uuid }: { uuid: string }) {
     const promise = client.GET('/folders/{uuid}/meta', {
       params: { path: { uuid } },
     });
@@ -49,7 +49,7 @@ export class FoldersService {
     });
   }
 
-  async getFolders({ query }: { query: TGetFoldersQuery }) {
+  getFolders({ query }: { query: TGetFoldersQuery }) {
     const promise = client.GET('/folders', { params: { query } });
 
     return this.clientWrapper.run({
@@ -121,7 +121,7 @@ export class FoldersService {
     }
   }
 
-  async moveFolder({ uuid, parentUuid }: { uuid: string; parentUuid: string }) {
+  moveFolder({ uuid, parentUuid }: { uuid: string; parentUuid: string }) {
     const promise = client.PATCH('/folders/{uuid}', {
       params: { path: { uuid } },
       body: { destinationFolder: parentUuid },
@@ -143,7 +143,7 @@ export class FoldersService {
     });
   }
 
-  async renameFolder({ uuid, plainName }: { uuid: string; plainName: string }) {
+  renameFolder({ uuid, plainName }: { uuid: string; plainName: string }) {
     const promise = client.PUT('/folders/{uuid}/meta', {
       params: { path: { uuid } },
       body: { plainName },
@@ -165,7 +165,7 @@ export class FoldersService {
     });
   }
 
-  async existsFolder({ parentUuid, basename }: { parentUuid: string; basename: string }) {
+  existsFolder({ parentUuid, basename }: { parentUuid: string; basename: string }) {
     const promise = client.POST('/folders/content/{uuid}/folders/existence', {
       params: { path: { uuid: parentUuid } },
       body: { plainNames: [basename] },
diff --git a/src/infra/drive-server-wip/services/storage.service.ts b/src/infra/drive-server-wip/services/storage.service.ts
index c98f5f8708..c44ee8fe96 100644
--- a/src/infra/drive-server-wip/services/storage.service.ts
+++ b/src/infra/drive-server-wip/services/storage.service.ts
@@ -3,7 +3,7 @@ import { noContentWrapper } from '../in/no-content-wrapper.service';
 import { clientWrapper } from '../in/client-wrapper.service';
 
 export class StorageService {
-  async deleteFile(context: { fileId: string }) {
+  deleteFile(context: { fileId: string }) {
     const promise = noContentWrapper({
       request: client.DELETE('/storage/trash/file/{fileId}', {
         params: { path: { fileId: context.fileId } },
@@ -23,7 +23,7 @@ export class StorageService {
     });
   }
 
-  async deleteFolder(context: { folderId: number }) {
+  deleteFolder(context: { folderId: number }) {
     const promise = noContentWrapper({
       request: client.DELETE('/storage/trash/folder/{folderId}', {
         params: { path: { folderId: context.folderId } },
@@ -43,7 +43,7 @@ export class StorageService {
     });
   }
 
-  async deleteFileByUuid(context: { uuid: string }) {
+  deleteFileByUuid(context: { uuid: string }) {
     const promise = noContentWrapper({
       request: client.POST('/storage/trash/add', {
         body: { items: [{ type: 'file', uuid: context.uuid, id: null }] },
@@ -63,7 +63,7 @@ export class StorageService {
     });
   }
 
-  async deleteFolderByUuid(context: { uuid: string }) {
+  deleteFolderByUuid(context: { uuid: string }) {
     const promise = noContentWrapper({
       request: client.POST('/storage/trash/add', {
         body: { items: [{ type: 'folder', uuid: context.uuid, id: null }] },
diff --git a/src/infra/drive-server-wip/services/user.service.ts b/src/infra/drive-server-wip/services/user.service.ts
index b57add3b26..4b14411153 100644
--- a/src/infra/drive-server-wip/services/user.service.ts
+++ b/src/infra/drive-server-wip/services/user.service.ts
@@ -4,7 +4,7 @@ import { ClientWrapperService } from '../in/client-wrapper.service';
 export class UserService {
   constructor(private readonly clientWrapper = new ClientWrapperService()) {}
 
-  async getUsage() {
+  getUsage() {
     const promise = client.GET('/users/usage');
 
     return this.clientWrapper.run({
@@ -19,7 +19,7 @@ export class UserService {
     });
   }
 
-  async getLimit() {
+  getLimit() {
     const promise = client.GET('/users/limit');
 
     return this.clientWrapper.run({
diff --git a/src/infra/drive-server-wip/services/workspaces.service.ts b/src/infra/drive-server-wip/services/workspaces.service.ts
index 1c74b4e1bb..80b9e22b83 100644
--- a/src/infra/drive-server-wip/services/workspaces.service.ts
+++ b/src/infra/drive-server-wip/services/workspaces.service.ts
@@ -1,7 +1,7 @@
 import { client } from '@/apps/shared/HttpClient/client';
 import { clientWrapper } from '../in/client-wrapper.service';
 
-export async function getWorkspaces() {
+export function getWorkspaces() {
   const promise = client.GET('/workspaces');
 
   return clientWrapper({
@@ -16,7 +16,7 @@ export async function getWorkspaces() {
   });
 }
 
-export async function getCredentials({ workspaceId }: { workspaceId: string }) {
+export function getCredentials({ workspaceId }: { workspaceId: string }) {
   const promise = client.GET('/workspaces/{workspaceId}/credentials', {
     params: { path: { workspaceId } },
   });
diff --git a/tests/context/virtual-drive/contents/application/ContentsDownloader.test.ts b/tests/context/virtual-drive/contents/application/ContentsDownloader.test.ts
index a584c102de..f9949b1d44 100644
--- a/tests/context/virtual-drive/contents/application/ContentsDownloader.test.ts
+++ b/tests/context/virtual-drive/contents/application/ContentsDownloader.test.ts
@@ -11,11 +11,9 @@ import { EventEmitter, Readable } from 'stream';
 import { EnvironmentRemoteFileContentsManagersFactory } from '@/context/virtual-drive/contents/infrastructure/EnvironmentRemoteFileContentsManagersFactory';
 import { EventRecorder } from '@/context/virtual-drive/shared/infrastructure/EventRecorder';
 
-// Creamos un EventEmitter real
-
 describe('Contents Downloader', () => {
   const temporalFolderProvider = async (): Promise<string> => {
-    return 'C:/temp';
+    return await 'C:/temp';
   };
 
   const localWriter = mockDeep<LocalFileWriter>();
@@ -35,7 +33,7 @@ describe('Contents Downloader', () => {
     eventEmitter.emit('error', new Error('Download stopped'));
   });
   const callbackFunction = async (data: boolean, path: string) => {
-    return {
+    return await {
       finished: data,
       progress: path.length,
     };
diff --git a/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts b/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts
index c1f0cd05d5..c71f5a3925 100644
--- a/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts
+++ b/tests/context/virtual-drive/files/application/FilePathUpdater.test.ts
@@ -54,7 +54,7 @@ describe('File path updater', () => {
     expect(remoteFileSystem.rename).toBeCalledWith(expect.objectContaining({ path: destination.value }));
   });
 
-  it('does not rename or moves a file when the extension changes', async () => {
+  it('does not rename or moves a file when the extension changes', () => {
     const fileToRename = FileMother.any();
     const fileWithDestinationPath = undefined;
 
diff --git a/tests/issues.e2e.ts b/tests/issues.e2e.ts
index 678b06240c..833202b060 100644
--- a/tests/issues.e2e.ts
+++ b/tests/issues.e2e.ts
@@ -16,7 +16,7 @@ test.describe('process issues', () => {
   let electronApp: ElectronApplication;
   let page: Page;
 
-  const addSyncErrors = async (errors: Array<ProcessErrorName>) => {
+  const addSyncErrors = (errors: Array<ProcessErrorName>) => {
     const emitEvents = errors.map(createSyncError).map((error) => ipcMainEmit(electronApp, 'SYNC_INFO_UPDATE', error));
 
     return Promise.all(emitEvents);


Reviews:
user: login: dajimenezriv-internxt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:27:12Z
user: login: dajimenezriv-internxt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:29:45Z
user: login: dajimenezriv-internxt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:36:37Z
user: login: ArceDanielShok
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:52:12Z
user: login: dajimenezriv-internxt
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T14:57:27Z

Review comments:
diff_hunk: @@ -19,7 +19,7 @@ test.describe('process issues', () => {
   const addSyncErrors = async (errors: Array<ProcessErrorName>) => {
     const emitEvents = errors.map(createSyncError).map((error) => ipcMainEmit(electronApp, 'SYNC_INFO_UPDATE', error));
 
-    return Promise.all(emitEvents);
+    return await Promise.all(emitEvents);
path: tests/issues.e2e.ts
user: login: dajimenezriv-internxt
body: Here instead of doing an wait in the Promise.all, we can just remove the async in the function, otherwise it's like awaiting two promises.
created_at: 2025-04-14T13:27:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,7 +4,7 @@ import { clientWrapper } from '../in/client-wrapper.service';
 export async function getWorkspaces() {
   const promise = client.GET('/workspaces');
 
-  return clientWrapper({
+  return await clientWrapper({
path: src/infra/drive-server-wip/services/workspaces.service.ts
user: login: dajimenezriv-internxt
body: And for all client wrappers it's the same, it's better to remove the async instead of adding await.
created_at: 2025-04-14T13:29:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,20 +1,41 @@
+import { sleep } from '../util';
 import { Usage } from './Usage';
-import { driveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
+import { DriveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
 
 const INFINITE_SPACE_TRHESHOLD = 108851651149824;
 const OFFER_UPGRADE_TRHESHOLD = 2199023255552;
 
 export class UserUsageService {
+  constructor(private driveServerWipModule = new DriveServerWipModule()) {}
path: src/apps/main/usage/service.ts
user: login: dajimenezriv-internxt
body: Do you think here is better to instance the class again? I was usually doing:
private readonly driveServerWip = driveServerWipModule, so then we have like just one singleton
created_at: 2025-04-14T13:36:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,20 +1,41 @@
+import { sleep } from '../util';
 import { Usage } from './Usage';
-import { driveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
+import { DriveServerWipModule } from '@/infra/drive-server-wip/drive-server-wip.module';
 
 const INFINITE_SPACE_TRHESHOLD = 108851651149824;
 const OFFER_UPGRADE_TRHESHOLD = 2199023255552;
 
 export class UserUsageService {
+  constructor(private driveServerWipModule = new DriveServerWipModule()) {}
path: src/apps/main/usage/service.ts
user: login: ArceDanielShok
body: I think it's irrelevant, but I can make the change

created_at: 2025-04-14T13:52:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-14T12:32:34Z
body: <h2>Coverage Report</h2>
<table> <thead> <tr> <th align="center">Status</th> <th align="left">Category</th> <th align="right">Percentage</th> <th align="right">Covered / Total</th> </tr> </thead> <tbody> <tr> <td align="center">🔵</td> <td align="left">Lines</td> <td align="right">13.49%</td> <td align="right">2893 / 21433</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Statements</td> <td align="right">13.49%</td> <td align="right">2893 / 21433</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Functions</td> <td align="right">46.83%</td> <td align="right">451 / 963</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Branches</td> <td align="right">63.7%</td> <td align="right">588 / 923</td> </tr> </tbody> </table><details><summary>File Coverage</summary>No changed files found.</details>
<em>Generated in workflow <a href=https://github.com/internxt/drive-desktop/actions/runs/14447441528>#333</a> for commit <a href="https://github.com/internxt/drive-desktop/commit/71ce0c9e467c31380090036db1090684d2f141d7">71ce0c9</a> by the <a href="https://github.com/davelosert/vitest-coverage-report-action">Vitest Coverage Report Action</a></em>

<!-- vitest-coverage-report-marker-root -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-14T13:57:40Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=internxt_drive-desktop&pullRequest=719) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [71.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=internxt_drive-desktop&pullRequest=719&metric=new_coverage&view=list) (required ≥ 80%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=internxt_drive-desktop&pullRequest=719)


author_association: NONE