github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/pkg/cataloger/python/cataloger_test.go (about) 1 package python 2 3 import ( 4 "testing" 5 6 "github.com/nextlinux/gosbom/gosbom/file" 7 "github.com/nextlinux/gosbom/gosbom/pkg" 8 "github.com/nextlinux/gosbom/gosbom/pkg/cataloger/internal/pkgtest" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func Test_PackageCataloger(t *testing.T) { 13 tests := []struct { 14 name string 15 fixtures []string 16 expectedPackage pkg.Package 17 }{ 18 { 19 name: "egg-file-no-version", 20 fixtures: []string{"test-fixtures/no-version-py3.8.egg-info"}, 21 expectedPackage: pkg.Package{ 22 Name: "no-version", 23 PURL: "pkg:pypi/no-version", 24 Type: pkg.PythonPkg, 25 Language: pkg.Python, 26 FoundBy: "python-package-cataloger", 27 MetadataType: pkg.PythonPackageMetadataType, 28 Metadata: pkg.PythonPackageMetadata{ 29 Name: "no-version", 30 SitePackagesRootPath: "test-fixtures", 31 }, 32 }, 33 }, 34 { 35 name: "egg-info directory", 36 fixtures: []string{ 37 "test-fixtures/egg-info/PKG-INFO", 38 "test-fixtures/egg-info/RECORD", 39 "test-fixtures/egg-info/top_level.txt", 40 }, 41 expectedPackage: pkg.Package{ 42 Name: "requests", 43 Version: "2.22.0", 44 PURL: "pkg:pypi/requests@2.22.0", 45 Type: pkg.PythonPkg, 46 Language: pkg.Python, 47 Licenses: pkg.NewLicenseSet( 48 pkg.NewLicenseFromLocations("Apache 2.0", file.NewLocation("test-fixtures/egg-info/PKG-INFO")), 49 ), 50 FoundBy: "python-package-cataloger", 51 MetadataType: pkg.PythonPackageMetadataType, 52 Metadata: pkg.PythonPackageMetadata{ 53 Name: "requests", 54 Version: "2.22.0", 55 Platform: "UNKNOWN", 56 Author: "Kenneth Reitz", 57 AuthorEmail: "me@kennethreitz.org", 58 SitePackagesRootPath: "test-fixtures", 59 Files: []pkg.PythonFileRecord{ 60 {Path: "requests-2.22.0.dist-info/INSTALLER", Digest: &pkg.PythonFileDigest{"sha256", "zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg"}, Size: "4"}, 61 {Path: "requests/__init__.py", Digest: &pkg.PythonFileDigest{"sha256", "PnKCgjcTq44LaAMzB-7--B2FdewRrE8F_vjZeaG9NhA"}, Size: "3921"}, 62 {Path: "requests/__pycache__/__version__.cpython-38.pyc"}, 63 {Path: "requests/__pycache__/utils.cpython-38.pyc"}, 64 {Path: "requests/__version__.py", Digest: &pkg.PythonFileDigest{"sha256", "Bm-GFstQaFezsFlnmEMrJDe8JNROz9n2XXYtODdvjjc"}, Size: "436"}, 65 {Path: "requests/utils.py", Digest: &pkg.PythonFileDigest{"sha256", "LtPJ1db6mJff2TJSJWKi7rBpzjPS3mSOrjC9zRhoD3A"}, Size: "30049"}, 66 }, 67 TopLevelPackages: []string{"requests"}, 68 }, 69 }, 70 }, 71 { 72 name: "dist-info directory", 73 fixtures: []string{ 74 "test-fixtures/dist-info/METADATA", 75 "test-fixtures/dist-info/RECORD", 76 "test-fixtures/dist-info/top_level.txt", 77 "test-fixtures/dist-info/direct_url.json", 78 }, 79 expectedPackage: pkg.Package{ 80 Name: "Pygments", 81 Version: "2.6.1", 82 PURL: "pkg:pypi/Pygments@2.6.1?vcs_url=git+https://github.com/python-test/test.git%40aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 83 Type: pkg.PythonPkg, 84 Language: pkg.Python, 85 Licenses: pkg.NewLicenseSet( 86 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/dist-info/METADATA")), 87 ), 88 FoundBy: "python-package-cataloger", 89 MetadataType: pkg.PythonPackageMetadataType, 90 Metadata: pkg.PythonPackageMetadata{ 91 Name: "Pygments", 92 Version: "2.6.1", 93 Platform: "any", 94 Author: "Georg Brandl", 95 AuthorEmail: "georg@python.org", 96 SitePackagesRootPath: "test-fixtures", 97 Files: []pkg.PythonFileRecord{ 98 {Path: "../../../bin/pygmentize", Digest: &pkg.PythonFileDigest{"sha256", "dDhv_U2jiCpmFQwIRHpFRLAHUO4R1jIJPEvT_QYTFp8"}, Size: "220"}, 99 {Path: "Pygments-2.6.1.dist-info/AUTHORS", Digest: &pkg.PythonFileDigest{"sha256", "PVpa2_Oku6BGuiUvutvuPnWGpzxqFy2I8-NIrqCvqUY"}, Size: "8449"}, 100 {Path: "Pygments-2.6.1.dist-info/RECORD"}, 101 {Path: "pygments/__pycache__/__init__.cpython-38.pyc"}, 102 {Path: "pygments/util.py", Digest: &pkg.PythonFileDigest{"sha256", "586xXHiJGGZxqk5PMBu3vBhE68DLuAe5MBARWrSPGxA"}, Size: "10778"}, 103 104 {Path: "pygments/x_util.py", Digest: &pkg.PythonFileDigest{"sha256", "qpzzsOW31KT955agi-7NS--90I0iNiJCyLJQnRCHgKI="}, Size: "10778"}, 105 }, 106 TopLevelPackages: []string{"pygments", "something_else"}, 107 DirectURLOrigin: &pkg.PythonDirectURLOriginInfo{URL: "https://github.com/python-test/test.git", VCS: "git", CommitID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, 108 }, 109 }, 110 }, 111 { 112 name: "malformed-record", 113 fixtures: []string{ 114 "test-fixtures/malformed-record/dist-info/METADATA", 115 "test-fixtures/malformed-record/dist-info/RECORD", 116 }, 117 expectedPackage: pkg.Package{ 118 Name: "Pygments", 119 Version: "2.6.1", 120 PURL: "pkg:pypi/Pygments@2.6.1", 121 Type: pkg.PythonPkg, 122 Language: pkg.Python, 123 Licenses: pkg.NewLicenseSet( 124 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/malformed-record/dist-info/METADATA")), 125 ), 126 FoundBy: "python-package-cataloger", 127 MetadataType: pkg.PythonPackageMetadataType, 128 Metadata: pkg.PythonPackageMetadata{ 129 Name: "Pygments", 130 Version: "2.6.1", 131 Platform: "any", 132 Author: "Georg Brandl", 133 AuthorEmail: "georg@python.org", 134 SitePackagesRootPath: "test-fixtures/malformed-record", 135 Files: []pkg.PythonFileRecord{ 136 {Path: "flask/json/tag.py", Digest: &pkg.PythonFileDigest{"sha256", "9ehzrmt5k7hxf7ZEK0NOs3swvQyU9fWNe-pnYe69N60"}, Size: "8223"}, 137 {Path: "../../Scripts/flask.exe", Digest: &pkg.PythonFileDigest{"sha256", "mPrbVeZCDX20himZ_bRai1nCs_tgr7jHIOGZlcgn-T4"}, Size: "93063"}, 138 {Path: "../../Scripts/flask.exe", Size: "89470", Digest: &pkg.PythonFileDigest{"sha256", "jvqh4N3qOqXLlq40i6ZOLCY9tAOwfwdzIpLDYhRjoqQ"}}, 139 {Path: "Flask-1.0.2.dist-info/INSTALLER", Size: "4", Digest: &pkg.PythonFileDigest{"sha256", "zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg"}}, 140 }, 141 }, 142 }, 143 }, 144 { 145 // in cases where the metadata file is available and the record is not we should still record there is a package 146 // additionally empty top_level.txt files should not result in an error 147 name: "partial dist-info directory", 148 fixtures: []string{"test-fixtures/partial.dist-info/METADATA"}, 149 expectedPackage: pkg.Package{ 150 Name: "Pygments", 151 Version: "2.6.1", 152 PURL: "pkg:pypi/Pygments@2.6.1", 153 Type: pkg.PythonPkg, 154 Language: pkg.Python, 155 Licenses: pkg.NewLicenseSet( 156 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/partial.dist-info/METADATA")), 157 ), 158 FoundBy: "python-package-cataloger", 159 MetadataType: pkg.PythonPackageMetadataType, 160 Metadata: pkg.PythonPackageMetadata{ 161 Name: "Pygments", 162 Version: "2.6.1", 163 Platform: "any", 164 Author: "Georg Brandl", 165 AuthorEmail: "georg@python.org", 166 SitePackagesRootPath: "test-fixtures", 167 }, 168 }, 169 }, 170 { 171 name: "egg-info regular file", 172 fixtures: []string{"test-fixtures/test.egg-info"}, 173 expectedPackage: pkg.Package{ 174 Name: "requests", 175 Version: "2.22.0", 176 PURL: "pkg:pypi/requests@2.22.0", 177 Type: pkg.PythonPkg, 178 Language: pkg.Python, 179 Licenses: pkg.NewLicenseSet( 180 pkg.NewLicenseFromLocations("Apache 2.0", file.NewLocation("test-fixtures/test.egg-info")), 181 ), 182 FoundBy: "python-package-cataloger", 183 MetadataType: pkg.PythonPackageMetadataType, 184 Metadata: pkg.PythonPackageMetadata{ 185 Name: "requests", 186 Version: "2.22.0", 187 Platform: "UNKNOWN", 188 Author: "Kenneth Reitz", 189 AuthorEmail: "me@kennethreitz.org", 190 SitePackagesRootPath: "test-fixtures", 191 }, 192 }, 193 }, 194 } 195 196 for _, test := range tests { 197 t.Run(test.name, func(t *testing.T) { 198 resolver := file.NewMockResolverForPaths(test.fixtures...) 199 200 locations, err := resolver.FilesByPath(test.fixtures...) 201 require.NoError(t, err) 202 203 test.expectedPackage.Locations = file.NewLocationSet(locations...) 204 205 pkgtest.NewCatalogTester(). 206 WithResolver(resolver). 207 Expects([]pkg.Package{test.expectedPackage}, nil). 208 TestCataloger(t, NewPythonPackageCataloger()) 209 }) 210 } 211 } 212 213 func Test_PackageCataloger_IgnorePackage(t *testing.T) { 214 tests := []struct { 215 MetadataFixture string 216 }{ 217 { 218 MetadataFixture: "test-fixtures/Python-2.7.egg-info", 219 }, 220 { 221 MetadataFixture: "test-fixtures/empty-1.0.0-py3.8.egg-info", 222 }, 223 } 224 225 for _, test := range tests { 226 t.Run(test.MetadataFixture, func(t *testing.T) { 227 resolver := file.NewMockResolverForPaths(test.MetadataFixture) 228 229 actual, _, err := NewPythonPackageCataloger().Catalog(resolver) 230 require.NoError(t, err) 231 232 if len(actual) != 0 { 233 t.Fatalf("Expected 0 packages but found: %d", len(actual)) 234 } 235 }) 236 } 237 } 238 239 func Test_IndexCataloger_Globs(t *testing.T) { 240 tests := []struct { 241 name string 242 fixture string 243 expected []string 244 }{ 245 { 246 name: "obtain index files", 247 fixture: "test-fixtures/glob-paths", 248 expected: []string{ 249 "src/requirements.txt", 250 "src/extra-requirements.txt", 251 "src/requirements-dev.txt", 252 "src/1-requirements-dev.txt", 253 "src/setup.py", 254 "src/poetry.lock", 255 "src/Pipfile.lock", 256 }, 257 }, 258 } 259 260 for _, test := range tests { 261 t.Run(test.name, func(t *testing.T) { 262 pkgtest.NewCatalogTester(). 263 FromDirectory(t, test.fixture). 264 ExpectsResolverContentQueries(test.expected). 265 TestCataloger(t, NewPythonIndexCataloger()) 266 }) 267 } 268 } 269 270 func Test_PackageCataloger_Globs(t *testing.T) { 271 tests := []struct { 272 name string 273 fixture string 274 expected []string 275 }{ 276 { 277 name: "obtain index files", 278 fixture: "test-fixtures/glob-paths", 279 expected: []string{ 280 "site-packages/x.dist-info/METADATA", 281 "site-packages/y.egg-info/PKG-INFO", 282 "site-packages/z.egg-info", 283 }, 284 }, 285 } 286 287 for _, test := range tests { 288 t.Run(test.name, func(t *testing.T) { 289 pkgtest.NewCatalogTester(). 290 FromDirectory(t, test.fixture). 291 ExpectsResolverContentQueries(test.expected). 292 TestCataloger(t, NewPythonPackageCataloger()) 293 }) 294 } 295 }