Skip to content

Commit

Permalink
fix: tests
Browse files Browse the repository at this point in the history
Signed-off-by: axel7083 <[email protected]>
  • Loading branch information
axel7083 committed Apr 22, 2024
1 parent 3b8f568 commit d51f6ad
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 48 deletions.
7 changes: 3 additions & 4 deletions packages/backend/src/managers/applicationManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,6 @@ describe('pullApplication', () => {
ref: '000000',
readme: '',
repository: 'repo',
config: 'ai-lab.yaml',
};
const model: ModelInfo = {
id: 'model1',
Expand All @@ -287,7 +286,7 @@ describe('pullApplication', () => {
license: '',
name: 'Model 1',
registry: '',
url: '',
url: 'dummy-url',
memory: 1000,
};
mocks.inspectContainerMock.mockResolvedValue({
Expand Down Expand Up @@ -343,7 +342,7 @@ describe('pullApplication', () => {
description: '',
readme: '',
repository: 'repo',
config: 'ai-lab.yaml',
basedir: 'ai-lab.yaml',
};
const model: ModelInfo = {
id: 'model1',
Expand Down Expand Up @@ -372,7 +371,7 @@ describe('pullApplication', () => {
ref: '000000',
readme: '',
repository: 'repo',
config: 'ai-lab.yaml',
basedir: 'ai-lab.yaml',
};
const model: ModelInfo = {
id: 'model1',
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/managers/applicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ export class ApplicationManager extends Publisher<ApplicationState[]> implements
}

getConfigAndFilterContainers(
recipeBaseDir: string,
recipeBaseDir: string | undefined,
localFolder: string,
labels?: { [key: string]: string },
): AIContainers {
Expand Down Expand Up @@ -543,7 +543,7 @@ export class ApplicationManager extends Publisher<ApplicationState[]> implements
);
}

getConfiguration(recipeBaseDir: string, localFolder: string): AIConfigFile {
getConfiguration(recipeBaseDir: string | undefined, localFolder: string): AIConfigFile {
let configFile: string;
if (recipeBaseDir !== undefined) {
configFile = path.join(localFolder, recipeBaseDir, CONFIG_FILENAME);
Expand Down
7 changes: 5 additions & 2 deletions packages/backend/src/managers/catalogManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class CatalogManager extends Publisher<ApplicationCatalog> implements Dis
}

private loadDefaultCatalog(): void {
this.catalog = defaultCatalog;
this.catalog = defaultCatalog as ApplicationCatalog;
this.notify();
}

Expand All @@ -82,7 +82,10 @@ export class CatalogManager extends Publisher<ApplicationCatalog> implements Dis

const sanitize = this.sanitize(content);
this.catalog = {
models: [...defaultCatalog.models.filter(a => !sanitize.models.some(b => a.id === b.id)), ...sanitize.models],
models: [
...defaultCatalog.models.filter(a => !sanitize.models.some(b => a.id === b.id)),
...sanitize.models,
] as ModelInfo[],
recipes: [...defaultCatalog.recipes.filter(a => !sanitize.recipes.some(b => a.id === b.id)), ...sanitize.recipes],
categories: [
...defaultCatalog.categories.filter(a => !sanitize.categories.some(b => a.id === b.id)),
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/managers/gitManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ export class GitManager {
while (remoteCommits.length && localCommits.length) {
const remote = remoteCommits.pop();
const local = localCommits.pop();
if (!remote || !local) {
break;
}
if (remote === local) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ describe('containerRegistry events', () => {
const listener = await deferred;

const server = inferenceManager.get('dummyId');
expect(server.status).toBe('running');
expect(server?.status).toBe('running');
expect(containerEngine.inspectContainer).toHaveBeenCalledOnce();

vi.mocked(containerEngine.inspectContainer).mockResolvedValue({
Expand All @@ -578,7 +578,7 @@ describe('containerRegistry events', () => {
listener('die');

await vi.waitFor(() => {
expect(inferenceManager.get('dummyId').status).toBe('stopped');
expect(inferenceManager.get('dummyId')?.status).toBe('stopped');
expect(containerEngine.inspectContainer).toHaveBeenCalledTimes(2);
});

Expand Down Expand Up @@ -611,7 +611,7 @@ describe('containerRegistry events', () => {
const listener = await deferred;

const server = inferenceManager.get('dummyId');
expect(server.status).toBe('running');
expect(server?.status).toBe('running');

listener('remove');

Expand Down
66 changes: 36 additions & 30 deletions packages/backend/src/managers/modelsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,38 +171,40 @@ export class ModelsManager implements Disposable {

async deleteModel(modelId: string): Promise<void> {
const model = this.#models.get(modelId);
if (model) {
model.state = 'deleting';
await this.sendModelsInfo();
try {
await this.deleteRemoteModel(model);
let modelPath;
// if model does not have any url, it has been imported locally by the user
if (!model.url) {
modelPath = path.join(model.file.path, model.file.file);
// remove it from the catalog as it cannot be downloaded anymore
await this.catalogManager.removeUserModel(modelId);
} else {
modelPath = this.getLocalModelFolder(modelId);
}
await fs.promises.rm(modelPath, { recursive: true, force: true, maxRetries: 3 });

this.telemetry.logUsage('model.delete', { 'model.id': modelId });
model.file = model.state = undefined;
} catch (err: unknown) {
this.telemetry.logError('model.delete', {
'model.id': modelId,
message: 'error deleting model from disk',
error: err,
});
await podmanDesktopApi.window.showErrorMessage(`Error deleting model ${modelId}. ${String(err)}`);
if (!model?.file) {
throw new Error('model cannot be found.');
}

// Let's reload the models manually to avoid any issue
model.state = undefined;
this.getLocalModelsFromDisk();
} finally {
await this.sendModelsInfo();
model.state = 'deleting';
await this.sendModelsInfo();
try {
await this.deleteRemoteModel(model);
let modelPath;
// if model does not have any url, it has been imported locally by the user
if (!model.url) {
modelPath = path.join(model.file.path, model.file.file);
// remove it from the catalog as it cannot be downloaded anymore
await this.catalogManager.removeUserModel(modelId);
} else {
modelPath = this.getLocalModelFolder(modelId);
}
await fs.promises.rm(modelPath, { recursive: true, force: true, maxRetries: 3 });

this.telemetry.logUsage('model.delete', { 'model.id': modelId });
model.file = model.state = undefined;
} catch (err: unknown) {
this.telemetry.logError('model.delete', {
'model.id': modelId,
message: 'error deleting model from disk',
error: err,
});
await podmanDesktopApi.window.showErrorMessage(`Error deleting model ${modelId}. ${String(err)}`);

// Let's reload the models manually to avoid any issue
model.state = undefined;
this.getLocalModelsFromDisk();
} finally {
await this.sendModelsInfo();
}
}

Expand Down Expand Up @@ -326,6 +328,10 @@ export class ModelsManager implements Disposable {
}

private createDownloader(model: ModelInfo, abortSignal: AbortSignal): Downloader {
if (!model.url) {
throw new Error(`model ${model.id} does not have url defined.`);
}

// Ensure path to model directory exist
const destDir = path.join(this.appUserDirectory, 'models', model.id);
if (!fs.existsSync(destDir)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/studio-api-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export class StudioApiImpl implements StudioAPI {
}
}

async openDialog(options?: podmanDesktopApi.OpenDialogOptions): Promise<podmanDesktopApi.Uri[]> {
async openDialog(options?: podmanDesktopApi.OpenDialogOptions): Promise<podmanDesktopApi.Uri[] | undefined> {
return await podmanDesktopApi.window.showOpenDialog(options);
}

Expand Down Expand Up @@ -464,7 +464,7 @@ export class StudioApiImpl implements StudioAPI {
}

async checkInvalidModels(models: string[]): Promise<string[]> {
const invalidPaths = [];
const invalidPaths: string[] = [];
const catalogModels = await this.getModelsInfo();
for (const model of models) {
const modelPath = path.resolve(model);
Expand Down
3 changes: 2 additions & 1 deletion packages/backend/src/utils/podman.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { beforeEach, expect, test, describe, vi } from 'vitest';
import * as podmanDesktopApi from '@podman-desktop/api';
import * as utils from '../utils/podman';
import type { ContainerEngineInfo } from '@podman-desktop/api';

const mocks = vi.hoisted(() => {
return {
Expand Down Expand Up @@ -354,7 +355,7 @@ describe('checkContainerConnectionStatusAndResources', () => {
providerId: 'podman',
},
]);
vi.mocked(podmanDesktopApi.containerEngine.info).mockResolvedValue(undefined);
vi.mocked(podmanDesktopApi.containerEngine.info).mockResolvedValue(undefined as unknown as ContainerEngineInfo);
const result = await utils.checkContainerConnectionStatusAndResources({
memoryNeeded: 10,
context: 'inference',
Expand Down
15 changes: 12 additions & 3 deletions packages/backend/src/utils/podman.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export async function isQEMUMachine(): Promise<boolean> {
export async function checkContainerConnectionStatusAndResources(
modelInfo: ModelCheckerInfo,
): Promise<ContainerConnectionInfo> {
let connection: ProviderContainerConnection;
let connection: ProviderContainerConnection | undefined = undefined;
try {
connection = getFirstRunningPodmanConnection();
} catch (e) {
Expand Down Expand Up @@ -166,13 +166,22 @@ export async function checkContainerConnectionStatusAndResources(
const hasCpus = engineInfo.cpus !== undefined && engineInfo.cpus >= MIN_CPUS_VALUE;
const multiplier = modelInfo.context === 'recipe' ? 1.25 : 1.1;
const memoryExpected = modelInfo.memoryNeeded * multiplier;
const hasMemory = engineInfo.memory - engineInfo.memoryUsed >= memoryExpected;

let hasMemory: boolean = true;
if (engineInfo.memory !== undefined && engineInfo.memoryUsed !== undefined) {
hasMemory = engineInfo.memory - engineInfo.memoryUsed >= memoryExpected;
}

let memoryIdle: number = 0;
if (engineInfo.memory !== undefined && engineInfo.memoryUsed !== undefined) {
memoryIdle = engineInfo.memory - engineInfo.memoryUsed;
}

if (!hasCpus || !hasMemory) {
return {
name: connection.connection.name,
cpus: engineInfo.cpus ?? 0,
memoryIdle: engineInfo.memory - engineInfo.memoryUsed,
memoryIdle: memoryIdle,
cpusExpected: MIN_CPUS_VALUE,
memoryExpected: memoryExpected,
status: 'low-resources',
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/StudioAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export abstract class StudioAPI {
abstract pullApplication(recipeId: string, modelId: string): Promise<void>;
abstract openURL(url: string): Promise<boolean>;
abstract openFile(file: string, recipeId?: string): Promise<boolean>;
abstract openDialog(options?: OpenDialogOptions): Promise<Uri[]>;
abstract openDialog(options?: OpenDialogOptions): Promise<Uri[] | undefined>;

/**
* Get the information of models saved locally into the user's directory
Expand Down

0 comments on commit d51f6ad

Please sign in to comment.