Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cortex-js/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
},
],
},
};
24 changes: 15 additions & 9 deletions cortex-js/src/infrastructure/commanders/serve.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,22 @@ export class ServeCommand extends CommandRunner {
const host = options?.host || defaultCortexJsHost;
const port = options?.port || defaultCortexJsPort;

spawn('node', [join(__dirname, '../../main.js')], {
env: {
...process.env,
CORTEX_JS_HOST: host,
CORTEX_JS_PORT: port.toString(),
NODE_ENV: 'production',
spawn(
'node',
process.env.TEST
? [join(__dirname, '../../../dist/src/main.js')]
: [join(__dirname, '../../main.js')],
{
env: {
...process.env,
CORTEX_JS_HOST: host,
CORTEX_JS_PORT: port.toString(),
NODE_ENV: 'production',
},
stdio: 'inherit',
detached: false,
},
stdio: 'inherit',
detached: false,
});
);
}

@Option({
Expand Down
107 changes: 107 additions & 0 deletions cortex-js/src/infrastructure/commanders/test/helpers.command.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { TestingModule } from '@nestjs/testing';
import { spy, Stub, stubMethod } from 'hanbi';
import { CommandTestFactory } from 'nest-commander-testing';
import { CommandModule } from '@/command.module';
import { LogService } from '@/infrastructure/commanders/test/log.service';
import axios from 'axios';

let commandInstance: TestingModule,
exitSpy: Stub<typeof process.exit>,
stdoutSpy: Stub<typeof process.stdout.write>,
stderrSpy: Stub<typeof process.stderr.write>;
export const timeout = 500000;

beforeEach(
() =>
new Promise<void>(async (res) => {
stubMethod(process.stderr, 'write');
exitSpy = stubMethod(process, 'exit');
stdoutSpy = stubMethod(process.stdout, 'write');
stderrSpy = stubMethod(process.stderr, 'write');
commandInstance = await CommandTestFactory.createTestingCommand({
imports: [CommandModule],
})
.overrideProvider(LogService)
.useValue({ log: spy().handler })
.compile();
res();
stdoutSpy.reset();
stderrSpy.reset();
}),
);

describe('Helper commands', () => {
test(
'Init with hardware auto detection',
async () => {
await CommandTestFactory.run(commandInstance, ['init', '-s']);

// Wait for a brief period to allow the command to execute
await new Promise((resolve) => setTimeout(resolve, 1000));

expect(stdoutSpy.firstCall?.args.length).toBeGreaterThan(0);
},
timeout,
);

test('Chat with option -m', async () => {
const logMock = stubMethod(console, 'log');

await CommandTestFactory.run(commandInstance, [
'chat',
// '-m',
// 'hello',
// '>output.txt',
]);
expect(logMock.firstCall?.args[0]).toBe("Inorder to exit, type 'exit()'.");
// expect(exitSpy.callCount).toBe(1);
// expect(exitSpy.firstCall?.args[0]).toBe(1);
});

test('Show / kill running models', async () => {
const tableMock = stubMethod(console, 'table');

const logMock = stubMethod(console, 'log');
await CommandTestFactory.run(commandInstance, ['kill']);
await CommandTestFactory.run(commandInstance, ['ps']);

expect(logMock.firstCall?.args[0]).toEqual({
message: 'Cortex stopped successfully',
status: 'success',
});
expect(tableMock.firstCall?.args[0]).toBeInstanceOf(Array);
expect(tableMock.firstCall?.args[0].length).toEqual(0);
});

test('Help command return guideline to users', async () => {
await CommandTestFactory.run(commandInstance, ['-h']);
expect(stdoutSpy.firstCall?.args).toBeInstanceOf(Array);
expect(stdoutSpy.firstCall?.args.length).toBe(1);
expect(stdoutSpy.firstCall?.args[0]).toContain('display help for command');

expect(exitSpy.callCount).toBeGreaterThan(1);
expect(exitSpy.firstCall?.args[0]).toBe(0);
});

test('Should handle missing command', async () => {
await CommandTestFactory.run(commandInstance, ['--unknown']);
expect(stderrSpy.firstCall?.args[0]).toContain('error: unknown option');
expect(stderrSpy.firstCall?.args[0]).toContain('--unknown');
expect(exitSpy.callCount).toBe(1);
expect(exitSpy.firstCall?.args[0]).toBe(1);
});

test('Local API server via localhost:1337/api', async () => {
await CommandTestFactory.run(commandInstance, ['serve']);

// Add a delay of 1000 milliseconds (1 second)
return new Promise<void>(async (resolve) => {
setTimeout(async () => {
// Send a request to the API server to check if it's running
const response = await axios.get('http://localhost:1337/api');
expect(response.status).toBe(200);
resolve();
}, 1000);
});
});
});
8 changes: 8 additions & 0 deletions cortex-js/src/infrastructure/commanders/test/log.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class LogService {
log(...args: any[]): void {
console.log(...args);
}
}

This file was deleted.

100 changes: 100 additions & 0 deletions cortex-js/src/infrastructure/commanders/test/models.command.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { TestingModule } from '@nestjs/testing';
import { stubMethod } from 'hanbi';
import { CommandTestFactory } from 'nest-commander-testing';
import { CommandModule } from '@/command.module';
import { join } from 'path';
import { rmSync } from 'fs';
import { timeout } from '@/infrastructure/commanders/test/helpers.command.spec';

let commandInstance: TestingModule;

beforeEach(
() =>
new Promise<void>(async (res) => {
commandInstance = await CommandTestFactory.createTestingCommand({
imports: [CommandModule],
})
// .overrideProvider(LogService)
// .useValue({})
.compile();
res();
}),
);

afterEach(
() =>
new Promise<void>(async (res) => {
// Attempt to clean test folder
rmSync(join(__dirname, 'test_data'), {
recursive: true,
force: true,
});
res();
}),
);

export const modelName = 'tinyllama';
describe('Models list returns array of models', () => {
test('Init with CPU', async () => {
const logMock = stubMethod(console, 'log');

logMock.passThrough();
CommandTestFactory.setAnswers(['CPU', '', 'AVX2']);

await CommandTestFactory.run(commandInstance, ['init']);
expect(logMock.firstCall?.args[0]).toBe(
'Downloading engine file windows-amd64-avx2.tar.gz',
);
}, 50000);

test('Empty model list', async () => {
const logMock = stubMethod(console, 'table');

await CommandTestFactory.run(commandInstance, ['models', 'list']);
expect(logMock.firstCall?.args[0]).toBeInstanceOf(Array);
expect(logMock.firstCall?.args[0].length).toBe(0);
});

test(
'Run model and check with cortex ps',
async () => {
const logMock = stubMethod(console, 'log');

await CommandTestFactory.run(commandInstance, ['run', modelName]);
expect(logMock.lastCall?.args[0]).toBe("Inorder to exit, type 'exit()'.");

const tableMock = stubMethod(console, 'table');
await CommandTestFactory.run(commandInstance, ['ps']);
expect(tableMock.firstCall?.args[0].length).toBeGreaterThan(0);
},
timeout,
);

test('Get model', async () => {
const logMock = stubMethod(console, 'log');

await CommandTestFactory.run(commandInstance, ['models', 'get', modelName]);
expect(logMock.firstCall?.args[0]).toBeInstanceOf(Object);
expect(logMock.firstCall?.args[0].files.length).toBe(1);
});

test('Many models in the list', async () => {
const logMock = stubMethod(console, 'table');
await CommandTestFactory.run(commandInstance, ['models', 'list']);
expect(logMock.firstCall?.args[0]).toBeInstanceOf(Array);
expect(logMock.firstCall?.args[0].length).toBe(1);
expect(logMock.firstCall?.args[0][0].id).toBe(modelName);
});

test(
'Model already exists',
async () => {
const stdoutSpy = stubMethod(process.stdout, 'write');
const exitSpy = stubMethod(process, 'exit');
await CommandTestFactory.run(commandInstance, ['pull', modelName]);
expect(stdoutSpy.firstCall?.args[0]).toContain('Model already exists');
expect(exitSpy.firstCall?.args[0]).toBe(1);
},
timeout,
);
});