test(orchestrator): expand unit tests for enterprise services

Add comprehensive tests for CLI provider (cleanupWorkflow, garbageCollect,
listWorkflow, watchWorkflow, stderr forwarding, timeout handling), local
cache service (saveLfsCache full path and error handling), git hooks service
(husky install, failure logging, edge cases), and LFS agent service (empty
storagePaths, validate logging). 73 tests across 4 test files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
frostebite
2026-03-05 08:20:31 +00:00
parent cfac5f138d
commit a0c79bd657
4 changed files with 314 additions and 0 deletions
@@ -207,6 +207,38 @@ describe('LocalCacheService', () => {
await LocalCacheService.saveLfsCache('/repo', '/cache', 'key1');
expect(mockFs.mkdirSync).not.toHaveBeenCalled();
});
it('should create cache directory and save tar when lfs has content', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(true);
(mockFs.readdirSync as jest.Mock).mockImplementation((dirPath: string) => {
if (String(dirPath).includes('lfs') && !String(dirPath).includes('cache')) {
return ['objects', 'tmp'];
}
return [];
});
(mockFs.statSync as jest.Mock).mockReturnValue({ mtimeMs: Date.now() });
(mockFs.mkdirSync as jest.Mock).mockReturnValue(undefined);
const { OrchestratorSystem } = require('../core/orchestrator-system');
OrchestratorSystem.Run.mockResolvedValue('');
await LocalCacheService.saveLfsCache('/repo', '/cache', 'key1');
expect(mockFs.mkdirSync).toHaveBeenCalledWith(path.join('/cache', 'key1', 'lfs'), { recursive: true });
expect(OrchestratorSystem.Run).toHaveBeenCalledWith(
expect.stringContaining('tar -cf'),
true,
);
});
it('should handle save errors gracefully', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(true);
(mockFs.readdirSync as jest.Mock).mockImplementation(() => {
throw new Error('Disk full');
});
// Should not throw
await LocalCacheService.saveLfsCache('/repo', '/cache', 'key1');
});
});
describe('garbageCollect', () => {
@@ -106,6 +106,18 @@ describe('GitHooksService', () => {
expect(OrchestratorSystem.Run).toHaveBeenCalledWith(`cd "/repo" && npx lefthook install`, true);
});
it('should run npx husky install when husky is detected', async () => {
(mockFs.existsSync as jest.Mock).mockImplementation((filePath: string) => {
return String(filePath).endsWith('.husky');
});
const { OrchestratorSystem } = require('../core/orchestrator-system');
await GitHooksService.installHooks('/repo');
expect(OrchestratorSystem.Run).toHaveBeenCalledWith(`cd "/repo" && npx husky install`, true);
});
it('should log and return when no framework is detected', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(false);
@@ -117,5 +129,45 @@ describe('GitHooksService', () => {
expect(OrchestratorSystem.Run).not.toHaveBeenCalled();
expect(OrchestratorLogger.log).toHaveBeenCalledWith(expect.stringContaining('No hook framework detected'));
});
it('should log warning on installation failure', async () => {
(mockFs.existsSync as jest.Mock).mockImplementation((filePath: string) => {
return String(filePath).includes('lefthook.yml') && !String(filePath).startsWith('.');
});
const { OrchestratorSystem } = require('../core/orchestrator-system');
const OrchestratorLogger = require('../core/orchestrator-logger').default;
OrchestratorSystem.Run.mockRejectedValue(new Error('npx not found'));
await GitHooksService.installHooks('/repo');
expect(OrchestratorLogger.logWarning).toHaveBeenCalledWith(
expect.stringContaining('Hook installation failed'),
);
});
});
describe('disableHooks', () => {
it('should log warning on failure to disable hooks', async () => {
(mockFs.mkdirSync as jest.Mock).mockReturnValue(undefined);
const { OrchestratorSystem } = require('../core/orchestrator-system');
const OrchestratorLogger = require('../core/orchestrator-logger').default;
OrchestratorSystem.Run.mockRejectedValue(new Error('git config failed'));
await GitHooksService.disableHooks('/repo');
expect(OrchestratorLogger.logWarning).toHaveBeenCalledWith(
expect.stringContaining('Failed to disable hooks'),
);
});
});
describe('configureSkipList edge cases', () => {
it('should handle single hook in skip list', () => {
const result = GitHooksService.configureSkipList(['commit-msg']);
expect(result.LEFTHOOK_EXCLUDE).toBe('commit-msg');
expect(result.HUSKY).toBe('0');
});
});
});
@@ -80,6 +80,23 @@ describe('LfsAgentService', () => {
});
});
describe('configure with empty storagePaths', () => {
it('should not set LFS_STORAGE_PATHS when storagePaths is empty', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(true);
const originalValue = process.env.LFS_STORAGE_PATHS;
delete process.env.LFS_STORAGE_PATHS;
await LfsAgentService.configure('/usr/local/bin/agent', '', [], '/repo');
expect(process.env.LFS_STORAGE_PATHS).toBeUndefined();
if (originalValue !== undefined) {
process.env.LFS_STORAGE_PATHS = originalValue;
}
});
});
describe('validate', () => {
it('should return true when agent executable exists', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(true);
@@ -92,5 +109,16 @@ describe('LfsAgentService', () => {
const result = await LfsAgentService.validate('/nonexistent/agent');
expect(result).toBe(false);
});
it('should log warning when agent does not exist', async () => {
(mockFs.existsSync as jest.Mock).mockReturnValue(false);
const OrchestratorLogger = require('../core/orchestrator-logger').default;
await LfsAgentService.validate('/nonexistent/agent');
expect(OrchestratorLogger.logWarning).toHaveBeenCalledWith(
expect.stringContaining('Agent executable not found'),
);
});
});
});