@@ -32,6 +32,102 @@ def test_detect_linux_distro_returns_tuple(self) -> None:
3232 assert isinstance (distro , (str , type (None )))
3333 assert isinstance (version , (str , type (None )))
3434
35+ def test_detect_derivative_distro_pop_os (self , tmp_path : Path ) -> None :
36+ """Detect Pop!_OS as Ubuntu derivative via ID_LIKE."""
37+ os_release = tmp_path / "os-release"
38+ os_release .write_text ('ID=pop\n VERSION_ID="22.04"\n ID_LIKE="ubuntu debian"' )
39+
40+ os_release_data = 'ID=pop\n VERSION_ID="22.04"\n ID_LIKE="ubuntu debian"'
41+
42+ with (
43+ mock .patch ("promptfoo.environment.Path" ) as mock_path_class ,
44+ mock .patch ("builtins.open" , mock .mock_open (read_data = os_release_data )),
45+ ):
46+
47+ def path_side_effect (path_str : str ) -> mock .Mock :
48+ mock_path_obj = mock .Mock ()
49+ if path_str == "/etc/os-release" :
50+ mock_path_obj .exists .return_value = True
51+ mock_path_obj .__truediv__ = lambda self , other : os_release
52+ # Make the mock path object work with open()
53+ return os_release
54+ else :
55+ mock_path_obj .exists .return_value = False
56+ return mock_path_obj
57+
58+ mock_path_class .side_effect = path_side_effect
59+
60+ distro , version = _detect_linux_distro ()
61+ assert distro == "ubuntu" # Should resolve to parent via ID_LIKE
62+ assert version == "22.04"
63+
64+ def test_detect_derivative_distro_raspbian (self , tmp_path : Path ) -> None :
65+ """Detect Raspbian as Debian derivative via ID_LIKE."""
66+ os_release_data = 'ID=raspbian\n VERSION_ID="11"\n ID_LIKE=debian'
67+
68+ with (
69+ mock .patch ("builtins.open" , mock .mock_open (read_data = os_release_data )),
70+ mock .patch ("promptfoo.environment.Path" ) as mock_path_class ,
71+ ):
72+ mock_path_obj = mock .Mock ()
73+ mock_path_obj .exists .return_value = True
74+ mock_path_class .return_value = mock_path_obj
75+
76+ distro , version = _detect_linux_distro ()
77+ assert distro == "debian" # Should resolve to parent via ID_LIKE
78+ assert version == "11"
79+
80+ def test_detect_derivative_distro_linux_mint (self , tmp_path : Path ) -> None :
81+ """Detect Linux Mint as Ubuntu derivative via ID_LIKE."""
82+ os_release_data = 'ID=linuxmint\n VERSION_ID="21"\n ID_LIKE="ubuntu debian"'
83+
84+ with (
85+ mock .patch ("builtins.open" , mock .mock_open (read_data = os_release_data )),
86+ mock .patch ("promptfoo.environment.Path" ) as mock_path_class ,
87+ ):
88+ mock_path_obj = mock .Mock ()
89+ mock_path_obj .exists .return_value = True
90+ mock_path_class .return_value = mock_path_obj
91+
92+ distro , version = _detect_linux_distro ()
93+ assert distro == "ubuntu" # Should resolve to first known parent in ID_LIKE
94+ assert version == "21"
95+
96+ def test_usr_lib_os_release_fallback (self , tmp_path : Path ) -> None :
97+ """Detect distro from /usr/lib/os-release if /etc/os-release missing."""
98+ with mock .patch ("promptfoo.environment.Path" ) as mock_path_class :
99+
100+ def path_exists_side_effect (path_obj : mock .Mock ) -> bool :
101+ # /etc/os-release doesn't exist, /usr/lib/os-release does
102+ if "/etc/os-release" in str (path_obj ):
103+ return False
104+ elif "/usr/lib/os-release" in str (path_obj ):
105+ return True
106+ return False
107+
108+ # Create mock Path objects
109+ etc_path = mock .Mock ()
110+ etc_path .exists .return_value = False
111+ etc_path .__str__ = lambda self : "/etc/os-release"
112+
113+ usr_path = mock .Mock ()
114+ usr_path .exists .return_value = True
115+ usr_path .__str__ = lambda self : "/usr/lib/os-release"
116+
117+ def path_constructor (path_str : str ) -> mock .Mock :
118+ if path_str == "/etc/os-release" :
119+ return etc_path
120+ elif path_str == "/usr/lib/os-release" :
121+ return usr_path
122+ return mock .Mock ()
123+
124+ mock_path_class .side_effect = path_constructor
125+
126+ with mock .patch ("builtins.open" , mock .mock_open (read_data = 'ID=ubuntu\n VERSION_ID="22.04"' )):
127+ distro , version = _detect_linux_distro ()
128+ assert distro == "ubuntu"
129+ assert version == "22.04"
130+
35131
36132class TestCloudProviderDetection :
37133 """Test cloud provider detection."""
0 commit comments