"""Публичный CLI профилей и установка в изолированный корень.""" import os import subprocess import tempfile import unittest from pathlib import Path CLI = Path(__file__).resolve().parents[1] / 'proxy-client/.local/bin/proxy-client' class ProfilesServiceTest(unittest.TestCase): def setUp(self): tmp = tempfile.TemporaryDirectory() self.addCleanup(tmp.cleanup) self.root = Path(tmp.name) self.config = self.root / 'config/proxy-client' self.config.mkdir(parents=True) self.env = dict(os.environ, HOME=str(self.root), XDG_CONFIG_HOME=str(self.root / 'config'), XDG_STATE_HOME=str(self.root / 'state')) def cli(self, *args): return subprocess.run([str(CLI), *map(str, args)], env=self.env, capture_output=True, text=True, timeout=15) def test_unknown_profile_never_falls_back_even_for_stop(self): for command in ('status', 'env', 'run', 'start', 'stop'): result = self.cli('--profile', 'missing', command) self.assertEqual(result.returncode, 1, result.stderr) self.assertIn('неизвестный профиль', result.stderr) result = self.cli('--profile', '../escape', 'stop') self.assertEqual(result.returncode, 1) self.assertIn('имя профиля', result.stderr) def install_args(self): source = self.root / 'source' source.mkdir(exist_ok=True) (source / 'config').write_text('[proxy]\ntype=xray\nname=Service\nno_proxy_extra=\naddress=127.0.0.1\nport=12345\n') (source / 'default.url').write_text( 'vless://11111111-2222-4333-8444-555555555555@cdn.example:443' '?type=xhttp&security=tls&encryption=none&sni=cdn.example&fp=chrome&path=%2Ftest\n') (source / 'default.url').chmod(0o600) xray = self.root / 'xray' xray.write_text('#!/bin/sh\n[ "$1" != version ] || echo "Xray 26.10.10 (fake)"\nexit 0\n') xray.chmod(0o755) return ['service', 'install', '--config-dir', source, '--xray', xray, '--root', self.root / 'stage'] def test_staged_install_is_standalone_and_preserves_config(self): args = self.install_args() result = self.cli(*args) self.assertEqual(result.returncode, 0, result.stderr) stage = self.root / 'stage' unit = (stage / 'etc/systemd/system/proxy-client.service').read_text() self.assertIn('User=proxy-client', unit) self.assertIn('Restart=on-failure', unit) self.assertIn('RuntimeDirectoryMode=0700', unit) self.assertIn('StandardOutput=journal', unit) self.assertNotIn(str(self.root), unit) self.assertTrue((stage / 'usr/local/lib/proxy-client/xray').is_file()) self.assertTrue((stage / 'usr/lib/sysusers.d/proxy-client.conf').is_file()) config = stage / 'etc/proxy-client/config' config.write_text(config.read_text() + '# preserved\n') result = self.cli(*args) self.assertEqual(result.returncode, 0, result.stderr) self.assertIn('# preserved', config.read_text()) self.assertEqual((stage / 'etc/proxy-client/default.url').stat().st_mode & 0o777, 0o640) self.assertIn('journald', result.stdout) def test_install_refuses_foreign_files_before_writing(self): args = self.install_args() target = self.root / 'stage/etc/systemd/system/proxy-client.service' target.parent.mkdir(parents=True) target.write_text('foreign unit') result = self.cli(*args) self.assertEqual(result.returncode, 1) self.assertEqual(target.read_text(), 'foreign unit') self.assertFalse((self.root / 'stage/usr/local/lib/proxy-client/xray').exists()) def test_install_reports_journal_storage_without_changing_policy(self): args = self.install_args() policy = self.root / 'stage/etc/systemd/journald.conf.d/storage.conf' policy.parent.mkdir(parents=True) policy.write_text('[Journal]\nStorage=volatile\n') result = self.cli(*args) self.assertEqual(result.returncode, 0, result.stderr) self.assertIn('Storage=volatile', result.stdout) self.assertIn('не сохраняется', result.stdout) self.assertEqual(policy.read_text(), '[Journal]\nStorage=volatile\n') def test_update_does_not_require_original_home_profile(self): args = self.install_args() first = self.cli(*args) self.assertEqual(0, first.returncode, first.stderr) for path in (self.root / 'source').iterdir(): path.unlink() (self.root / 'source').rmdir() updated = self.cli(*args) self.assertEqual(0, updated.returncode, updated.stderr) def test_unspecified_journal_storage_is_not_guessed(self): result = self.cli(*self.install_args()) self.assertEqual(0, result.returncode, result.stderr) self.assertIn('Storage не задан', result.stdout)