@@ -2556,6 +2556,30 @@ def test_package_model_inferred_url_property(self):
25562556 expected = "https://github.com/package-url/packageurl-python/tree/v0.10.4"
25572557 self .assertEqual (expected , package1 .inferred_url )
25582558
2559+ @mock .patch ("dejacode_toolkit.purldb.PurlDB.find_packages" )
2560+ def test_package_model_get_purldb_entries (self , mock_find_packages ):
2561+ purl = "pkg:pypi/django@3.0"
2562+ package1 = make_package (self .dataspace , package_url = purl )
2563+ purldb_entry1 = {
2564+ "purl" : purl ,
2565+ "type" : "pypi" ,
2566+ "name" : "django" ,
2567+ "version" : "3.0" ,
2568+ }
2569+ purldb_entry2 = {
2570+ "purl" : "pkg:pypi/django" ,
2571+ "type" : "pypi" ,
2572+ "name" : "django" ,
2573+ }
2574+
2575+ mock_find_packages .return_value = None
2576+ purldb_entries = package1 .get_purldb_entries (user = self .user )
2577+
2578+ mock_find_packages .return_value = [purldb_entry1 , purldb_entry2 ]
2579+ purldb_entries = package1 .get_purldb_entries (user = self .user )
2580+ # The purldb_entry2 is excluded as the PURL differs
2581+ self .assertEqual ([purldb_entry1 ], purldb_entries )
2582+
25592583 @mock .patch ("component_catalog.models.Package.get_purldb_entries" )
25602584 def test_package_model_update_from_purldb (self , mock_get_purldb_entries ):
25612585 purldb_entry = {
@@ -2577,9 +2601,9 @@ def test_package_model_update_from_purldb(self, mock_get_purldb_entries):
25772601 }
25782602
25792603 mock_get_purldb_entries .return_value = [purldb_entry ]
2580- package1 = Package .objects .create (
2604+ package1 = make_package (
2605+ self .dataspace ,
25812606 filename = "package" ,
2582- dataspace = self .dataspace ,
25832607 # "unknown" values are overrided
25842608 declared_license_expression = "unknown" ,
25852609 )
@@ -2607,6 +2631,68 @@ def test_package_model_update_from_purldb(self, mock_get_purldb_entries):
26072631 for field_name in updated_fields :
26082632 self .assertEqual (purldb_entry [field_name ], getattr (package1 , field_name ))
26092633
2634+ @mock .patch ("component_catalog.models.Package.get_purldb_entries" )
2635+ def test_package_model_update_from_purldb_multiple_entries (self , mock_get_purldb_entries ):
2636+ purldb_entry1 = {
2637+ "uuid" : "326aa7a8-4f28-406d-89f9-c1404916925b" ,
2638+ "purl" : "pkg:pypi/django@3.0" ,
2639+ "type" : "pypi" ,
2640+ "name" : "django" ,
2641+ "version" : "3.0" ,
2642+ "keywords" : ["Keyword1" , "Keyword2" ],
2643+ "filename" : "Django-3.0.tar.gz" ,
2644+ "download_url" : "https://files.pythonhosted.org/packages/38/Django-3.0.tar.gz" ,
2645+ }
2646+ purldb_entry2 = {
2647+ "uuid" : "e133e70b-8dd3-4cf1-9711-72b1f57523a0" ,
2648+ "purl" : "pkg:pypi/django@3.0" ,
2649+ "type" : "pypi" ,
2650+ "name" : "django" ,
2651+ "version" : "3.0" ,
2652+ "primary_language" : "Python" ,
2653+ "keywords" : ["Keyword1" , "Keyword2" ],
2654+ "download_url" : "https://another.url/Django-3.0.tar.gz" ,
2655+ }
2656+
2657+ mock_get_purldb_entries .return_value = [purldb_entry1 , purldb_entry2 ]
2658+ package1 = make_package (self .dataspace , package_url = "pkg:pypi/django@3.0" )
2659+ updated_fields = package1 .update_from_purldb (self .user )
2660+ expected = ["filename" , "keywords" , "primary_language" ]
2661+ self .assertEqual (expected , sorted (updated_fields ))
2662+ self .assertEqual ("Django-3.0.tar.gz" , package1 .filename )
2663+ self .assertEqual (["Keyword1" , "Keyword2" ], package1 .keywords )
2664+ self .assertEqual ("Python" , package1 .primary_language )
2665+
2666+ @mock .patch ("component_catalog.models.Package.get_purldb_entries" )
2667+ def test_package_model_update_from_purldb_duplicate_exception (self , mock_get_purldb_entries ):
2668+ package_url = "pkg:pypi/django@3.0"
2669+ download_url = "https://files.pythonhosted.org/packages/38/Django-3.0.tar.gz"
2670+ purldb_entry = {
2671+ "purl" : package_url ,
2672+ "type" : "pypi" ,
2673+ "name" : "django" ,
2674+ "version" : "3.0" ,
2675+ "download_url" : download_url ,
2676+ "description" : "This value will be updated" ,
2677+ "md5" : "This value is skipped" ,
2678+ "sha1" : "This value is skipped" ,
2679+ }
2680+ mock_get_purldb_entries .return_value = [purldb_entry ]
2681+
2682+ # 2 packages with the same "pkg:pypi/django@3.0" PURL:
2683+ # - 1 with a `download_url` value
2684+ # - 1 without a `download_url` value
2685+ make_package (self .dataspace , package_url = package_url , download_url = download_url )
2686+ package_no_download_url = make_package (self .dataspace , package_url = package_url )
2687+
2688+ # Updating the package with the `download_url` from the purldb_entry data
2689+ # would violates the unique constraint.
2690+ # This is handle properly by update_from_purldb.
2691+ updated_fields = package_no_download_url .update_from_purldb (self .user )
2692+ self .assertEqual (["description" ], updated_fields )
2693+ package_no_download_url .refresh_from_db ()
2694+ self .assertEqual (purldb_entry ["description" ], package_no_download_url .description )
2695+
26102696 def test_package_model_vulnerability_queryset_mixin (self ):
26112697 package1 = make_package (self .dataspace , is_vulnerable = True )
26122698 package2 = make_package (self .dataspace )
0 commit comments