diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_subcmds_sync.py | 167 |
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 | ) | ||
| 528 | def 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 | ) | ||
| 556 | def 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 | ) |
| 523 | def test_cli_manifest_server_credentials( | 611 | def 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 | ||
| 543 | class LocalSyncState(unittest.TestCase): | 636 | class 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 |
