def test_koji_rpms(fake_koji, koji_dir): """Koji source yields requested RPMs""" source = Source.get( "koji:https://koji.example.com/?rpm=foo-1.0-1.x86_64.rpm,notfound-2.0-1.noarch.rpm", basedir=koji_dir, ) # It should not have done anything yet (lazy loading) assert not fake_koji.last_url # Insert some data fake_koji.rpm_data["foo-1.0-1.x86_64.rpm"] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } # Eagerly fetch items = list(source) # It should have constructed a session for the given URL assert fake_koji.last_url == "https://koji.example.com/" # It should have returned push items for the two RPMs assert len(items) == 2 items = sorted(items, key=lambda pi: pi.name) # For present RPM, a push item should be yielded using the koji metadata. assert items[0] == RpmPushItem( name="foo-1.0-1.x86_64.rpm", state="PENDING", src= "%s/vol/somevol/packages/foobuild/1.0/1.el8/x86_64/foo-1.0-1.x86_64.rpm" % koji_dir, build="foobuild-1.0-1.el8", ) # For missing RPMs, a push item should be yielded with NOTFOUND state. assert items[1] == RpmPushItem(name="notfound-2.0-1.noarch.rpm", state="NOTFOUND")
def push_item_for_rpm(self, unit): out = {} out["state"] = "DELETED" out["origin"] = "pulp" filename_parts = [ unit.name, "-", unit.version, "-", unit.release, ".", unit.arch, ".rpm", ] out["name"] = "".join(filename_parts) if unit.sha256sum: out["sha256sum"] = unit.sha256sum if unit.md5sum: out["md5sum"] = unit.md5sum out["signing_key"] = unit.signing_key return RpmPushItem(**out)
def push_item_for_rpm(self, unit, dest, state): out = {} out["state"] = state out["origin"] = "pulp" filename_parts = [ unit.name, "-", unit.version, "-", unit.release, ".", unit.arch, ".rpm", ] out["name"] = "".join(filename_parts) out["dest"] = [dest] # Note: in practice we don't necessarily expect to get all of these # attributes, as after a delete the server will only provide those # which make up the unit key. We still copy them anyway (even if # values are None) in case this is improved some day. out["sha256sum"] = unit.sha256sum out["md5sum"] = unit.md5sum out["signing_key"] = unit.signing_key return RpmPushItem(**out)
def test_pre_push_no_dest(fake_controller, data_path, fake_push, fake_state_path, command_tester): """Test usage of --pre-push with an RPM having no dest.""" # Sanity check that the Pulp server is, initially, empty. client = fake_controller.client assert list(client.search_content()) == [] # We're going to push just this one RPM. rpm_src = os.path.join(data_path, "staged-mixed/dest1/RPMS/walrus-5.21-1.noarch.rpm") rpm_item = RpmPushItem(name=os.path.basename(rpm_src), src=rpm_src, signing_key="a1b2c3") # Set up a pushsource backend to return just that item. Source.register_backend("fake", lambda: [rpm_item]) compare_extra = { "pulp.yaml": { "filename": fake_state_path, "normalize": hide_unit_ids, } } args = [ "", # This option enables pre-push which should avoid making content # visible to end-users "--pre-push", "--source", "fake:", "--pulp-url", "https://pulp.example.com/", ] run = functools.partial(entry_point, cls=lambda: fake_push) # It should be able to run without crashing. command_tester.test( run, args, compare_plaintext=False, compare_jsonl=False, compare_extra=compare_extra, ) # command_tester will have already compared pulp state against baseline, # but just to be explicit about it we will check here too... units = list(client.search_content()) # It should have uploaded the one RPM assert len(units) == 1 assert isinstance(units[0], RpmUnit) # Only to this repo assert units[0].repository_memberships == ["all-rpm-content"]
def test_keep_prepush_no_dest_items(): """Push item filtering keeps items with no dest if pre-pushable.""" ctx = Context() phase = LoadPushItems( ctx, ["fake:"], allow_unsigned=True, pre_push=True, ) fake_items = [ FilePushItem(name="file", dest=["some-repo"]), RpmPushItem(name="rpm", dest=[]), ] Source.register_backend("fake", lambda: fake_items) # Let it run to completion... with phase: pass # It should have succeeded assert not ctx.has_error # Now let's get everything from the output queue. all_outputs = [] while True: item = phase.out_queue.get() if item is Phase.FINISHED: break all_outputs.append(item.pushsource_item) # We should have got this: assert all_outputs == [ # get file as usual FilePushItem(name="file", dest=["some-repo"]), # even though this item has no destination, we still get it since rpms # support pre-push and pre_push was enabled. RpmPushItem(name="rpm", dest=[]), ]
def test_staged_simple_rpm(caplog): staged_dir = os.path.join(DATADIR, "simple_rpm") source = Source.get("staged:" + staged_dir) files = list(source) files.sort(key=lambda item: item.src) # It should find the staged RPMs assert files == [ RpmPushItem( name="walrus-5.21-1.noarch.rpm", state="PENDING", src=os.path.join(staged_dir, "dest1/RPMS/walrus-5.21-1.noarch.rpm"), dest=["dest1"], md5sum=None, sha256sum=None, origin=staged_dir, build=None, # Note this signing key was extracted from RPM headers. signing_key="F78FB195", ), RpmPushItem( name="test-srpm01-1.0-1.src.rpm", state="PENDING", src=os.path.join(staged_dir, "dest1/SRPMS/test-srpm01-1.0-1.src.rpm"), dest=["dest1"], md5sum=None, sha256sum=None, origin=staged_dir, build=None, signing_key=None, ), ] # It should also warn about this nonrpm_path = os.path.join(staged_dir, "dest1/RPMS/not-an-rpm.txt") msg = "Unexpected non-RPM %s (ignored)" % nonrpm_path assert msg in caplog.messages
def test_rpm_bad_filename(): """rpm_nvr raises a meaningful error when NVR can't be parsed.""" # This RPM's filename doesn't match the NVR.A.rpm convention # per http://ftp.rpm.org/max-rpm/ch-rpm-file-format.html item = PulpRpmPushItem(pushsource_item=RpmPushItem( name="my-badlynamed.rpm")) # We should not be able to retrieve the NVR. with pytest.raises(ValueError) as excinfo: item.rpm_nvr # The exception should tell us why. assert ("Invalid RPM filename my-badlynamed.rpm " "(expected: [name]-[version]-[release].[arch].rpm" in str(excinfo.value))
def test_koji_poll_for_signed_rpm_highest_priority_key_absent( mock_sleep, mock_path_exists, fake_koji, koji_dir, caplog): """Highest priority key is always absent and a lower priority key is found.""" source = Source.get( "koji:https://koji.example.com/?rpm=foo-1.0-1.x86_64.rpm", basedir=koji_dir, signing_key=["ABC123", None, "DEF456"], ) fake_koji.rpm_data["foo-1.0-1.x86_64.rpm"] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } signed_rpm_path = os.path.join( koji_dir, "vol/somevol/packages/foobuild/1.0/1.el8", "data/signed/def456/x86_64/foo-1.0-1.x86_64.rpm", ) mock_path_exists.side_effect = [ False, False, False, False, False, True, True, True ] # Eagerly fetch items = list(source) # It should have found the RPM using the signing key we created within testdata assert items[0] == RpmPushItem( name="foo-1.0-1.x86_64.rpm", state="PENDING", src=signed_rpm_path, build="foobuild-1.0-1.el8", signing_key="def456", ) assert len(items) == 1 assert mock_sleep.call_count == 2
def test_koji_uses_signing_key(fake_koji, koji_dir, caplog): """RPM uses first existing of specified signing keys.""" source = Source.get( "koji:https://koji.example.com/?rpm=foo-1.0-1.x86_64.rpm", basedir=koji_dir, signing_key=["ABC123", None, "DEF456"], ) fake_koji.rpm_data["foo-1.0-1.x86_64.rpm"] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } signed_rpm_path = os.path.join( koji_dir, "vol/somevol/packages/foobuild/1.0/1.el8", "data/signed/def456/x86_64/foo-1.0-1.x86_64.rpm", ) # Make the signed RPM exist (contents not relevant here) os.makedirs(os.path.dirname(signed_rpm_path)) open(signed_rpm_path, "wb") # Eagerly fetch items = list(source) # It should have found the RPM using the signing key we created within testdata assert items[0] == RpmPushItem( name="foo-1.0-1.x86_64.rpm", state="PENDING", src=signed_rpm_path, build="foobuild-1.0-1.el8", signing_key="def456", )
def test_koji_missing_signing_key_timeout(mock_sleep, fake_koji, koji_dir, caplog): """RPM is NOTFOUND if requested signing key is not available.""" source = Source.get( "koji:https://koji.example.com/?rpm=foo-1.0-1.x86_64.rpm&signing_key=abc123", basedir=koji_dir, ) fake_koji.rpm_data["foo-1.0-1.x86_64.rpm"] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } # Eagerly fetch items = list(source) # It should be counted as NOTFOUND... assert items == [ RpmPushItem(name="foo-1.0-1.x86_64.rpm", state="NOTFOUND") ] # ...for this reason expected_path = ( "%s/vol/somevol/packages/foobuild/1.0/1.el8/data/signed/abc123/x86_64/foo-1.0-1.x86_64.rpm" % koji_dir) expected_msg = "RPM not found in koji at path(s): %s" % expected_path assert expected_msg in caplog.messages assert mock_sleep.call_count == 2
def test_unsigned_failure( fake_push, command_tester, caplog, ): """Test that a failure occurs if an unsigned RPM is encountered without the --allow-unsigned option. """ Source.register_backend( "unsigned", lambda: [RpmPushItem(name="quux", src="/some/unsigned.rpm", dest=["repo1"])], ) args = [ "", "--source", "unsigned:", "--pulp-url", "https://pulp.example.com/", ] run = functools.partial(entry_point, cls=lambda: fake_push) # It should exit... with pytest.raises(SystemExit) as excinfo: command_tester.test( run, args, compare_plaintext=False, compare_jsonl=False, ) # ...unsuccessfully assert excinfo.value.code != 0 # And it should tell us what went wrong assert "Unsigned content is not permitted: /some/unsigned.rpm" in caplog.text
def test_koji_missing_signing_key(fake_koji, koji_dir, caplog): """RPM is NOTFOUND if requested signing key is not available.""" source = Source.get( "koji:https://koji.example.com/?rpm=foo-1.0-1.x86_64.rpm&signing_key=abc123", basedir=koji_dir, ) fake_koji.rpm_data["foo-1.0-1.x86_64.rpm"] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } # Eagerly fetch items = list(source) # It should be counted as NOTFOUND... assert items == [ RpmPushItem(name="foo-1.0-1.x86_64.rpm", state="NOTFOUND") ] # ...for this reason assert ( "RPM not found in koji with signing key(s) abc123: foo-1.0-1.x86_64.rpm" in caplog.messages)
def test_koji_rpm_by_int(fake_koji, koji_dir): """Koji source yields requested RPM by ID""" source = Source.get( "koji:https://koji.example.com/", basedir=koji_dir, # source is expected to accept both real ints and integer strings, # the latter coming from URLs. rpm=["12345", 23456], ) # It should not have done anything yet (lazy loading) assert not fake_koji.last_url # Insert some data. Keys are using real integers, which tests that # the source is converting integer strings to real integers before calling # to koji. fake_koji.rpm_data[12345] = { "arch": "x86_64", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.rpm_data[23456] = { "arch": "noarch", "name": "foo", "version": "1.0", "release": "1", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "foobuild", "version": "1.0", "release": "1.el8", "nvr": "foobuild-1.0-1.el8", "volume_name": "somevol", } # Eagerly fetch items = list(source) # It should have constructed a session for the given URL assert fake_koji.last_url == "https://koji.example.com/" # It should have returned push items for the two RPMs assert len(items) == 2 items = sorted(items, key=lambda pi: pi.name) # It should have yielded the two RPMs. assert items[0] == RpmPushItem( name="foo-1.0-1.noarch.rpm", state="PENDING", src="%s/vol/somevol/packages/foobuild/1.0/1.el8/noarch/foo-1.0-1.noarch.rpm" % koji_dir, build="foobuild-1.0-1.el8", ) assert items[1] == RpmPushItem( name="foo-1.0-1.x86_64.rpm", state="PENDING", src="%s/vol/somevol/packages/foobuild/1.0/1.el8/x86_64/foo-1.0-1.x86_64.rpm" % koji_dir, build="foobuild-1.0-1.el8", )
def __iter__(self): yield RpmPushItem(name="sudo-1.8.25p1-4.el8_0.3.x86_64.rpm", state="NOTFOUND") yield RpmPushItem(name="sudo-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="NOTFOUND")
def test_errata_rpms_via_koji(fake_errata_tool, fake_koji, koji_dir): """Errata source yields RPMs taken from koji source""" source = Source.get( "errata:https://errata.example.com", errata="RHSA-2020:0509", koji_source="koji:https://koji.example.com?basedir=%s" % koji_dir, ) # Insert koji RPMs referenced by this advisory fake_koji.rpm_data["sudo-1.8.25p1-4.el8_0.3.ppc64le.rpm"] = { "arch": "ppc64le", "name": "sudo", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-1.8.25p1-4.el8_0.3.x86_64.rpm"] = { "arch": "x86_64", "name": "sudo", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-1.8.25p1-4.el8_0.3.src.rpm"] = { "arch": "src", "name": "sudo", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm"] = { "arch": "ppc64le", "name": "sudo-debuginfo", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-debuginfo-1.8.25p1-4.el8_0.3.x86_64.rpm"] = { "arch": "ppc64le", "name": "sudo-debuginfo", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm"] = { "arch": "ppc64le", "name": "sudo-debugsource", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.rpm_data["sudo-debugsource-1.8.25p1-4.el8_0.3.x86_64.rpm"] = { "arch": "ppc64le", "name": "sudo-debugsource", "version": "1.8.25p1", "release": "4.el8_0.3", "build_id": 1234, } fake_koji.build_data[1234] = { "id": 1234, "name": "sudo", "version": "1.8.25p1", "release": "4.el8_0.3", "nvr": "sudo-1.8.25p1-4.el8_0.3", } signed_rpm_path = os.path.join( koji_dir, "vol/somevol/packages/foobuild/1.0/1.el8", "data/signed/def456/x86_64/foo-1.0-1.x86_64.rpm", ) # Make signed RPMs exist (contents not relevant here) for filename, rpm in fake_koji.rpm_data.items(): signed_rpm_path = os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/", "data/signed/fd431d51/%s/%s" % (rpm["arch"], filename), ) signed_dir = os.path.dirname(signed_rpm_path) if not os.path.exists(signed_dir): os.makedirs(signed_dir) open(signed_rpm_path, "w") items = list(source) errata_items = [i for i in items if isinstance(i, ErratumPushItem)] rpm_items = [i for i in items if isinstance(i, RpmPushItem)] # It should have found the one advisory assert len(errata_items) == 1 errata_item = errata_items[0] # Validate a few of the advisory fields assert str( errata_item) == "RHSA-2020:0509: Important: sudo security update" # pkglist should have just one collection assert errata_item.pkglist == [ ErratumPackageCollection( name="RHSA-2020:0509", packages=[ ErratumPackage( arch="ppc64le", filename="sudo-1.8.25p1-4.el8_0.3.ppc64le.rpm", epoch="0", name="sudo", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="0d56f302617696d3511e71e1669e62c0", sha1sum=None, sha256sum= "31c4f73af90c6d267cc5281c59e4a93ae3557b2253d9a8e3fef55f3cafca6e54", ), ErratumPackage( arch="SRPMS", filename="sudo-1.8.25p1-4.el8_0.3.src.rpm", epoch="0", name="sudo", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="f94ab3724b498e3faeab643fe2a67c9c", sha1sum=None, sha256sum= "10d7724302a60d0d2ca890fc7834b8143df55ba1ce0176469ea634ac4ab7aa28", ), ErratumPackage( arch="x86_64", filename="sudo-1.8.25p1-4.el8_0.3.x86_64.rpm", epoch="0", name="sudo", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="25e9470c4fe96034fe1d7525c04b5d8e", sha1sum=None, sha256sum= "593f872c1869f7beb963c8df2945fc691a1d999945c8c45c6bc7e02731fa016f", ), ErratumPackage( arch="ppc64le", filename="sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm", epoch="0", name="sudo-debuginfo", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="e242826fb38f487502cdc1f1a06991d2", sha1sum=None, sha256sum= "04db0c39efb31518ff79bf98d1c27256d46cdc72b967a5b2094a6efec3166df2", ), ErratumPackage( arch="x86_64", filename="sudo-debuginfo-1.8.25p1-4.el8_0.3.x86_64.rpm", epoch="0", name="sudo-debuginfo", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="91126f02975c06015880d6ea99cb2760", sha1sum=None, sha256sum= "1b7d3a7613236ffea7c4553eb9dea69fc19557005ac3a059d7e83efc08c5b754", ), ErratumPackage( arch="ppc64le", filename="sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm", epoch="0", name="sudo-debugsource", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="d6da7e2e3d9efe050fef2e8d047682be", sha1sum=None, sha256sum= "355cbb9dc348b17782cff57120391685d6a1f6884facc54fac4b7fb54abeffba", ), ErratumPackage( arch="x86_64", filename="sudo-debugsource-1.8.25p1-4.el8_0.3.x86_64.rpm", epoch="0", name="sudo-debugsource", version="1.8.25p1", release="4.el8_0.3", src="sudo-1.8.25p1-4.el8_0.3.src.rpm", md5sum="6b0967941c0caf626c073dc7da0272b6", sha1sum=None, sha256sum= "43e318fa49e4df685ea0d5f0925a00a336236b2e20f27f9365c39a48102c2cf6", ), ], short="", module=None, ) ] # Erratum should be sent to every dest referenced by an RPM rpm_dests = [] for item in rpm_items: rpm_dests.extend(item.dest) assert set(errata_item.dest) == set(rpm_dests) # It should have found the RPMs referenced by the advisory assert sorted(rpm_items, key=lambda rpm: rpm.src) == [ RpmPushItem( name="sudo-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/ppc64le/sudo-1.8.25p1-4.el8_0.3.ppc64le.rpm", ), dest=["rhel-8-for-ppc64le-baseos-e4s-rpms__8_DOT_0"], md5sum="0d56f302617696d3511e71e1669e62c0", sha256sum= "31c4f73af90c6d267cc5281c59e4a93ae3557b2253d9a8e3fef55f3cafca6e54", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/ppc64le/sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm", ), dest=["rhel-8-for-ppc64le-baseos-e4s-debug-rpms__8_DOT_0"], md5sum="e242826fb38f487502cdc1f1a06991d2", sha256sum= "04db0c39efb31518ff79bf98d1c27256d46cdc72b967a5b2094a6efec3166df2", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/ppc64le/sudo-debuginfo-1.8.25p1-4.el8_0.3.ppc64le.rpm", ), dest=["rhel-8-for-ppc64le-baseos-e4s-debug-rpms__8_DOT_0"], md5sum="e242826fb38f487502cdc1f1a06991d2", sha256sum= "04db0c39efb31518ff79bf98d1c27256d46cdc72b967a5b2094a6efec3166df2", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/ppc64le/sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm", ), dest=["rhel-8-for-ppc64le-baseos-e4s-debug-rpms__8_DOT_0"], md5sum="d6da7e2e3d9efe050fef2e8d047682be", sha256sum= "355cbb9dc348b17782cff57120391685d6a1f6884facc54fac4b7fb54abeffba", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/ppc64le/sudo-debugsource-1.8.25p1-4.el8_0.3.ppc64le.rpm", ), dest=["rhel-8-for-ppc64le-baseos-e4s-debug-rpms__8_DOT_0"], md5sum="d6da7e2e3d9efe050fef2e8d047682be", sha256sum= "355cbb9dc348b17782cff57120391685d6a1f6884facc54fac4b7fb54abeffba", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-1.8.25p1-4.el8_0.3.src.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/src/sudo-1.8.25p1-4.el8_0.3.src.rpm", ), dest=[ "rhel-8-for-ppc64le-baseos-e4s-source-rpms__8_DOT_0", "rhel-8-for-x86_64-baseos-e4s-source-rpms__8_DOT_0", ], md5sum="f94ab3724b498e3faeab643fe2a67c9c", sha256sum= "10d7724302a60d0d2ca890fc7834b8143df55ba1ce0176469ea634ac4ab7aa28", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), RpmPushItem( name="sudo-1.8.25p1-4.el8_0.3.x86_64.rpm", state="PENDING", src=os.path.join( koji_dir, "packages/sudo/1.8.25p1/4.el8_0.3/data/signed", "fd431d51/x86_64/sudo-1.8.25p1-4.el8_0.3.x86_64.rpm", ), dest=["rhel-8-for-x86_64-baseos-e4s-rpms__8_DOT_0"], md5sum="25e9470c4fe96034fe1d7525c04b5d8e", sha256sum= "593f872c1869f7beb963c8df2945fc691a1d999945c8c45c6bc7e02731fa016f", origin="RHSA-2020:0509", build="sudo-1.8.25p1-4.el8_0.3", signing_key="fd431d51", ), ]
def test_uploads_shared(data_path): """Upload phase allows for uploads of identical content to be reused.""" pulp_ctrl = FakeController() pulp_ctrl.insert_repository(YumRepository(id="all-rpm-content")) pulp_ctrl.insert_repository(YumRepository(id="repo1")) pulp_ctrl.insert_repository(YumRepository(id="repo2")) pulp_ctrl.insert_repository(YumRepository(id="repo3")) client_wrapper = ClientWrapper(pulp_ctrl.client) ctx = Context() queue = ctx.new_queue() phase = Upload( context=ctx, pulp_client_factory=lambda: client_wrapper, pre_push=None, in_queue=queue, update_push_items=lambda _: None, ) rpm1 = RpmPushItem( name="walrus-5.21-1.noarch.rpm", sha256sum= "e837a635cc99f967a70f34b268baa52e0f412c1502e08e924ff5b09f1f9573f2", src=os.path.join(data_path, "staged-mixed/dest1/RPMS/walrus-5.21-1.noarch.rpm"), ) rpm2 = RpmPushItem( name="test-srpm01-1.0-1.src.rpm", sha256sum= "54cc4713fe704dfc7a4fd5b398f834ceb6a692f53b0c6aefaf89d88417b4c51d", src=os.path.join(data_path, "staged-mixed/dest1/SRPMS/test-srpm01-1.0-1.src.rpm"), ) inputs = [ # Some copies of the same RPM to different repos PulpRpmPushItem(pushsource_item=attr.evolve(rpm1, dest=["repo1"])), PulpRpmPushItem( pushsource_item=attr.evolve(rpm1, dest=["repo2", "repo3"])), # A different RPM PulpRpmPushItem(pushsource_item=attr.evolve(rpm2, dest=["repo1"])), ] # Shove 'em into the queue for item in inputs: queue.put(item) # Put this so that iteration will end queue.put(Phase.FINISHED) # Let the phase run with phase: pass # It should not have failed assert not ctx.has_error # Should have called upload exactly once per file. assert sorted(client_wrapper.uploads) == [ ("rpm", rpm1.src), ("rpm", rpm2.src), ] # Look at the pulp units created. outputs = {} while True: item = phase.out_queue.get() if item is phase.FINISHED: break outputs.setdefault(item.pushsource_item.name, []).append(item.pulp_unit) # Although there were two items dealing with this RPM... assert len(outputs["walrus-5.21-1.noarch.rpm"]) == 2 # If we de-duplicate, we'll find they're actually the same unit since # upload was shared. assert len(set(outputs["walrus-5.21-1.noarch.rpm"])) == 1 # And the non-dupe should just work as normal. assert len(outputs["test-srpm01-1.0-1.src.rpm"]) == 1