Files
cloud-host/backend/src/build/build.service.spec.ts
T
keyhan 1ec4d07939 Add egress proxy to user-app Kaniko build jobs.
Inject registry-egress-proxy into Kaniko and network init containers so npm/apk/composer/pip/git clone work on restricted egress clusters.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 18:07:48 +03:30

166 lines
5.4 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { ConfigService } from '@nestjs/config';
import * as path from 'path';
import { BuildService } from './build.service';
import { Application } from '../applications/entities/application.entity';
import { AppRuntime } from '../common/enums';
import { ClustersService } from '../clusters/clusters.service';
import { RegistryService } from '../kubernetes/registry.service';
import { BuildProgressStore } from './build-progress.store';
import { SourceStorageService } from '../storage/source-storage.service';
describe('BuildService', () => {
let service: BuildService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
BuildService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
const map: Record<string, string> = {
'build.namespace': 'cloudhost-builds',
'build.serviceAccount': 'kaniko-builder',
'registry.url': 'registry.local:5000',
};
return map[key];
}),
},
},
{ provide: ClustersService, useValue: {} },
{
provide: BuildProgressStore,
useValue: { get: jest.fn(), set: jest.fn(), clear: jest.fn() },
},
{ provide: RegistryService, useValue: {} },
{
provide: SourceStorageService,
useValue: {
isObjectStorage: () => false,
materializeToTempFile: jest.fn(),
getSize: jest.fn(),
},
},
],
}).compile();
service = module.get(BuildService);
});
describe('generateDockerfile', () => {
it('generates Go Dockerfile with requested runtime version', () => {
const app = {
runtime: AppRuntime.GO,
runtimeVersion: '1.22',
port: 8080,
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('FROM golang:1.22-alpine');
expect(dockerfile).toContain('EXPOSE 8080');
});
it('generates Go Dockerfile with cmd package when present in archive entries', () => {
const app = {
runtime: AppRuntime.GO,
runtimeVersion: '1.22',
port: 8080,
} as Application;
const dockerfile = (service as any).generateDockerfile(app, [
'go.mod',
'cmd/server/main.go',
]) as string;
expect(dockerfile).toContain('go build -a -installsuffix cgo -ldflags="-w -s" -o main ./cmd/server');
});
it('generates Node.js Dockerfile with default port', () => {
const app = {
runtime: AppRuntime.NODEJS,
runtimeVersion: '20',
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('FROM node:20');
expect(dockerfile).toContain('EXPOSE 3000');
});
it('generates Laravel Dockerfile with artisan migrate', () => {
const app = {
runtime: AppRuntime.LARAVEL,
phpVersion: '8.3',
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('php:8.3');
expect(dockerfile).toContain('artisan migrate');
});
it('generates WordPress Dockerfile with official image', () => {
const app = {
runtime: AppRuntime.WORDPRESS,
runtimeVersion: '6.4',
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('wordpress:6.4');
});
it('generates Django Dockerfile with detected settings module', () => {
const app = {
runtime: AppRuntime.DJANGO,
runtimeVersion: '3.12',
} as Application;
const dockerfile = (service as any).generateDockerfile(app, ['myproject/settings.py']) as string;
expect(dockerfile).toContain('DJANGO_SETTINGS_MODULE=myproject.settings');
expect(dockerfile).toContain('gunicorn');
});
it('generates .NET Dockerfile that restores nested csproj', () => {
const app = {
runtime: AppRuntime.DOTNET,
runtimeVersion: '8.0',
} as Application;
const dockerfile = (service as any).generateDockerfile(app, ['src/App/App.csproj']) as string;
expect(dockerfile).toContain('CSPROJ="src/App/App.csproj"');
expect(dockerfile).toContain('dotnet publish "$CSPROJ"');
});
});
describe('egressProxyEnvFrom', () => {
it('returns secretRef when BUILD_EGRESS_PROXY_SECRET is set', () => {
const config = (service as any).configService as { get: jest.Mock };
config.get.mockImplementation((key: string) => {
if (key === 'build.egressProxySecret') return 'registry-egress-proxy';
return undefined;
});
expect((service as any).egressProxyEnvFrom()).toEqual([
{ secretRef: { name: 'registry-egress-proxy' } },
]);
});
it('returns undefined when egress proxy is disabled', () => {
const config = (service as any).configService as { get: jest.Mock };
config.get.mockImplementation((key: string) => {
if (key === 'build.egressProxySecret') return '';
return undefined;
});
expect((service as any).egressProxyEnvFrom()).toBeUndefined();
expect((service as any).withEgressProxy({ name: 'kaniko' })).toEqual({ name: 'kaniko' });
});
});
});