55import re
66import shlex
77import subprocess
8+ import sys
89import tempfile
910import unittest
1011
@@ -79,6 +80,41 @@ def _docker_compose_down(self):
7980 self ._docker_is_up = False
8081 return run
8182
83+ def _docker_fix_permissions_for_cleanup (self , service , path ):
84+ """Fix permissions on container-created files to allow temp directory cleanup.
85+
86+ Docker containers may create files with different ownership that the
87+ test process cannot delete. This chmod's them before stopping containers.
88+ """
89+ try :
90+ self ._docker_compose ('exec' , '-T' , service , 'chmod' , '-R' , '777' , path )
91+ except Exception :
92+ pass # Best effort - container might not be running
93+
94+ def _print_container_versions (self ):
95+ """Print the versions of the containers being used for debugging.
96+
97+ Uses sys.stderr to ensure output is visible even when pytest
98+ captures stdout.
99+ """
100+ print ('\n === Container Versions ===' , file = sys .stderr )
101+ for service , container_name in self .CONTAINERS .items ():
102+ try :
103+ # Get the image name and digest
104+ result = subprocess .run (
105+ ['docker' , 'inspect' , '--format' ,
106+ '{{.Config.Image}} ({{.Image}})' , container_name ],
107+ capture_output = True ,
108+ text = True ,
109+ )
110+ if result .returncode == 0 :
111+ print (f'{ service } : { result .stdout .strip ()} ' , file = sys .stderr )
112+ else :
113+ print (f'{ service } : unable to get version' , file = sys .stderr )
114+ except Exception as e :
115+ print (f'{ service } : error getting version - { e } ' , file = sys .stderr )
116+ print ('=== End Container Versions ===\n ' , file = sys .stderr )
117+
82118 def setUp (self ):
83119 self .CONTAINERS = {}
84120 self ._tmpdir = tempfile .TemporaryDirectory (
@@ -88,6 +124,11 @@ def setUp(self):
88124
89125 def tearDown (self ):
90126 if hasattr (self , '_docker_is_up' ) and self ._docker_is_up :
127+ # Fix permissions on files created by containers before stopping them
128+ # This allows the temp directory cleanup to work properly
129+ self ._docker_fix_permissions_for_cleanup ('appdaemon' , '/conf' )
130+ self ._docker_fix_permissions_for_cleanup ('homeassistant' , '/config' )
131+
91132 # Stop and destroy containers
92133 self ._docker_compose_down ()
93134
@@ -131,6 +172,9 @@ async def get_context(self):
131172 # Start containers
132173 self ._docker_compose_up ()
133174
175+ # Print container versions for debugging
176+ self ._print_container_versions ()
177+
134178 # Grab logs from AppDaemon
135179 appdaemon = AppDaemonDockerLogReader (
136180 container_name = self .CONTAINERS ['appdaemon' ],
0 commit comments