11import { ContainerRuntimeClient , getContainerRuntimeClient } from "../container-runtime" ;
2+ import { RandomUniquePortGenerator } from "../utils/port-generator" ;
23
34describe ( "Reaper" , { timeout : 120_000 } , ( ) => {
45 let client : ContainerRuntimeClient ;
@@ -7,9 +8,64 @@ describe("Reaper", { timeout: 120_000 }, () => {
78
89 beforeEach ( async ( ) => {
910 vi . resetModules ( ) ;
11+ vi . stubEnv ( "TESTCONTAINERS_RYUK_TEST_LABEL" , "true" ) ;
1012 client = await getContainerRuntimeClient ( ) ;
1113 } ) ;
1214
15+ it ( "should create disabled reaper when TESTCONTAINERS_RYUK_DISABLED=true" , async ( ) => {
16+ vi . stubEnv ( "TESTCONTAINERS_RYUK_DISABLED" , "true" ) ;
17+ vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
18+
19+ const reaper = await getReaper ( ) ;
20+
21+ expect ( ( ) => reaper . addSession ( "test-session" ) ) . not . toThrow ( ) ;
22+ expect ( ( ) => reaper . addComposeProject ( "test-project" ) ) . not . toThrow ( ) ;
23+ } ) ;
24+
25+ it ( "should return cached reaper instance" , async ( ) => {
26+ vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
27+
28+ const reaper = await getReaper ( ) ;
29+ const reaper2 = await getReaper ( ) ;
30+
31+ expect ( reaper2 . containerId ) . toBe ( reaper . containerId ) ;
32+ } ) ;
33+
34+ it ( "should create new reaper container if one is not running" , async ( ) => {
35+ vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
36+ const reaper = await getReaper ( ) ;
37+ vi . resetModules ( ) ;
38+
39+ const reaper2 = await getReaper ( ) ;
40+
41+ expect ( reaper2 . containerId ) . not . toBe ( reaper . containerId ) ;
42+ } ) ;
43+
44+ it ( "should reuse existing reaper container if one is already running" , async ( ) => {
45+ const reaper = await getReaper ( ) ;
46+ vi . resetModules ( ) ;
47+ const reaperContainerInfo = ( await client . container . list ( ) ) . filter ( ( c ) => c . Id === reaper . containerId ) [ 0 ] ;
48+ reaperContainerInfo . Labels [ "TESTCONTAINERS_RYUK_TEST_LABEL" ] = "false" ;
49+ vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ reaperContainerInfo ] ) ;
50+
51+ const reaper2 = await getReaper ( ) ;
52+
53+ expect ( reaper2 . containerId ) . toBe ( reaper . containerId ) ;
54+ } ) ;
55+
56+ it ( "should use custom port when TESTCONTAINERS_RYUK_PORT is set" , async ( ) => {
57+ const customPort = ( await new RandomUniquePortGenerator ( ) . generatePort ( ) ) . toString ( ) ;
58+ vi . stubEnv ( "TESTCONTAINERS_RYUK_PORT" , customPort ) ;
59+ vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
60+
61+ const reaper = await getReaper ( ) ;
62+
63+ const reaperContainer = client . container . getById ( reaper . containerId ) ;
64+ const ports = ( await reaperContainer . inspect ( ) ) . HostConfig . PortBindings ;
65+ const port = ports [ "8080" ] || ports [ "8080/tcp" ] ;
66+ expect ( port [ 0 ] . HostPort ) . toBe ( customPort ) ;
67+ } ) ;
68+
1369 it ( "should create Reaper container without RYUK_VERBOSE env var by default" , async ( ) => {
1470 vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
1571 const reaper = await getReaper ( ) ;
@@ -22,8 +78,8 @@ describe("Reaper", { timeout: 120_000 }, () => {
2278
2379 it ( "should propagate TESTCONTAINERS_RYUK_VERBOSE into Reaper container" , async ( ) => {
2480 vi . stubEnv ( "TESTCONTAINERS_RYUK_VERBOSE" , "true" ) ;
25-
2681 vi . spyOn ( client . container , "list" ) . mockResolvedValue ( [ ] ) ;
82+
2783 const reaper = await getReaper ( ) ;
2884
2985 const reaperContainer = client . container . getById ( reaper . containerId ) ;
0 commit comments