@@ -3,10 +3,10 @@ import { StartedRedisContainer } from "@testcontainers/redis";
33import { PrismaClient } from "@trigger.dev/database" ;
44import { RedisOptions } from "ioredis" ;
55import { Network , type StartedNetwork } from "testcontainers" ;
6- import { test } from "vitest" ;
6+ import { TaskContext , test } from "vitest" ;
77import { createElectricContainer , createPostgresContainer , createRedisContainer } from "./utils" ;
88import { x } from "tinyexec" ;
9- import { isCI } from "std-env" ;
9+ import { isCI , env } from "std-env" ;
1010
1111export { assertNonNullable } from "./utils" ;
1212export { StartedRedisContainer } ;
@@ -41,7 +41,11 @@ let activeCleanups = 0;
4141 * @param resource - The resource that is being cleaned up.
4242 * @param promise - The cleanup promise to await..
4343 */
44- async function logCleanup ( resource : string , promise : Promise < unknown > ) {
44+ async function logCleanup (
45+ resource : string ,
46+ promise : Promise < unknown > ,
47+ metadata : Record < string , unknown > = { }
48+ ) {
4549 const start = new Date ( ) ;
4650 const order = cleanupOrder ++ ;
4751 const activeAtStart = ++ activeCleanups ;
@@ -66,7 +70,7 @@ async function logCleanup(resource: string, promise: Promise<unknown>) {
6670 let dockerDiagnostics : DockerDiagnostics = { } ;
6771
6872 // Only run docker diagnostics if there was an error or cleanup took longer than 5s
69- if ( error || durationMs > 5000 ) {
73+ if ( error || durationMs > 5000 || env . DOCKER_DIAGNOSTICS ) {
7074 try {
7175 dockerDiagnostics = await getDockerDiagnostics ( ) ;
7276 } catch ( diagnosticErr ) {
@@ -85,6 +89,7 @@ async function logCleanup(resource: string, promise: Promise<unknown>) {
8589 error,
8690 activeAtStart,
8791 activeAtEnd,
92+ ...metadata ,
8893 ...dockerDiagnostics ,
8994 } )
9095 ) ;
@@ -121,7 +126,7 @@ async function getDockerContainers(): Promise<string[]> {
121126type DockerResource = { id : string ; name : string } ;
122127
123128type DockerNetworkAttachment = DockerResource & {
124- containers : DockerResource [ ] ;
129+ containers : string [ ] ;
125130} ;
126131
127132export async function getDockerNetworkAttachments ( ) : Promise < DockerNetworkAttachment [ ] > {
@@ -153,15 +158,11 @@ export async function getDockerNetworkAttachments(): Promise<DockerNetworkAttach
153158 "network" ,
154159 "inspect" ,
155160 "--format" ,
156- " {{range $k, $v := .Containers}}{{$k}} {{$v.Name}}\n{{end}}" ,
161+ ' {{range $k, $v := .Containers}}{{$k | printf "%.12s" }} {{$v.Name}}\n{{end}}' ,
157162 id ,
158163 ] ) ;
159- const lines = stringToLines ( containersResult . stdout ) ;
160164
161- const containers : DockerResource [ ] = lines . map ( ( line ) => {
162- const [ id , name ] = lineToWords ( line ) ;
163- return { id, name } ;
164- } ) ;
165+ const containers = stringToLines ( containersResult . stdout ) ;
165166
166167 attachments . push ( { id, name, containers } ) ;
167168 } catch ( err ) {
@@ -204,11 +205,11 @@ export async function getDockerContainerNetworks(): Promise<DockerContainerNetwo
204205 const inspectResult = await x ( "docker" , [
205206 "inspect" ,
206207 "--format" ,
207- " {{ range $k, $v := .NetworkSettings.Networks }}{{ $k }} {{ end }}" ,
208+ ' {{ range $k, $v := .NetworkSettings.Networks }}{{ $k | printf "%.12s" }} {{ $v.Name }}\n{{ end }}' ,
208209 id ,
209210 ] ) ;
210211
211- const networks = inspectResult . stdout . trim ( ) . split ( / \s + / ) ;
212+ const networks = stringToLines ( inspectResult . stdout ) ;
212213
213214 results . push ( { id, name, networks } ) ;
214215 } catch ( err ) {
@@ -243,34 +244,68 @@ async function getDockerDiagnostics(): Promise<DockerDiagnostics> {
243244 } ;
244245}
245246
246- const network = async ( { } , use : Use < StartedNetwork > ) => {
247+ const network = async ( { task } : TaskContext , use : Use < StartedNetwork > ) => {
248+ const testName = task . name ;
249+
250+ logSetup ( "network: starting" , { testName } ) ;
251+
252+ const start = Date . now ( ) ;
247253 const network = await new Network ( ) . start ( ) ;
254+ const startDurationMs = Date . now ( ) - start ;
255+
256+ const metadata = {
257+ testName,
258+ networkId : network . getId ( ) . slice ( 0 , 12 ) ,
259+ networkName : network . getName ( ) ,
260+ startDurationMs,
261+ } ;
262+
263+ logSetup ( "network: started" , metadata ) ;
264+
248265 try {
249266 await use ( network ) ;
250267 } finally {
251268 // Make sure to stop the network after use
252- await logCleanup ( "network" , network . stop ( ) ) ;
269+ await logCleanup ( "network" , network . stop ( ) , metadata ) ;
253270 }
254271} ;
255272
256273const postgresContainer = async (
257- { network } : { network : StartedNetwork } ,
274+ { network, task } : { network : StartedNetwork } & TaskContext ,
258275 use : Use < StartedPostgreSqlContainer >
259276) => {
277+ const testName = task . name ;
278+
279+ logSetup ( "postgresContainer: starting" , { testName } ) ;
280+
281+ const start = Date . now ( ) ;
260282 const { container } = await createPostgresContainer ( network ) ;
283+ const startDurationMs = Date . now ( ) - start ;
284+
285+ const metadata = {
286+ testName,
287+ containerId : container . getId ( ) . slice ( 0 , 12 ) ,
288+ containerName : container . getName ( ) ,
289+ containerNetworkNames : container . getNetworkNames ( ) ,
290+ startDurationMs,
291+ } ;
292+
293+ logSetup ( "postgresContainer: started" , metadata ) ;
294+
261295 try {
262296 await use ( container ) ;
263297 } finally {
264298 // WARNING: Testcontainers by default will not wait until the container has stopped. It will simply issue the stop command and return immediately.
265299 // If you need to wait for the container to be stopped, you can provide a timeout. The unit of timeout option here is second
266- await logCleanup ( "postgresContainer" , container . stop ( { timeout : 30 } ) ) ;
300+ await logCleanup ( "postgresContainer" , container . stop ( { timeout : 30 } ) , metadata ) ;
267301 }
268302} ;
269303
270304const prisma = async (
271- { postgresContainer } : { postgresContainer : StartedPostgreSqlContainer } ,
305+ { postgresContainer, task } : { postgresContainer : StartedPostgreSqlContainer } & TaskContext ,
272306 use : Use < PrismaClient >
273307) => {
308+ const testName = task . name ;
274309 const url = postgresContainer . getConnectionUri ( ) ;
275310
276311 console . log ( "Initializing Prisma with URL:" , url ) ;
@@ -285,26 +320,65 @@ const prisma = async (
285320 try {
286321 await use ( prisma ) ;
287322 } finally {
288- await logCleanup ( "prisma" , prisma . $disconnect ( ) ) ;
323+ await logCleanup ( "prisma" , prisma . $disconnect ( ) , { testName } ) ;
289324 }
290325} ;
291326
292327export const postgresTest = test . extend < PostgresContext > ( { network, postgresContainer, prisma } ) ;
293328
329+ let setupOrder = 0 ;
330+
331+ function logSetup ( resource : string , metadata : Record < string , unknown > ) {
332+ const order = setupOrder ++ ;
333+
334+ if ( ! isCI ) {
335+ return ;
336+ }
337+
338+ console . log (
339+ JSON . stringify ( {
340+ type : "setup" ,
341+ order,
342+ resource,
343+ timestamp : new Date ( ) . toISOString ( ) ,
344+ ...metadata ,
345+ } )
346+ ) ;
347+ }
348+
294349const redisContainer = async (
295- { network } : { network : StartedNetwork } ,
350+ { network, task } : { network : StartedNetwork } & TaskContext ,
296351 use : Use < StartedRedisContainer >
297352) => {
353+ const testName = task . name ;
354+
355+ logSetup ( "redisContainer: starting" , { testName } ) ;
356+
357+ const start = Date . now ( ) ;
358+
298359 const { container } = await createRedisContainer ( {
299360 port : 6379 ,
300361 network,
301362 } ) ;
363+
364+ const startDurationMs = Date . now ( ) - start ;
365+
366+ const metadata = {
367+ containerName : container . getName ( ) ,
368+ containerId : container . getId ( ) . slice ( 0 , 12 ) ,
369+ containerNetworkNames : container . getNetworkNames ( ) ,
370+ startDurationMs,
371+ testName,
372+ } ;
373+
374+ logSetup ( "redisContainer: started" , metadata ) ;
375+
302376 try {
303377 await use ( container ) ;
304378 } finally {
305379 // WARNING: Testcontainers by default will not wait until the container has stopped. It will simply issue the stop command and return immediately.
306380 // If you need to wait for the container to be stopped, you can provide a timeout. The unit of timeout option here is second
307- await logCleanup ( "redisContainer" , container . stop ( { timeout : 30 } ) ) ;
381+ await logCleanup ( "redisContainer" , container . stop ( { timeout : 30 } ) , metadata ) ;
308382 }
309383} ;
310384
@@ -347,16 +421,33 @@ const electricOrigin = async (
347421 {
348422 postgresContainer,
349423 network,
350- } : { postgresContainer : StartedPostgreSqlContainer ; network : StartedNetwork } ,
424+ task,
425+ } : { postgresContainer : StartedPostgreSqlContainer ; network : StartedNetwork } & TaskContext ,
351426 use : Use < string >
352427) => {
428+ const testName = task . name ;
429+
430+ logSetup ( "electricOrigin: starting" , { testName } ) ;
431+
432+ const start = Date . now ( ) ;
353433 const { origin, container } = await createElectricContainer ( postgresContainer , network ) ;
434+ const startDurationMs = Date . now ( ) - start ;
435+
436+ const metadata = {
437+ testName,
438+ containerId : container . getId ( ) . slice ( 0 , 12 ) ,
439+ containerName : container . getName ( ) ,
440+ startDurationMs,
441+ } ;
442+
443+ logSetup ( "electricOrigin: started" , metadata ) ;
444+
354445 try {
355446 await use ( origin ) ;
356447 } finally {
357448 // WARNING: Testcontainers by default will not wait until the container has stopped. It will simply issue the stop command and return immediately.
358449 // If you need to wait for the container to be stopped, you can provide a timeout. The unit of timeout option here is second
359- await logCleanup ( "electricContainer" , container . stop ( { timeout : 30 } ) ) ;
450+ await logCleanup ( "electricContainer" , container . stop ( { timeout : 30 } ) , metadata ) ;
360451 }
361452} ;
362453
0 commit comments