|
10 | 10 |
|
11 | 11 | from poetry.console.exceptions import PoetryRuntimeError |
12 | 12 | from poetry.installation.chooser import Chooser |
| 13 | +from poetry.core.packages.utils.link import Link |
13 | 14 | from poetry.repositories.legacy_repository import LegacyRepository |
14 | 15 | from poetry.utils.env import MockEnv |
15 | 16 |
|
16 | 17 |
|
17 | 18 | if TYPE_CHECKING: |
18 | 19 | from poetry.core.packages.package import PackageFile |
19 | 20 |
|
| 21 | + from pytest_mock import MockerFixture |
| 22 | + |
20 | 23 | from poetry.repositories.repository_pool import RepositoryPool |
21 | 24 | from tests.conftest import Config |
22 | 25 | from tests.types import DistributionHashGetter |
@@ -323,6 +326,60 @@ def test_chooser_does_not_choose_yanked_if_others( |
323 | 326 | assert link_partial_yank.filename == "futures-3.2.0.tar.gz" |
324 | 327 |
|
325 | 328 |
|
| 329 | +LOCKED_SHA = "sha256:" + "1" * 64 |
| 330 | +OTHER_SHA = "sha256:" + "2" * 64 |
| 331 | + |
| 332 | + |
| 333 | +def _hashless_package_and_pool( |
| 334 | + pool: RepositoryPool, mocker: MockerFixture, computed: str |
| 335 | +) -> Package: |
| 336 | + """Point the pool at a single link that advertises no hash at all, and make |
| 337 | + the repository compute `computed` for it. |
| 338 | + """ |
| 339 | + package = Package( |
| 340 | + "isort", |
| 341 | + "4.3.4", |
| 342 | + source_type="legacy", |
| 343 | + source_reference="foo", |
| 344 | + source_url="https://legacy.foo.bar/simple/", |
| 345 | + ) |
| 346 | + package.files = [{"file": "isort-4.3.4.tar.gz", "hash": LOCKED_SHA}] |
| 347 | + |
| 348 | + hashless = Link("https://legacy.foo.bar/isort-4.3.4.tar.gz") |
| 349 | + assert not hashless.hashes |
| 350 | + |
| 351 | + mocker.patch.object( |
| 352 | + LegacyRepository, "find_links_for_package", return_value=[hashless] |
| 353 | + ) |
| 354 | + mocker.patch.object(LegacyRepository, "calculate_sha256", return_value=computed) |
| 355 | + return package |
| 356 | + |
| 357 | + |
| 358 | +def test_chooser_rejects_a_hashless_link_whose_computed_hash_does_not_match( |
| 359 | + env: MockEnv, pool: RepositoryPool, mocker: MockerFixture |
| 360 | +) -> None: |
| 361 | + """An index that omits the hash fragment must not bypass the locked hashes.""" |
| 362 | + package = _hashless_package_and_pool(pool, mocker, OTHER_SHA) |
| 363 | + |
| 364 | + with pytest.raises(PoetryRuntimeError) as e: |
| 365 | + Chooser(pool, env).choose_for(package) |
| 366 | + |
| 367 | + assert "did not match any known checksums" in str(e.value) |
| 368 | + |
| 369 | + |
| 370 | +def test_chooser_accepts_a_hashless_link_whose_computed_hash_matches( |
| 371 | + env: MockEnv, pool: RepositoryPool, mocker: MockerFixture |
| 372 | +) -> None: |
| 373 | + """Computing the hash is the point, so a hashless link that hashes to the |
| 374 | + locked value is still installable. |
| 375 | + """ |
| 376 | + package = _hashless_package_and_pool(pool, mocker, LOCKED_SHA) |
| 377 | + |
| 378 | + link = Chooser(pool, env).choose_for(package) |
| 379 | + |
| 380 | + assert link.filename == "isort-4.3.4.tar.gz" |
| 381 | + |
| 382 | + |
326 | 383 | @pytest.mark.parametrize("source_type", ["", "legacy"]) |
327 | 384 | def test_chooser_throws_an_error_if_package_hashes_do_not_match( |
328 | 385 | env: MockEnv, |
|
0 commit comments