summaryrefslogtreecommitdiffstats
path: root/tests/test_subcmds_sync.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_subcmds_sync.py')
-rw-r--r--tests/test_subcmds_sync.py167
1 files changed, 151 insertions, 16 deletions
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py
index e7e8013e0..32ff3cdd1 100644
--- a/tests/test_subcmds_sync.py
+++ b/tests/test_subcmds_sync.py
@@ -501,27 +501,116 @@ def test_cli_smart_sync(
501 501
502 502
503@pytest.mark.parametrize( 503@pytest.mark.parametrize(
504 "argv, sync_smartsync_manifest, expected_exception", 504 "argv, user_pref, sync_smartsync_manifest, expected_smart_sync, "
505 "expected_implicit",
505 [ 506 [
506 (["-u", "user", "-p", "pass"], False, sync.SmartSyncError), 507 # sync.smartsync=false: never smart sync unless -s/-t is given.
507 (["-u", "user", "-p", "pass"], True, None), 508 ([], False, True, False, False),
508 (["-s", "-u", "user", "-p", "pass"], False, None), 509 ([], False, False, False, False),
509 (["-t", "tag", "-u", "user", "-p", "pass"], False, None), 510 (["-s"], False, True, True, False),
511 (["--smart-sync"], False, False, True, False),
512 (["-t", "tag123"], False, True, False, False),
513 (["--nmu"], False, True, False, False),
514 # sync.smartsync=true: like -s, counted as explicit, not implicit.
515 ([], True, False, True, False),
516 ([], True, True, True, False),
517 (["--nmu"], True, False, True, False),
518 (["--no-smart-sync"], True, True, False, False),
519 (["-t", "tag123"], True, False, False, False),
520 (["-m", "other.xml"], True, False, False, False),
521 (["-l"], True, False, False, False),
522 (["--superproject-revision=abc"], True, False, False, False),
523 # sync.smartsync unset: manifest default applies as before.
524 ([], None, True, True, True),
525 ([], None, False, False, False),
526 ],
527)
528def test_user_config_smart_sync(
529 argv: List[str],
530 user_pref: Optional[bool],
531 sync_smartsync_manifest: bool,
532 expected_smart_sync: bool,
533 expected_implicit: bool,
534) -> None:
535 """Tests the sync.smartsync user setting against CLI and manifest."""
536 manifest = mock.MagicMock()
537 manifest.default.sync_smartsync = sync_smartsync_manifest
538
539 user_cfg = mock.MagicMock()
540 user_cfg.GetBoolean.return_value = user_pref
541
542 cmd = sync.Sync(manifest=manifest)
543 opts, args = cmd.OptionParser.parse_args(argv)
544 cmd.ValidateOptions(opts, args)
545 with mock.patch.object(sync.RepoConfig, "ForUser", return_value=user_cfg):
546 implicit = cmd._ResolveSmartSyncOption(opts, manifest)
547 user_cfg.GetBoolean.assert_called_once_with("sync.smartsync")
548 assert opts.smart_sync == expected_smart_sync
549 assert implicit == expected_implicit
550
551
552@pytest.mark.parametrize(
553 "value, expected_smart_sync",
554 [("true", True), ("false", False), ("yes", True), ("no", False)],
555)
556def test_user_config_smart_sync_from_file(
557 monkeypatch: pytest.MonkeyPatch,
558 tmp_home_dir: Path,
559 value: str,
560 expected_smart_sync: bool,
561) -> None:
562 """Tests that sync.smartsync is read from ~/.repoconfig/config."""
563 # ForUser() caches its instance process-wide; make it pick up this HOME.
564 monkeypatch.setattr(sync.RepoConfig, "_ForUser", None)
565 monkeypatch.delenv("REPO_CONFIG_DIR", raising=False)
566 cfg_dir = tmp_home_dir / ".repoconfig"
567 cfg_dir.mkdir()
568 (cfg_dir / "config").write_text(f"[sync]\n\tsmartsync = {value}\n")
569
570 manifest = mock.MagicMock()
571 # Set the manifest default to the opposite so we know the user config won.
572 manifest.default.sync_smartsync = not expected_smart_sync
573
574 cmd = sync.Sync(manifest=manifest)
575 opts, args = cmd.OptionParser.parse_args([])
576 cmd.ValidateOptions(opts, args)
577 assert cmd._ResolveSmartSyncOption(opts, manifest) is False
578 assert opts.smart_sync == expected_smart_sync
579
580
581@pytest.mark.parametrize(
582 "argv, user_pref, sync_smartsync_manifest, expected_exception",
583 [
584 (["-u", "user", "-p", "pass"], None, False, sync.SmartSyncError),
585 (["-u", "user", "-p", "pass"], None, True, None),
586 (["-s", "-u", "user", "-p", "pass"], None, False, None),
587 (["-t", "tag", "-u", "user", "-p", "pass"], None, False, None),
510 ( 588 (
511 ["--no-smart-sync", "-u", "user", "-p", "pass"], 589 ["--no-smart-sync", "-u", "user", "-p", "pass"],
590 None,
512 True, 591 True,
513 sync.SmartSyncError, 592 sync.SmartSyncError,
514 ), 593 ),
515 (["-l", "-u", "user", "-p", "pass"], True, sync.SmartSyncError), 594 (["-l", "-u", "user", "-p", "pass"], None, True, sync.SmartSyncError),
516 (["--nmu", "-u", "user", "-p", "pass"], True, None), 595 (["--nmu", "-u", "user", "-p", "pass"], None, True, None),
517 (["--nmu", "-u", "user", "-p", "pass"], False, sync.SmartSyncError), 596 (
518 (["-s", "-l", "-u", "user", "-p", "pass"], True, None), 597 ["--nmu", "-u", "user", "-p", "pass"],
519 (["-u", "user"], False, SystemExit), 598 None,
520 (["-p", "pass"], False, SystemExit), 599 False,
600 sync.SmartSyncError,
601 ),
602 (["-s", "-l", "-u", "user", "-p", "pass"], None, True, None),
603 (["-u", "user"], None, False, SystemExit),
604 (["-p", "pass"], None, False, SystemExit),
605 # -u/-p are accepted when smart sync comes from sync.smartsync=true...
606 (["-u", "user", "-p", "pass"], True, False, None),
607 # ...and rejected when sync.smartsync=false drops the manifest default.
608 (["-u", "user", "-p", "pass"], False, True, sync.SmartSyncError),
521 ], 609 ],
522) 610)
523def test_cli_manifest_server_credentials( 611def test_cli_manifest_server_credentials(
524 argv: List[str], 612 argv: List[str],
613 user_pref: Optional[bool],
525 sync_smartsync_manifest: bool, 614 sync_smartsync_manifest: bool,
526 expected_exception: Optional[Type[BaseException]], 615 expected_exception: Optional[Type[BaseException]],
527) -> None: 616) -> None:
@@ -529,15 +618,19 @@ def test_cli_manifest_server_credentials(
529 manifest = mock.MagicMock() 618 manifest = mock.MagicMock()
530 manifest.default.sync_smartsync = sync_smartsync_manifest 619 manifest.default.sync_smartsync = sync_smartsync_manifest
531 620
621 user_cfg = mock.MagicMock()
622 user_cfg.GetBoolean.return_value = user_pref
623
532 cmd = sync.Sync(manifest=manifest) 624 cmd = sync.Sync(manifest=manifest)
533 opts, args = cmd.OptionParser.parse_args(argv) 625 opts, args = cmd.OptionParser.parse_args(argv)
534 if expected_exception: 626 with mock.patch.object(sync.RepoConfig, "ForUser", return_value=user_cfg):
535 with pytest.raises(expected_exception): 627 if expected_exception:
628 with pytest.raises(expected_exception):
629 cmd.ValidateOptions(opts, args)
630 cmd._ResolveSmartSyncOption(opts, manifest)
631 else:
536 cmd.ValidateOptions(opts, args) 632 cmd.ValidateOptions(opts, args)
537 cmd._ResolveSmartSyncOption(opts, manifest) 633 cmd._ResolveSmartSyncOption(opts, manifest)
538 else:
539 cmd.ValidateOptions(opts, args)
540 cmd._ResolveSmartSyncOption(opts, manifest)
541 634
542 635
543class LocalSyncState(unittest.TestCase): 636class LocalSyncState(unittest.TestCase):
@@ -1699,6 +1792,48 @@ class SyncCommand(unittest.TestCase):
1699 mock_setup.assert_called_once() 1792 mock_setup.assert_called_once()
1700 self.assertFalse(mock_setup.call_args.kwargs.get("best_effort")) 1793 self.assertFalse(mock_setup.call_args.kwargs.get("best_effort"))
1701 1794
1795 def test_user_config_smart_sync_disabled(self) -> None:
1796 """Ensure sync.smartsync=false skips the manifest's default."""
1797 self.manifest.default.sync_smartsync = True
1798 self.opt.smart_sync = None
1799 mock.patch.object(self.cmd, "_UpdateAllManifestProjects").start()
1800 user_cfg = mock.MagicMock()
1801 user_cfg.GetBoolean.return_value = False
1802 with mock.patch.object(
1803 sync.RepoConfig, "ForUser", return_value=user_cfg
1804 ):
1805 with mock.patch.object(self.cmd, "_SmartSyncSetup") as mock_setup:
1806 with mock.patch.object(self.cmd, "_UpdateRepoProject"):
1807 with mock.patch.object(
1808 self.cmd, "_ValidateOptionsWithManifest"
1809 ):
1810 with mock.patch.object(self.cmd, "_SyncInterleaved"):
1811 with mock.patch.object(
1812 self.cmd, "_RunPostSyncHook"
1813 ):
1814 self.cmd.Execute(self.opt, [])
1815 mock_setup.assert_not_called()
1816 self.assertFalse(self.opt.smart_sync)
1817
1818 def test_user_config_smart_sync_enabled_error(self) -> None:
1819 """Ensure sync.smartsync=true fails hard instead of falling back."""
1820 self.manifest.default.sync_smartsync = False
1821 self.opt.smart_sync = None
1822 self.opt.mp_update = False
1823 user_cfg = mock.MagicMock()
1824 user_cfg.GetBoolean.return_value = True
1825 with mock.patch.object(
1826 sync.RepoConfig, "ForUser", return_value=user_cfg
1827 ):
1828 with mock.patch.object(
1829 self.cmd,
1830 "_SmartSyncSetup",
1831 side_effect=sync.SmartSyncError("unreachable"),
1832 ) as mock_setup:
1833 with self.assertRaises(sync.SmartSyncError):
1834 self.cmd.Execute(self.opt, [])
1835 mock_setup.assert_called_once()
1836
1702 def test_implicit_smart_sync_unparsable_manifest(self) -> None: 1837 def test_implicit_smart_sync_unparsable_manifest(self) -> None:
1703 """Ensure an unparsable smart sync manifest falls back to ToT.""" 1838 """Ensure an unparsable smart sync manifest falls back to ToT."""
1704 self.manifest.default.sync_smartsync = True 1839 self.manifest.default.sync_smartsync = True