Skip to content
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
19 changes: 10 additions & 9 deletions apps/server-nestjs/test/argocd.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import type { ConfigType } from '@nestjs/config'
import type { TestingModule } from '@nestjs/testing'
import { faker } from '@faker-js/faker'
import { ConfigModule } from '@nestjs/config'
import { EventEmitter2 } from '@nestjs/event-emitter'
import { Test } from '@nestjs/testing'
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
import { parse } from 'yaml'
import { baseConfigFactory } from '../src/config/base.config'
import { projectSelect } from '../src/modules/argocd/argocd-datastore.service'
import { ArgoCDModule } from '../src/modules/argocd/argocd.module'
import { ArgoCDService } from '../src/modules/argocd/argocd.service'
import { GITLAB_REST_CLIENT, GitlabClientService } from '../src/modules/gitlab/gitlab-client.service'
import { AuthModule } from '../src/modules/infrastructure/auth/auth.module'
import { DatabaseModule } from '../src/modules/infrastructure/database/database.module'
Expand All @@ -19,15 +19,16 @@ import { LoggerModule } from '../src/modules/infrastructure/logger/logger.module
import { PermissionModule } from '../src/modules/infrastructure/permission/permission.module'
import { VaultClientService } from '../src/modules/vault/vault-client.service'
import { getDotenvPaths } from '../src/utils/dotenv.utils'
import { ARGOCD_RECONCILE_TIMEOUT, EXTERNAL_SYNC_TIMEOUT } from './e2e-timeout'

const canRunArgoCDE2E
= Boolean(process.env.E2E)

const describeWithArgoCD = describe.runIf(canRunArgoCDE2E)

describeWithArgoCD('ArgoCDController (e2e)', {}, () => {
describeWithArgoCD('ArgoCDService (e2e)', () => {
let moduleRef: TestingModule
let argocdController: ArgoCDService
let eventEmitter: EventEmitter2
let gitlab: GitlabClientService
let gitlabClient: Gitlab
let vault: VaultClientService
Expand Down Expand Up @@ -60,11 +61,11 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {

await moduleRef.init()

argocdController = moduleRef.get<ArgoCDService>(ArgoCDService)
gitlab = moduleRef.get<GitlabClientService>(GitlabClientService)
gitlabClient = moduleRef.get<Gitlab>(GITLAB_REST_CLIENT)
vault = moduleRef.get<VaultClientService>(VaultClientService)
prisma = moduleRef.get<PrismaService>(PrismaService)
eventEmitter = moduleRef.get<EventEmitter2>(EventEmitter2)
config = moduleRef.get(baseConfigFactory.KEY)

ownerId = faker.string.uuid()
Expand Down Expand Up @@ -212,7 +213,7 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {

vaultProjectValuesPath = `${config.projectsRootDir}/${testProjectId}`
await vault.write({ e2e: true }, vaultProjectValuesPath)
})
}, ARGOCD_RECONCILE_TIMEOUT)

afterAll(async () => {
if (vaultProjectValuesPath) {
Expand Down Expand Up @@ -252,7 +253,7 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {
const staleAction = await gitlab.generateCreateOrUpdateAction(infraProject, 'main', staleFilePath, 'stale: true\n')
await gitlab.maybeCreateCommit(infraProject, 'ci: :robot_face: Seed stale values', staleAction ? [staleAction] : [])

await argocdController.handleUpsert(project)
await eventEmitter.emitAsync('project.upsert', project)
Comment thread
shikanime marked this conversation as resolved.

const expectedFilePath = `${project.name}/${clusterLabel}/${envDevName}/values.yaml`
const file = await gitlabClient.RepositoryFiles.show(infraRepoId, expectedFilePath, 'main')
Expand All @@ -267,7 +268,7 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {

const shouldBeDeleted = await gitlab.getFile(infraProject, staleFilePath, 'main')
expect(shouldBeDeleted).toBeUndefined()
}, 144000)
}, ARGOCD_RECONCILE_TIMEOUT)
Comment thread
shikanime marked this conversation as resolved.

it('should update existing values and delete values of a removed environment', async () => {
const before = await prisma.project.findUniqueOrThrow({
Expand All @@ -294,7 +295,7 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {
select: projectSelect,
})

await argocdController.handleUpsert(after)
await eventEmitter.emitAsync('project.upsert', after)

const updatedDev = await gitlabClient.RepositoryFiles.show(infraRepoId, devFilePath, 'main')
const devRaw = Buffer.from(updatedDev.content, 'base64').toString('utf8')
Expand All @@ -304,5 +305,5 @@ describeWithArgoCD('ArgoCDController (e2e)', {}, () => {

const prodFile = await gitlab.getFile(infraProject, prodFilePath, 'main')
expect(prodFile).toBeUndefined()
}, 72000)
}, EXTERNAL_SYNC_TIMEOUT)
})
7 changes: 7 additions & 0 deletions apps/server-nestjs/test/e2e-timeout.ts
Comment thread
shikanime marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// e2e specs hit real external services; the latency lives in the operation, not the test shape.
// Each timeout names the task it bounds so a reader knows which system and operation it covers.
export const SONARQUBE_PROJECT_TIMEOUT = 30_000 // provision + delete a SonarQube project/user
export const KEYCLOAK_GROUP_SYNC_TIMEOUT = 60_000 // reconcile Keycloak groups/roles
export const EXTERNAL_SYNC_TIMEOUT = 72_000 // sync GitLab groups/members, teardown Nexus/registry
export const ARGOCD_RECONCILE_TIMEOUT = 144_000 // ArgoCD commit + sync to git
export const VAULT_PROVISION_TIMEOUT = 180_000 // provision Vault mounts/policies/approles, zone secrets
48 changes: 32 additions & 16 deletions apps/server-nestjs/test/gitlab.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import type { ConfigType } from '@nestjs/config'
import type { TestingModule } from '@nestjs/testing'
import { faker } from '@faker-js/faker'
import { ConfigModule } from '@nestjs/config'
import { EventEmitter2 } from '@nestjs/event-emitter'
import { Test } from '@nestjs/testing'
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
import z from 'zod'
import { baseConfigFactory } from '../src/config/base.config'
import { GITLAB_REST_CLIENT, GitlabClientService } from '../src/modules/gitlab/gitlab-client.service'
import { projectSelect } from '../src/modules/gitlab/gitlab-datastore.service'
import { GitlabModule } from '../src/modules/gitlab/gitlab.module'
import { GitlabService } from '../src/modules/gitlab/gitlab.service'
import { AuthModule } from '../src/modules/infrastructure/auth/auth.module'
import { DatabaseModule } from '../src/modules/infrastructure/database/database.module'
import { PrismaService } from '../src/modules/infrastructure/database/prisma.service'
Expand All @@ -19,16 +19,17 @@ import { LoggerModule } from '../src/modules/infrastructure/logger/logger.module
import { PermissionModule } from '../src/modules/infrastructure/permission/permission.module'
import { VaultClientService } from '../src/modules/vault/vault-client.service'
import { getDotenvPaths } from '../src/utils/dotenv.utils'
import { EXTERNAL_SYNC_TIMEOUT } from './e2e-timeout'

const canRunGitlabE2E
= Boolean(process.env.E2E)

const describeWithGitLab = describe.runIf(canRunGitlabE2E)

describeWithGitLab('GitlabController (e2e)', {}, () => {
describeWithGitLab('GitlabService (e2e)', () => {
let moduleRef: TestingModule
let gitlabController: GitlabService
let gitlabService: GitlabClientService
let eventEmitter: EventEmitter2
let gitlabClientService: GitlabClientService
let gitlabClient: Gitlab
let vaultService: VaultClientService
let prisma: PrismaService
Expand All @@ -46,11 +47,11 @@ describeWithGitLab('GitlabController (e2e)', {}, () => {

await moduleRef.init()

gitlabController = moduleRef.get<GitlabService>(GitlabService)
gitlabService = moduleRef.get<GitlabClientService>(GitlabClientService)
gitlabClientService = moduleRef.get<GitlabClientService>(GitlabClientService)
gitlabClient = moduleRef.get<Gitlab>(GITLAB_REST_CLIENT)
vaultService = moduleRef.get<VaultClientService>(VaultClientService)
prisma = moduleRef.get<PrismaService>(PrismaService)
eventEmitter = moduleRef.get<EventEmitter2>(EventEmitter2)
config = moduleRef.get(baseConfigFactory.KEY)

ownerId = faker.string.uuid()
Expand Down Expand Up @@ -109,9 +110,9 @@ describeWithGitLab('GitlabController (e2e)', {}, () => {
// Clean GitLab group
if (testProjectSlug && config.projectsRootDir) {
const fullPath = `${config.projectsRootDir}/${testProjectSlug}`
const group = await gitlabService.getGroupByPath(fullPath)
const group = await gitlabClientService.getGroupByPath(fullPath)
if (group) {
await gitlabService.deleteGroup(group).catch(() => {})
await gitlabClientService.deleteGroup(group).catch(() => {})
}
}

Expand Down Expand Up @@ -146,7 +147,7 @@ describeWithGitLab('GitlabController (e2e)', {}, () => {
})

// Act
await gitlabController.handleUpsert(project)
await eventEmitter.emitAsync('project.upsert', project)

// Assert
const groupPath = `${config.projectsRootDir}/${testProjectSlug}`
Expand All @@ -155,19 +156,19 @@ describeWithGitLab('GitlabController (e2e)', {}, () => {
name: z.string(),
full_path: z.string(),
web_url: z.string(),
}).parse(await gitlabService.getGroupByPath(groupPath))
}).parse(await gitlabClientService.getGroupByPath(groupPath))
expect(group.full_path).toBe(groupPath)

// Check membership
const members = await gitlabService.getGroupMembers(group)
const members = await gitlabClientService.getGroupMembers(group)
const isMember = members.some(m => m.id === ownerUser.id)
expect(isMember).toBe(true)

const repoVaultPath = `${config.projectsRootDir}/${testProjectSlug}/app-mirror`
const repoSecret = await vaultService.read(repoVaultPath)
expect(repoSecret?.data?.GIT_OUTPUT_USER).toBeTruthy()
expect(repoSecret?.data?.GIT_OUTPUT_PASSWORD).toBeTruthy()
}, 72000)
}, EXTERNAL_SYNC_TIMEOUT)

describe('project members', () => {
let newUserId: string | undefined
Expand Down Expand Up @@ -219,18 +220,33 @@ describeWithGitLab('GitlabController (e2e)', {}, () => {
select: projectSelect,
})

await gitlabController.handleUpsert(project)
await eventEmitter.emitAsync('project.upsert', project)

const groupPath = `${config.projectsRootDir}/${testProjectSlug}`
const group = z.object({
id: z.number(),
name: z.string(),
web_url: z.string(),
}).parse(await gitlabService.getGroupByPath(groupPath))
}).parse(await gitlabClientService.getGroupByPath(groupPath))

const members = await gitlabService.getGroupMembers(group)
const members = await gitlabClientService.getGroupMembers(group)
const isNewMemberPresent = members.some(m => m.id === newUserGitlabId)
expect(isNewMemberPresent).toBe(true)
}, 72000)
}, EXTERNAL_SYNC_TIMEOUT)
})

it('should remove project group from GitLab on delete', async () => {
const project = await prisma.project.findUniqueOrThrow({
where: { id: testProjectId },
select: projectSelect,
})

const groupPath = `${config.projectsRootDir}/${testProjectSlug}`
expect(await gitlabClientService.getGroupByPath(groupPath)).toBeTruthy()

await eventEmitter.emitAsync('project.delete', project)

const group = await gitlabClientService.getGroupByPath(groupPath)
Comment thread
shikanime marked this conversation as resolved.
expect(group).toBeUndefined()
}, EXTERNAL_SYNC_TIMEOUT)
})
Loading