diff --git a/productmd/composeinfo.py b/productmd/composeinfo.py index bf853cc..a5d0a38 100644 --- a/productmd/composeinfo.py +++ b/productmd/composeinfo.py @@ -838,9 +838,14 @@ def _serialize_v2(self, data): field = getattr(self, name) value = field.get(arch, None) if value: - # Use stored Location if available (round-trip) - loc = self._locations.get(name, {}).get(arch, None) - if loc is not None: + # Check if value is already a Location object (direct assignment) + if isinstance(value, Location): + # User assigned a Location directly - use it and store for round-trip + self._locations.setdefault(name, {})[arch] = value + paths.setdefault(name, {})[arch] = value.serialize() + # Use stored Location if available (round-trip from deserialization) + elif name in self._locations and arch in self._locations[name]: + loc = self._locations[name][arch] paths.setdefault(name, {})[arch] = loc.serialize() else: # Synthesize Location from path string diff --git a/tests/test_composeinfo_v2.py b/tests/test_composeinfo_v2.py index 42336c3..967c422 100644 --- a/tests/test_composeinfo_v2.py +++ b/tests/test_composeinfo_v2.py @@ -413,3 +413,73 @@ def test_no_paths_variant(self): data = {} ci.serialize(data, force_version=version) assert "Server" in data["payload"]["variants"] + + +class TestVariantPathsLocationAssignment: + """Tests for issue #227: assigning Location objects to variant paths.""" + + def test_assign_location_object_to_variant_path(self): + """Test that assigning a Location object directly works as expected.""" + ci = _create_composeinfo() + _add_server_variant(ci) + + # Create a Location with different url and local_path + loc = Location( + url="https://pulp.example.com/pulp/content/Server/x86_64", + local_path="Server/x86_64/os", + size=1234567, + checksum="sha256:" + "a" * 64, + ) + + # This should work - directly assign Location to repository path + ci.variants["Server"].paths.repository["x86_64"] = loc + + # Verify the assignment worked correctly + # Getting back should return the Location object + stored_loc = ci.variants["Server"].paths.repository["x86_64"] + assert isinstance(stored_loc, Location) + assert stored_loc.url == "https://pulp.example.com/pulp/content/Server/x86_64" + assert stored_loc.local_path == "Server/x86_64/os" + assert stored_loc.size == 1234567 + assert stored_loc.checksum == "sha256:" + "a" * 64 + + def test_assign_string_to_variant_path_backward_compatible(self): + """Test that assigning a string still works (backward compatibility).""" + ci = _create_composeinfo() + _add_server_variant(ci) + + # Assign a string (backward compatible behavior) + ci.variants["Server"].paths.repository["x86_64"] = "Server/x86_64/os" + + # Verify the path is set + assert ci.variants["Server"].paths.repository["x86_64"] == "Server/x86_64/os" + + # No Location should be stored (v1.x behavior) + paths = ci.variants["Server"].paths + assert "repository" not in paths._locations or "x86_64" not in paths._locations.get("repository", {}) + + def test_location_assignment_serializes_correctly(self): + """Test that assigned Location objects serialize correctly in v2.0.""" + ci = _create_composeinfo() + _add_server_variant(ci) + + # Assign Location using direct assignment + loc = Location( + url="https://cdn.example.com/Server/x86_64/os", + local_path="Server/x86_64/os", + size=5555, + checksum="sha256:" + "c" * 64, + ) + ci.variants["Server"].paths.repository["x86_64"] = loc + + # Serialize as v2.0 + data = {} + ci.serialize(data, force_version=VERSION_2_0) + + # Check serialized data + repo = data["payload"]["variants"]["Server"]["paths"]["repository"]["x86_64"] + assert isinstance(repo, dict) + assert repo["url"] == "https://cdn.example.com/Server/x86_64/os" + assert repo["local_path"] == "Server/x86_64/os" + assert repo["size"] == 5555 + assert repo["checksum"] == "sha256:" + "c" * 64