def test_search_mapped_field_less_than():
    controller = FakeController()

    dist1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo1",
        last_publish=datetime.datetime(2019, 8, 23, 2, 5, 0, tzinfo=None),
    )
    dist2 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo1",
        last_publish=datetime.datetime(2019, 8, 27, 2, 5, 0, tzinfo=None),
    )
    repo1 = Repository(id="repo1", distributors=(dist1, dist2))

    controller.insert_repository(repo1)

    client = controller.client
    crit = Criteria.with_field(
        "last_publish",
        Matcher.less_than(datetime.datetime(2019, 8, 24, 0, 0, 0)))
    found = client.search_distributor(crit).result().data

    assert found == [dist1]
Exemple #2
0
def test_publish_out_repos(mock_ubipop_runner):
    dt = datetime(2019, 9, 12, 0, 0, 0)

    d1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo",
        last_publish=dt,
        relative_url="content/unit/2/client",
    )
    repo = YumRepository(
        id="repo",
        eng_product_id=102,
        distributors=[d1],
        relative_url="content/unit/2/client",
    )
    fake_pulp = FakeController()
    repo.__dict__["_client"] = fake_pulp.client

    fake_pulp.insert_repository(repo)
    # Setup output repos, leave only binary repo as the actual one
    mock_ubipop_runner.repos.out_repos = RepoSet(
        f_proxy(f_return(repo)), f_proxy(f_return()), f_proxy(f_return())
    )

    fts = mock_ubipop_runner._publish_out_repos()

    # we should publish only one repository with one distributor
    assert len(fts) == 1
    assert [hist.repository.id for hist in fake_pulp.publish_history] == ["repo"]
Exemple #3
0
def test_can_update_repo():
    controller = FakeController()

    controller.insert_repository(
        FileRepository(id="repo", product_versions=["a", "b", "c"]))

    client = controller.client

    # Should be able to get the repo.
    repo = client.get_repository("repo").result()

    # Let's try putting it back. Note we try changing both some mutable
    # and immutable fields here.
    update_f = client.update_repository(
        attr.evolve(repo, eng_product_id=123, product_versions=["d", "b"]))

    # The update should succeed (and return None)
    assert update_f.result() is None

    # Try getting the same repo back.
    repo_updated = client.get_repository("repo").result()

    # It should be equal to this:
    assert repo_updated == FileRepository(
        id="repo",
        # product_versions is mutable, so it's what we asked for (with
        # values canonicalized by sorting)
        product_versions=["b", "d"],
        # eng_product_id is not mutable, so that update was ignored
        eng_product_id=None,
    )
def test_delete_missing_distributor_succeeds():
    """dist.delete() of absent distributor with fake client succeeds.

    Deleting a distributor succeeds with the fake client since it also succeeds
    with the real client.
    """
    controller = FakeController()

    controller.insert_repository(
        Repository(
            id="repo",
            distributors=[
                Distributor(id="somedist", type_id="sometype", repo_id="repo")
            ],
        ))

    client = controller.client

    # Get two handles to the repos/distributors so we can delete via one handle
    # and try to delete again via the other
    repo_copy1 = client.get_repository("repo")
    repo_copy2 = client.get_repository("repo")

    dist_copy1 = repo_copy1.distributors[0]
    dist_copy2 = repo_copy2.distributors[0]

    # First delete succeeds, with some tasks
    assert dist_copy1.delete().result()

    # Second delete also succeeds, but there are no tasks since distributor
    # already doesn't exist
    assert dist_copy2.delete().result() == []
def test_upload_checks_repos(tmpdir):
    """Upload fails if upload apparently succeeded in pulp client, yet the item
    still is missing from all Pulp repos."""

    testfile = tmpdir.join("myfile")
    testfile.write("hello")

    pulp_ctrl = FakeController()
    repo = FileRepository(id="some-repo")
    pulp_ctrl.insert_repository(repo)

    item = NeverInReposItem(pushsource_item=FilePushItem(
        name="test", src=str(testfile), dest=["some-repo"]))
    item = item.with_checksums()

    ctx = item.upload_context(pulp_ctrl.client)
    upload_f = item.ensure_uploaded(ctx)

    # The upload attempt should fail.
    exc = upload_f.exception()

    # It should tell us why & which item.
    assert (
        "item supposedly uploaded successfully, but remains missing from Pulp:"
        in str(exc))
    assert "FilePushItem(name='test'" in str(exc)
def test_can_upload_comps(data_path):
    """repo.upload_comps_xml() succeeds with fake client."""

    xml_path = os.path.join(data_path, "sample-comps.xml")

    controller = FakeController()

    controller.insert_repository(YumRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    upload_f = repo1.upload_comps_xml(xml_path)

    # Upload should complete successfully.
    tasks = upload_f.result()

    # At least one task.
    assert tasks

    # Every task should have succeeded.
    for t in tasks:
        assert t.succeeded

    # If I now search for all content...
    units_all = list(client.search_content())

    # There should still be nothing, as the fake does not actually store
    # and reproduce comps-related units.
    assert units_all == []
Exemple #7
0
def test_can_sync():
    """repo.sync() succeeds with fake client and populates sync_history."""
    controller = FakeController()

    controller.insert_repository(YumRepository(id="repo1"))
    controller.insert_repository(YumRepository(id="repo2"))

    client = controller.client
    repo1 = client.get_repository("repo1")

    # Call to sync should succeed
    sync_f = repo1.sync(YumSyncOptions(feed="mock://feed/"))

    # The future should resolve successfully
    tasks = sync_f.result()

    # It should have returned at least one successful task.
    assert tasks
    for task in tasks:
        assert task.succeeded

    # The change should be reflected in the controller's sync history
    history = controller.sync_history

    assert len(history) == 1
    assert history[0].repository.id == "repo1"
    assert history[0].tasks == tasks
def test_delete_missing_repo_fails():
    """dist.delete() of distributor with absent repo fails."""
    controller = FakeController()

    controller.insert_repository(
        Repository(
            id="repo",
            distributors=[
                Distributor(id="somedist", type_id="sometype", repo_id="repo")
            ],
        ))

    client = controller.client

    # Get two handles to the repo, to set up the situation that
    # the distributor is not detached despite repo deletion
    repo1 = client.get_repository("repo")
    repo2 = client.get_repository("repo")
    dist = repo2.distributors[0]

    # We can delete the repo
    assert repo1.delete().result()

    # The distributor (obtained via repo2) is not detached, but nevertheless
    # deletion should fail as repo no longer exists
    assert "Repository id=repo not found" in str(dist.delete().exception())
def test_get_wrong_type_raises():
    """get_repository raises TypeError if passed argument of wrong type."""
    controller = FakeController()

    client = controller.client
    with pytest.raises(TypeError):
        client.get_repository(["oops", "should have been a string"])
def test_can_upload_history(tmpdir):
    """repo.upload_file() succeeds with fake client and populates upload_history.

    Note that upload_history is deprecated, but remains working for now.
    """
    controller = FakeController()

    controller.insert_repository(FileRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    somefile = tmpdir.join("some-file.txt")
    somefile.write(b"there is some binary data:\x00\x01\x02")

    upload_f = repo1.upload_file(str(somefile))

    # The future should resolve successfully
    tasks = upload_f.result()

    # The task should be successful.
    assert tasks[0].succeeded

    # The change should be reflected in the controller's upload history
    history = controller.upload_history

    digest = "fad3fc1e6d583b2003ec0a5273702ed8fcc2504271c87c40d9176467ebe218cb"
    assert len(history) == 1
    assert history[0].repository == repo1
    assert history[0].tasks == tasks
    assert history[0].name == somefile.basename
    assert history[0].sha256 == digest
Exemple #11
0
def test_publish_absent_raises():
    """repo.publish() of a nonexistent repo raises."""
    controller = FakeController()

    controller.insert_repository(
        YumRepository(
            id="repo1",
            distributors=[
                Distributor(id="yum_distributor", type_id="yum_distributor"),
                Distributor(id="cdn_distributor",
                            type_id="rpm_rsync_distributor"),
            ],
        ))

    client = controller.client
    repo_copy1 = client.get_repository("repo1")
    repo_copy2 = client.get_repository("repo1")

    # If I delete the repo through one handle...
    assert repo_copy1.delete().result()

    # ...then publish through the other handle becomes impossible
    exception = repo_copy2.publish().exception()
    assert isinstance(exception, PulpException)
    assert "repo1 not found" in str(exception)
def test_can_upload_rpm_meta(data_path):
    rpm_path = os.path.join(data_path, "rpms/walrus-5.21-1.noarch.rpm")
    controller = FakeController()

    controller.insert_repository(YumRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    to_upload = rpm_path

    upload_f = repo1.upload_rpm(to_upload, cdn_path="/path/to/my-great.rpm")

    # Upload should complete successfully.
    tasks = upload_f.result()

    # At least one task.
    assert tasks

    # Every task should have succeeded.
    for t in tasks:
        assert t.succeeded

    # RPM should now be in repo.
    units_in_repo = list(repo1.search_content())
    assert len(units_in_repo) == 1
    unit = units_in_repo[0]

    # Sanity check we got the right unit.
    assert unit.filename == "walrus-5.21-1.noarch.rpm"

    # Extra fields we passed during upload should be present here.
    assert unit.cdn_path == "/path/to/my-great.rpm"
    def __init__(self, state_path):
        self.ctrl = FakeController()
        self.state_path = state_path

        # Register ourselves with pubtools so we can get the task stop hook,
        # at which point we will save our current state.
        pm.register(self)
Exemple #14
0
def test_can_publish():
    """repo.publish() succeeds with fake client and populates publish_history."""
    controller = FakeController()

    controller.insert_repository(
        YumRepository(
            id="repo1",
            distributors=[
                Distributor(id="yum_distributor", type_id="yum_distributor"),
                Distributor(id="cdn_distributor",
                            type_id="rpm_rsync_distributor"),
            ],
        ))
    controller.insert_repository(YumRepository(id="repo2"))

    client = controller.client
    repo1 = client.get_repository("repo1")

    # Call to publish should succeed
    publish_f = repo1.publish()

    # The future should resolve successfully
    tasks = publish_f.result()

    # It should have returned at least one successful task.
    assert tasks
    for task in tasks:
        assert task.succeeded

    # The change should be reflected in the controller's publish history
    history = controller.publish_history

    assert len(history) == 1
    assert history[0].repository.id == "repo1"
    assert history[0].tasks == tasks
def test_search_paginates():
    controller = FakeController()

    repos = []
    for i in range(0, 1000):
        repo = Repository(id="repo-%s" % i)
        repos.append(repo)
        controller.insert_repository(repo)

    client = controller.client
    crit = Criteria.true()

    page = client.search_repository(crit)
    found_repos = list(page)

    page_count = 1
    while page.next:
        page_count += 1
        page = page.next.result()

    # There should have been several pages (it is not defined exactly
    # what page size the fake client uses, but it should be relatively
    # small to enforce that clients think about pagination)
    assert page_count >= 10

    # All repos should have been found
    assert sorted(found_repos) == sorted(repos)
def test_search_distributor_with_relative_url():
    controller = FakeController()

    dist1 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo1",
        relative_url="relative/path",
    )
    dist2 = Distributor(
        id="cdn_distributor",
        type_id="rpm_rsync_distributor",
        repo_id="repo1",
        relative_url="relative/path",
    )
    repo1 = Repository(id="repo1", distributors=(dist1, dist2))

    dist3 = Distributor(
        id="yum_distributor",
        type_id="yum_distributor",
        repo_id="repo2",
        relative_url="another/path",
    )

    repo2 = Repository(id="repo2", distributors=(dist3, ))

    controller.insert_repository(repo1)
    controller.insert_repository(repo2)

    client = controller.client
    crit = Criteria.with_field("relative_url", Matcher.regex("relative/path"))

    found = client.search_distributor(crit).result().data

    assert sorted(found) == [dist2, dist1]
def test_can_reupload_file_meta(tmpdir):
    """Can overwrite by uploading same content twice with different metadata."""
    controller = FakeController()

    controller.insert_repository(FileRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    somefile = tmpdir.join("some-file.txt")
    somefile.write(b"there is some binary data:\x00\x01\x02")

    time1 = datetime.datetime(2021, 12, 14, 14, 44, 0)
    time2 = datetime.datetime(2022, 1, 2, 3, 4, 5)

    upload_f = repo1.upload_file(
        str(somefile),
        description="My great file",
        cdn_path="/foo/bar.txt",
        cdn_published=time1,
    )

    # The future should resolve successfully
    tasks = upload_f.result()

    # The task should be successful.
    assert tasks[0].succeeded

    # Now upload again, but with some different values.
    upload_f = repo1.upload_file(str(somefile),
                                 description="My even better file",
                                 cdn_published=time2)

    # The future should resolve successfully
    tasks = upload_f.result()

    # The task should be successful.
    assert tasks[0].succeeded

    # File should now be in repo.
    units_in_repo = list(repo1.search_content())

    # Should result in just one unit, as the second upload effectively merges
    # with the existing unit.
    assert len(units_in_repo) == 1
    unit = units_in_repo[0]

    # Sanity check we got the right thing.
    assert unit.path == "some-file.txt"

    # Extra fields should be equal to the values passed in at the most
    # recent upload.
    assert unit.description == "My even better file"
    assert unit.cdn_published == time2

    # cdn_path was provided at the first upload and not the second.
    # In such cases it is expected that the field is wiped out, as you must
    # always provide *all* metadata at once.
    assert unit.cdn_path is None
Exemple #18
0
def test_update_missing_repo():
    controller = FakeController()
    client = controller.client

    # Try to update something which is previously unknown to the client.
    update_f = client.update_repository(FileRepository(id="whatever"))

    # It should fail telling us the repo doesn't exist
    assert "repository not found: whatever" in str(update_f.exception())
def test_get_missing_raises():
    """get_repository returns unsuccessful future if repo doesn't exist."""
    controller = FakeController()

    repo_f = controller.client.get_repository("some-repo")
    with pytest.raises(PulpException) as raised:
        repo_f.result()

    assert "some-repo not found" in str(raised.value)
def test_set_content_type_ids():
    """Fake controller can be used to set content type IDs."""
    controller = FakeController()
    client = controller.client

    controller.set_content_type_ids(["a", "b", "c"])

    type_ids = client.get_content_type_ids()
    assert sorted(type_ids) == ["a", "b", "c"]
def test_can_remove_content():
    """repo.remove() succeeds and removes expected units inserted via controller."""
    controller = FakeController()
    client = controller.client

    rpm_units = [
        RpmUnit(name="bash", version="4.0", release="1", arch="x86_64"),
        RpmUnit(name="glibc", version="5.0", release="1", arch="x86_64"),
    ]
    modulemd_units = [
        ModulemdUnit(
            name="module1", stream="s1", version=1234, context="a1b2", arch="x86_64"
        ),
        ModulemdUnit(
            name="module1", stream="s1", version=1235, context="a1b2", arch="x86_64"
        ),
    ]
    units = rpm_units + modulemd_units

    repo = YumRepository(id="repo1")
    controller.insert_repository(repo)
    controller.insert_units(repo, units)

    remove_rpms = client.get_repository("repo1").remove_content(type_ids=["rpm"])

    assert len(remove_rpms) == 1
    task = remove_rpms[0]

    # It should have completed successfully
    assert task.completed
    assert task.succeeded

    # It should have removed (only) RPM units
    assert sorted(task.units) == sorted(rpm_units)

    # Now if we ask to remove same content again...
    remove_rpms = client.get_repository("repo1").remove_content(type_ids=["rpm"])

    assert len(remove_rpms) == 1
    task = remove_rpms[0]

    # It should have completed successfully, but no RPMs to remove
    assert task.completed
    assert task.succeeded
    assert not task.units

    # It should still be possible to remove other content
    remove_all = client.get_repository("repo1").remove_content()

    assert len(remove_all) == 1
    task = remove_all[0]

    # It should have completed successfully, and removed the modulemds
    assert task.completed
    assert task.succeeded
    assert sorted(task.units) == sorted(modulemd_units)
def test_can_upload_units(tmpdir):
    """repo.upload_file() succeeds with fake client and populates units."""
    controller = FakeController()

    controller.insert_repository(FileRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    somefile = tmpdir.join("some-file.txt")
    somefile.write(b"there is some binary data:\x00\x01\x02")

    otherfile = tmpdir.join("another.txt")
    otherfile.write("ahoy there")

    upload1_f = repo1.upload_file(str(somefile))
    upload2_f = repo1.upload_file(str(otherfile),
                                  relative_url="another/path.txt")

    for f in [upload1_f, upload2_f]:
        # The future should resolve successfully
        tasks = f.result()

        # The task should be successful.
        assert tasks[0].succeeded

    # If I now search for content in that repo, or content across all repos...
    units_in_repo = sorted(repo1.search_content().result(),
                           key=lambda u: u.sha256sum)
    units_all = sorted(client.search_content().result(),
                       key=lambda u: u.sha256sum)

    # They should be equal
    assert units_all == units_in_repo

    # And they should be this
    assert units_in_repo == [
        FileUnit(
            path="another/path.txt",
            size=10,
            sha256sum=
            "94c0c9d847ecaa45df01999676db772e5cb69cc54e1ff9db31d02385c56a86e1",
            repository_memberships=["repo1"],
            unit_id="d4713d60-c8a7-0639-eb11-67b367a9c378",
        ),
        FileUnit(
            path="some-file.txt",
            size=29,
            sha256sum=
            "fad3fc1e6d583b2003ec0a5273702ed8fcc2504271c87c40d9176467ebe218cb",
            repository_memberships=["repo1"],
            unit_id="e3e70682-c209-4cac-629f-6fbed82c07cd",
        ),
    ]
def test_update_checks_state():
    """Update fails if update apparently succeeded in pulp client, yet the item
    doesn't match the desired state."""

    pulp_unit = FileUnit(
        unit_id="some-file-unit",
        path="some/file.txt",
        size=5,
        sha256sum=
        "49ae93732fcf8d63fe1cce759664982dbd5b23161f007dba8561862adc96d063",
        description="a test file",
        repository_memberships=["some-repo"],
    )

    pulp_ctrl = FakeController()
    repo = FileRepository(id="some-repo")
    pulp_ctrl.insert_repository(repo)
    pulp_ctrl.insert_units(repo, [pulp_unit])

    item = NeverUpToDateItem(
        pushsource_item=FilePushItem(
            name="some/file.txt",
            sha256sum=
            "49ae93732fcf8d63fe1cce759664982dbd5b23161f007dba8561862adc96d063",
            dest=["some-repo"],
        ),
        pulp_unit=pulp_unit,
        pulp_state=State.NEEDS_UPDATE,
    )

    # Try updating it.
    update_f = item.ensure_uptodate(pulp_ctrl.client)

    # The update attempt should fail.
    exc = update_f.exception()

    # It should tell us why.
    assert (
        "item supposedly updated successfully, but actual and desired state still differ:"
        in str(exc))

    # It should tell us the item we failed to process.
    assert "item:         FilePushItem(name='some/file.txt'" in str(exc)

    # It should show the current and desired field values:

    # The 'current unit', i.e. the state after we updated, reversed the original
    # description.
    assert re.search(r"current unit: FileUnit.*elif tset a", str(exc))

    # The 'desired unit', i.e. the reason we still don't consider the unit up-to-date,
    # wants to reverse the description back again...
    assert re.search(r"desired unit: FileUnit.*a test file", str(exc))
def test_search_null_or():
    """Search with an empty OR gives an error."""
    controller = FakeController()

    repo1 = Repository(id="repo1")

    controller.insert_repository(repo1)

    client = controller.client
    crit = Criteria.or_()
    assert "Invalid OR in search query" in str(
        client.search_repository(crit).exception())
def _get_fake_controller(*args):
    @attr.s(kw_only=True, frozen=True)
    class TestRepo(Repository):
        is_temp_repo = pp_attr.pulp_attrib(default=None,
                                           type=str,
                                           pulp_field="notes.pub_temp_repo")

    controller = FakeController()
    for repo in args:
        yum_repo = TestRepo.from_data(repo)
        controller.insert_repository(yum_repo)
    return controller
def test_upload_comps_error():
    """repo.upload_comps_xml() raises with fake client when given invalid input."""
    xml = BytesIO(b"Oops not valid")

    controller = FakeController()

    controller.insert_repository(YumRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    with pytest.raises(ExpatError):
        repo1.upload_comps_xml(xml)
def test_search_no_result():
    controller = FakeController()

    repo1 = Repository(id="repo1")
    repo2 = Repository(id="repo2")

    controller.insert_repository(repo1)
    controller.insert_repository(repo2)

    client = controller.client
    crit = Criteria.with_field("notes.whatever", "foobar")
    found = client.search_repository(crit).data

    assert found == []
Exemple #28
0
def test_search_bad_criteria():
    """Search with criteria of wrong type gives an error."""
    controller = FakeController()

    repo1 = Repository(id="repo1")

    controller.insert_repository(repo1)

    client = controller.client

    with pytest.raises(Exception) as exc:
        client.search_repository("not a valid criteria")

    assert "Not a criteria" in str(exc.value)
def test_replace_file(tmpdir):
    """repo.upload_file() behaves as expected when replacing a file of the same name."""
    controller = FakeController()

    controller.insert_repository(FileRepository(id="repo1"))

    client = controller.client
    repo1 = client.get_repository("repo1").result()

    somefile = tmpdir.join("some-file.txt")
    somefile.write(b"there is some binary data:\x00\x01\x02")

    otherfile = tmpdir.join("another.txt")
    otherfile.write("ahoy there")

    # Upload both files, using the same relative_url for each.
    repo1.upload_file(str(somefile), relative_url="darmok-jalad.txt").result()
    repo1.upload_file(str(otherfile), relative_url="darmok-jalad.txt").result()

    # If I now search for content in that repo, or content across all repos...
    units_in_repo = sorted(repo1.search_content().result(),
                           key=lambda u: u.sha256sum)
    units_all = sorted(client.search_content().result(),
                       key=lambda u: u.sha256sum)

    # I should find that only the second uploaded file is still present in the repo.
    assert units_in_repo == [
        FileUnit(
            path="darmok-jalad.txt",
            size=10,
            sha256sum=
            "94c0c9d847ecaa45df01999676db772e5cb69cc54e1ff9db31d02385c56a86e1",
            repository_memberships=["repo1"],
            unit_id="d4713d60-c8a7-0639-eb11-67b367a9c378",
        )
    ]

    # However, both units should still exist in the system; the first uploaded unit
    # has become an orphan.
    assert units_all == units_in_repo + [
        FileUnit(
            path="darmok-jalad.txt",
            size=29,
            sha256sum=
            "fad3fc1e6d583b2003ec0a5273702ed8fcc2504271c87c40d9176467ebe218cb",
            content_type_id="iso",
            repository_memberships=[],
            unit_id="e3e70682-c209-4cac-629f-6fbed82c07cd",
        )
    ]
def test_can_get():
    """get_repository returns repository inserted via controller."""
    controller = FakeController()

    repo1 = Repository(id="repo1")
    repo2 = Repository(id="repo2")

    controller.insert_repository(repo1)
    controller.insert_repository(repo2)

    client = controller.client
    found = client.get_repository("repo2").result()

    assert found == repo2