diff --git a/packages/quality/environments/containers/services/proxy.ts b/packages/quality/environments/containers/services/proxy.ts index 74968ead9c7..c27d2f87034 100644 --- a/packages/quality/environments/containers/services/proxy.ts +++ b/packages/quality/environments/containers/services/proxy.ts @@ -11,20 +11,17 @@ import type { import { join } from 'path'; import { GenericContainer, Wait } from 'testcontainers'; -import { createSilentLogConsumer } from '../helpers/utils'; import { TEST_CONTAINER_IMAGES } from '../test-containers'; import type { HelperContext, Service, ServiceResult } from './types'; const HOSTNAME = 'proxyserver'; const PORT = 1080; -const MOCKSERVER_WAIT_STRATEGY = Wait.forAll([ - Wait.forLogMessage(`INFO ${PORT} started on port: ${PORT}`), - Wait.forHttp('/mockserver/status', PORT) - .withMethod('PUT') - .forStatusCode(200) - .withStartupTimeout(60_000) - .withReadTimeout(250), -]); +// The status check proves readiness without following MockServer logs. +const MOCKSERVER_WAIT_STRATEGY = Wait.forHttp('/mockserver/status', PORT) + .withMethod('PUT') + .forStatusCode(200) + .withStartupTimeout(60_000) + .withReadTimeout(250); export interface ProxyMeta { host: string; @@ -49,36 +46,29 @@ export const proxy: Service = { }, async start(network, projectName): Promise { - const { consumer, throwWithLogs } = createSilentLogConsumer(); + const container = await new GenericContainer(TEST_CONTAINER_IMAGES.mockserver) + .withNetwork(network) + .withNetworkAliases(HOSTNAME) + .withExposedPorts(PORT) + // Keep MockServer heap predictable under parallel container load. + .withEnvironment({ JVM_OPTIONS: '-Xmx512m -Xms512m' }) + .withWaitStrategy(MOCKSERVER_WAIT_STRATEGY) + .withLabels({ + 'com.docker.compose.project': projectName, + 'com.docker.compose.service': HOSTNAME, + }) + .withName(`${projectName}-${HOSTNAME}`) + .withReuse() + .start(); - try { - const container = await new GenericContainer(TEST_CONTAINER_IMAGES.mockserver) - .withNetwork(network) - .withNetworkAliases(HOSTNAME) - .withExposedPorts(PORT) - // Keep MockServer heap predictable under parallel container load. - .withEnvironment({ JVM_OPTIONS: '-Xmx512m -Xms512m' }) - .withWaitStrategy(MOCKSERVER_WAIT_STRATEGY) - .withLabels({ - 'com.docker.compose.project': projectName, - 'com.docker.compose.service': HOSTNAME, - }) - .withName(`${projectName}-${HOSTNAME}`) - .withReuse() - .withLogConsumer(consumer) - .start(); - - return { - container, - meta: { - host: HOSTNAME, - port: PORT, - internalUrl: `http://${HOSTNAME}:${PORT}`, - }, - }; - } catch (error) { - return throwWithLogs(error); - } + return { + container, + meta: { + host: HOSTNAME, + port: PORT, + internalUrl: `http://${HOSTNAME}:${PORT}`, + }, + }; }, env(result: ProxyResult, external?: boolean): Record { diff --git a/packages/quality/environments/containers/tests/proxy.test.ts b/packages/quality/environments/containers/tests/proxy.test.ts new file mode 100644 index 00000000000..f632cb05baf --- /dev/null +++ b/packages/quality/environments/containers/tests/proxy.test.ts @@ -0,0 +1,30 @@ +import { + GenericContainer, + Wait, + type StartedNetwork, + type StartedTestContainer, +} from 'testcontainers'; +import { afterEach, expect, test, vi } from 'vitest'; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +test('waits for MockServer status without a followed log stream', async () => { + const httpWait = vi.spyOn(Wait, 'forHttp'); + const logWait = vi.spyOn(Wait, 'forLogMessage'); + const withWaitStrategy = vi.spyOn(GenericContainer.prototype, 'withWaitStrategy'); + const withLogConsumer = vi.spyOn(GenericContainer.prototype, 'withLogConsumer'); + vi.spyOn(GenericContainer.prototype, 'start').mockResolvedValue({} as StartedTestContainer); + const { proxy } = await import('../services/proxy.js'); + const network = { getName: () => 'test-network' } as StartedNetwork; + + const result = await proxy.start(network, 'test-project'); + + expect(result.meta.internalUrl).toBe('http://proxyserver:1080'); + expect(httpWait).toHaveBeenCalledWith('/mockserver/status', 1080); + // DEVP-1269: Log waits and consumers leave followed Docker streams attached to the worker. + expect(logWait).not.toHaveBeenCalled(); + expect(withWaitStrategy).toHaveBeenCalledWith(httpWait.mock.results[0].value); + expect(withLogConsumer).not.toHaveBeenCalled(); +});