feat(k8s): add HelmService and rewrite deleteApplication
- New HelmService wrapping Helm CLI (install/upgrade, rollback, uninstall, history, status) - deleteApplication: helm uninstall + explicit cleanup of kept PVCs, secrets, TLS certs - buildHelmValues: include registry.url for pull secret - Add scaleDeployment for lifecycle suspend/resume - Unit tests for buildHelmValues and HelmService
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { HelmService } from './helm.service';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
describe('HelmService', () => {
|
||||
let service: HelmService;
|
||||
let writeSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
writeSpy = jest.spyOn(fs.promises, 'writeFile').mockResolvedValue(undefined);
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [HelmService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<HelmService>(HelmService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
writeSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
describe('chartPath', () => {
|
||||
it('should resolve to helm/cloudhost-app relative to project root', () => {
|
||||
const expectedSuffix = path.join('helm', 'cloudhost-app');
|
||||
expect((service as any).chartPath).toContain(expectedSuffix);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeTempKubeconfig', () => {
|
||||
it('should write kubeconfig with mode 0o600', async () => {
|
||||
const result = await (service as any).writeTempKubeconfig('apiVersion: v1\nclusters: []');
|
||||
expect(writeSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('cloudhost-kube-'),
|
||||
'apiVersion: v1\nclusters: []',
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
expect(typeof result).toBe('string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeTempValues', () => {
|
||||
it('should write values as JSON with mode 0o600', async () => {
|
||||
const values = { app: { name: 'test' } };
|
||||
const result = await (service as any).writeTempValues(values);
|
||||
expect(writeSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('cloudhost-vals-'),
|
||||
JSON.stringify(values, null, 2),
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
expect(result).toContain('.json');
|
||||
});
|
||||
});
|
||||
|
||||
describe('cleanupTempFiles', () => {
|
||||
it('should not throw if no files provided', () => {
|
||||
expect(() => (service as any).cleanupTempFiles()).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('history - parsing', () => {
|
||||
it('should map app_version to appVersion', () => {
|
||||
const raw = [
|
||||
{ revision: 1, updated: '2024-01-01', status: 'deployed', chart: 'cloudhost-app-0.1.0', app_version: '1.0.0', description: 'Install complete' },
|
||||
{ revision: 2, updated: '2024-01-02', status: 'superseded', chart: 'cloudhost-app-0.1.0', app_version: '1.0.0', description: 'Upgrade complete' },
|
||||
];
|
||||
const mapped = raw.map((r) => ({
|
||||
revision: r.revision,
|
||||
updated: r.updated,
|
||||
status: r.status,
|
||||
chart: r.chart,
|
||||
appVersion: r.app_version,
|
||||
description: r.description,
|
||||
}));
|
||||
expect(mapped[0].appVersion).toBe('1.0.0');
|
||||
expect(mapped[1].revision).toBe(2);
|
||||
expect(mapped).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user