You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
6.9 KiB
Python
217 lines
6.9 KiB
Python
|
3 weeks ago
|
import importlib.machinery
|
||
|
|
import importlib.util
|
||
|
|
import os
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
import unittest
|
||
|
|
from unittest.mock import MagicMock, patch
|
||
|
|
|
||
|
|
# Load the script with hyphens in name as a module
|
||
|
|
test_dir = os.path.dirname(os.path.abspath(__file__))
|
||
|
|
script_path = os.path.abspath(
|
||
|
|
os.path.join(test_dir, "..", "gclient-new-workdir.py"))
|
||
|
|
|
||
|
|
# Ensure depot_tools root is in sys.path so gclient_utils can be imported
|
||
|
|
depot_tools_dir = os.path.dirname(script_path)
|
||
|
|
if depot_tools_dir not in sys.path:
|
||
|
|
sys.path.insert(0, depot_tools_dir)
|
||
|
|
|
||
|
|
loader = importlib.machinery.SourceFileLoader(
|
||
|
|
"gclient_new_workdir",
|
||
|
|
script_path,
|
||
|
|
)
|
||
|
|
spec = importlib.util.spec_from_loader(loader.name, loader)
|
||
|
|
gclient_new_workdir = importlib.util.module_from_spec(spec)
|
||
|
|
loader.exec_module(gclient_new_workdir)
|
||
|
|
|
||
|
|
|
||
|
|
class TestGclientNewWorkdir(unittest.TestCase):
|
||
|
|
|
||
|
|
@patch("subprocess.check_output")
|
||
|
|
@patch("os.stat")
|
||
|
|
@patch("os.access")
|
||
|
|
@patch("subprocess.check_call")
|
||
|
|
@patch("os.makedirs")
|
||
|
|
@patch("sys.exit")
|
||
|
|
def test_abort_on_btrfs_fail(self, mock_exit, mock_makedirs,
|
||
|
|
mock_check_call, mock_os_access, mock_os_stat,
|
||
|
|
mock_check_output):
|
||
|
|
# Setup mocks
|
||
|
|
mock_check_output.return_value = b'btrfs'
|
||
|
|
mock_stat_res = MagicMock()
|
||
|
|
mock_stat_res.st_ino = 256
|
||
|
|
mock_os_stat.return_value = mock_stat_res
|
||
|
|
|
||
|
|
def mock_cc(args, **kwargs):
|
||
|
|
_ = kwargs
|
||
|
|
if args[2] == 'snapshot':
|
||
|
|
raise OSError("Failed")
|
||
|
|
|
||
|
|
mock_check_call.side_effect = mock_cc
|
||
|
|
|
||
|
|
# Make mock_exit raise SystemExit to stop execution
|
||
|
|
mock_exit.side_effect = SystemExit(1)
|
||
|
|
|
||
|
|
# Mock os.access to return True for diagnostics
|
||
|
|
mock_os_access.return_value = True
|
||
|
|
|
||
|
|
# Mock parse_options
|
||
|
|
mock_args = MagicMock()
|
||
|
|
mock_args.repository = "repo"
|
||
|
|
mock_args.new_workdir = "dest"
|
||
|
|
|
||
|
|
with patch.object(gclient_new_workdir,
|
||
|
|
"parse_options",
|
||
|
|
return_value=mock_args):
|
||
|
|
try:
|
||
|
|
gclient_new_workdir.main()
|
||
|
|
except SystemExit:
|
||
|
|
pass # Expected
|
||
|
|
|
||
|
|
# Assertions
|
||
|
|
mock_exit.assert_called_with(1)
|
||
|
|
mock_makedirs.assert_not_called()
|
||
|
|
|
||
|
|
@patch("subprocess.check_output")
|
||
|
|
@patch("os.stat")
|
||
|
|
@patch("os.access")
|
||
|
|
@patch("os.makedirs")
|
||
|
|
@patch("sys.exit")
|
||
|
|
@patch.object(gclient_new_workdir, "support_copy_on_write")
|
||
|
|
def test_fallback_on_non_subvolume(self, mock_support_cow, mock_exit,
|
||
|
|
mock_makedirs, mock_os_access,
|
||
|
|
mock_os_stat, mock_check_output):
|
||
|
|
# Setup mocks
|
||
|
|
mock_check_output.return_value = b'btrfs'
|
||
|
|
mock_stat_res = MagicMock()
|
||
|
|
mock_stat_res.st_ino = 123 # Not subvolume!
|
||
|
|
mock_os_stat.return_value = mock_stat_res
|
||
|
|
|
||
|
|
# Mock os.access to return True for diagnostics
|
||
|
|
mock_os_access.return_value = True
|
||
|
|
|
||
|
|
# Mock support_copy_on_write to stop execution after os.makedirs
|
||
|
|
mock_support_cow.side_effect = SystemExit(0)
|
||
|
|
|
||
|
|
# Mock parse_options
|
||
|
|
mock_args = MagicMock()
|
||
|
|
mock_args.repository = "repo"
|
||
|
|
mock_args.new_workdir = "dest"
|
||
|
|
|
||
|
|
with patch.object(gclient_new_workdir,
|
||
|
|
"parse_options",
|
||
|
|
return_value=mock_args):
|
||
|
|
try:
|
||
|
|
gclient_new_workdir.main()
|
||
|
|
except SystemExit:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Assertions
|
||
|
|
mock_exit.assert_not_called()
|
||
|
|
# It should proceed to os.makedirs with resolved path
|
||
|
|
mock_makedirs.assert_called_with(os.path.realpath("dest"))
|
||
|
|
|
||
|
|
@patch("subprocess.check_output")
|
||
|
|
@patch("os.stat")
|
||
|
|
@patch("os.access")
|
||
|
|
@patch("subprocess.check_call")
|
||
|
|
@patch("os.makedirs")
|
||
|
|
@patch("sys.exit")
|
||
|
|
def test_diagnostics_repo_not_readable(self, mock_exit, mock_makedirs,
|
||
|
|
mock_check_call, mock_os_access,
|
||
|
|
mock_os_stat, mock_check_output):
|
||
|
|
# Setup mocks
|
||
|
|
mock_check_output.return_value = b'btrfs'
|
||
|
|
mock_stat_res = MagicMock()
|
||
|
|
mock_stat_res.st_ino = 256
|
||
|
|
mock_os_stat.return_value = mock_stat_res
|
||
|
|
|
||
|
|
def mock_cc(args, **kwargs):
|
||
|
|
_ = kwargs
|
||
|
|
if args[2] == 'snapshot':
|
||
|
|
raise OSError("Failed")
|
||
|
|
|
||
|
|
mock_check_call.side_effect = mock_cc
|
||
|
|
|
||
|
|
# Make mock_exit raise SystemExit to stop execution
|
||
|
|
mock_exit.side_effect = SystemExit(1)
|
||
|
|
|
||
|
|
# Mock os.access: False for repo (not readable)
|
||
|
|
def side_effect(path, mode):
|
||
|
|
if path == "repo" and mode == os.R_OK:
|
||
|
|
return False
|
||
|
|
return True
|
||
|
|
|
||
|
|
mock_os_access.side_effect = side_effect
|
||
|
|
|
||
|
|
# Mock parse_options
|
||
|
|
mock_args = MagicMock()
|
||
|
|
mock_args.repository = "repo"
|
||
|
|
mock_args.new_workdir = "dest"
|
||
|
|
|
||
|
|
with patch.object(gclient_new_workdir,
|
||
|
|
"parse_options",
|
||
|
|
return_value=mock_args):
|
||
|
|
try:
|
||
|
|
gclient_new_workdir.main()
|
||
|
|
except SystemExit:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Assertions
|
||
|
|
mock_exit.assert_called_with(1)
|
||
|
|
mock_makedirs.assert_not_called()
|
||
|
|
|
||
|
|
@patch("subprocess.check_output")
|
||
|
|
@patch("os.stat")
|
||
|
|
@patch("os.access")
|
||
|
|
@patch("subprocess.check_call")
|
||
|
|
@patch("os.makedirs")
|
||
|
|
@patch("sys.exit")
|
||
|
|
def test_diagnostics_dest_not_writable(self, mock_exit, mock_makedirs,
|
||
|
|
mock_check_call, mock_os_access,
|
||
|
|
mock_os_stat, mock_check_output):
|
||
|
|
# Setup mocks
|
||
|
|
mock_check_output.return_value = b'btrfs'
|
||
|
|
mock_stat_res = MagicMock()
|
||
|
|
mock_stat_res.st_ino = 256
|
||
|
|
mock_os_stat.return_value = mock_stat_res
|
||
|
|
|
||
|
|
def mock_cc(args, **kwargs):
|
||
|
|
_ = kwargs
|
||
|
|
if args[2] == 'snapshot':
|
||
|
|
raise OSError("Failed")
|
||
|
|
|
||
|
|
mock_check_call.side_effect = mock_cc
|
||
|
|
|
||
|
|
# Make mock_exit raise SystemExit to stop execution
|
||
|
|
mock_exit.side_effect = SystemExit(1)
|
||
|
|
|
||
|
|
# Mock os.access: False for dest parent (not writable)
|
||
|
|
def side_effect(path, mode):
|
||
|
|
if path == "dir" and mode == os.W_OK:
|
||
|
|
return False
|
||
|
|
return True
|
||
|
|
|
||
|
|
mock_os_access.side_effect = side_effect
|
||
|
|
|
||
|
|
# Mock parse_options
|
||
|
|
mock_args = MagicMock()
|
||
|
|
mock_args.repository = "repo"
|
||
|
|
mock_args.new_workdir = "dir/dest"
|
||
|
|
|
||
|
|
with patch.object(gclient_new_workdir,
|
||
|
|
"parse_options",
|
||
|
|
return_value=mock_args):
|
||
|
|
try:
|
||
|
|
gclient_new_workdir.main()
|
||
|
|
except SystemExit:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Assertions
|
||
|
|
mock_exit.assert_called_with(1)
|
||
|
|
mock_makedirs.assert_not_called()
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|