Revision 7d272015
Added by koszko over 1 year ago
| tests/test_build.py | ||
|---|---|---|
| 10 | 10 |
import pytest |
| 11 | 11 |
import json |
| 12 | 12 |
import shutil |
| 13 |
import functools as ft |
|
| 13 | 14 |
|
| 14 | 15 |
from tempfile import TemporaryDirectory |
| 15 | 16 |
from pathlib import Path, PurePosixPath |
| ... | ... | |
| 255 | 256 |
|
| 256 | 257 |
yield sample_source |
| 257 | 258 |
|
| 259 |
def collect(list): |
|
| 260 |
"""Decorate function by appending it to the specified list.""" |
|
| 261 |
def decorator(function): |
|
| 262 |
"""The actual decorator that will be applied.""" |
|
| 263 |
list.append(function) |
|
| 264 |
return function |
|
| 265 |
|
|
| 266 |
return decorator |
|
| 267 |
|
|
| 258 | 268 |
variant_makers = [] |
| 259 |
def variant_maker(function): |
|
| 260 |
"""Decorate function by placing it in variant_makers array.""" |
|
| 261 |
variant_makers.append(function) |
|
| 262 |
return function |
|
| 263 | 269 |
|
| 264 |
@variant_maker
|
|
| 270 |
@collect(variant_makers)
|
|
| 265 | 271 |
def sample_source_change_index_json(monkeypatch, sample_source): |
| 266 | 272 |
""" |
| 267 | 273 |
Return a non-standard path for index.json. Ensure parent directories exist. |
| ... | ... | |
| 272 | 278 |
path.parent.mkdir() |
| 273 | 279 |
return path |
| 274 | 280 |
|
| 275 |
@variant_maker
|
|
| 281 |
@collect(variant_makers)
|
|
| 276 | 282 |
def sample_source_add_comments(monkeypatch, sample_source): |
| 277 | 283 |
"""Add index.json comments that should be preserved.""" |
| 278 | 284 |
for dictionary in index_obj, *index_obj['definitions'], *expected: |
| 279 | 285 |
monkeypatch.setitem(dictionary, 'comment', 'index.json comment') |
| 280 | 286 |
|
| 281 |
@variant_maker
|
|
| 287 |
@collect(variant_makers)
|
|
| 282 | 288 |
def sample_source_remove_spdx(monkeypatch, sample_source): |
| 283 | 289 |
"""Remove spdx report generation.""" |
| 284 | 290 |
monkeypatch.delitem(index_obj, 'reuse_generate_spdx_report') |
| ... | ... | |
| 297 | 303 |
# raise an error if called. |
| 298 | 304 |
(sample_source / 'mock_reuse_missing').touch() |
| 299 | 305 |
|
| 300 |
@variant_maker
|
|
| 306 |
@collect(variant_makers)
|
|
| 301 | 307 |
def sample_source_remove_additional_files(monkeypatch, sample_source): |
| 302 | 308 |
"""Use default value ([]) for 'additionall_files' property.""" |
| 303 | 309 |
monkeypatch.delitem(index_obj, 'additional_files') |
| ... | ... | |
| 305 | 311 |
for name in 'README.txt', 'README.txt.license', '.reuse/dep5': |
| 306 | 312 |
monkeypatch.delitem(src_files, name) |
| 307 | 313 |
|
| 308 |
@variant_maker
|
|
| 314 |
@collect(variant_makers)
|
|
| 309 | 315 |
def sample_source_remove_script(monkeypatch, sample_source): |
| 310 | 316 |
"""Use default value ([]) for 'scripts' property in one of the resources.""" |
| 311 | 317 |
monkeypatch.delitem(index_obj['definitions'][2], 'scripts') |
| ... | ... | |
| 315 | 321 |
for files in dist_files, src_files: |
| 316 | 322 |
monkeypatch.delitem(files, 'message.js') |
| 317 | 323 |
|
| 318 |
@variant_maker
|
|
| 324 |
@collect(variant_makers)
|
|
| 319 | 325 |
def sample_source_remove_payloads(monkeypatch, sample_source): |
| 320 | 326 |
"""Use default value ({}) for 'payloads' property in mapping."""
|
| 321 | 327 |
monkeypatch.delitem(index_obj['definitions'][0], 'payloads') |
| 322 | 328 |
|
| 323 | 329 |
monkeypatch.setitem(expected_mapping, 'payloads', {})
|
| 324 | 330 |
|
| 325 |
@variant_maker
|
|
| 331 |
@collect(variant_makers)
|
|
| 326 | 332 |
def sample_source_remove_uuids(monkeypatch, sample_source): |
| 327 | 333 |
"""Don't use UUIDs (they are optional).""" |
| 328 | 334 |
for definition in index_obj['definitions']: |
| ... | ... | |
| 332 | 338 |
if 'uuid' in description: |
| 333 | 339 |
monkeypatch.delitem(description, 'uuid') |
| 334 | 340 |
|
| 335 |
@variant_maker
|
|
| 341 |
@collect(variant_makers)
|
|
| 336 | 342 |
def sample_source_add_extra_props(monkeypatch, sample_source): |
| 337 | 343 |
"""Add some unrecognized properties that should be stripped.""" |
| 338 | 344 |
to_process = [index_obj] |
| ... | ... | |
| 346 | 352 |
if k != 'payloads') |
| 347 | 353 |
monkeypatch.setitem(processed, 'spurious_property', 'some_value') |
| 348 | 354 |
|
| 349 |
@variant_maker
|
|
| 355 |
@collect(variant_makers)
|
|
| 350 | 356 |
def sample_source_make_version_2(monkeypatch, sample_source, |
| 351 | 357 |
expected_documents_to_modify=[]): |
| 352 |
"""Increase sources' schema version from to 2.""" |
|
| 358 |
"""Increase sources' schema version from 1 to 2."""
|
|
| 353 | 359 |
for obj in index_obj, *expected_documents_to_modify: |
| 354 | 360 |
monkeypatch.setitem(obj, '$schema', obj['$schema'].replace('1', '2'))
|
| 355 | 361 |
|
| 356 |
@variant_maker |
|
| 357 |
def sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=True): |
|
| 362 |
permission_variant_makers = [] |
|
| 363 |
|
|
| 364 |
@collect(permission_variant_makers) |
|
| 365 |
def sample_source_bool_perm_ignored(permission, monkeypatch, sample_source, |
|
| 366 |
value=True): |
|
| 358 | 367 |
""" |
| 359 |
Specify CORS bypass permissions in sources, but keep sources' schema version
|
|
| 368 |
Specify a boolean permissions in sources, but keep sources' schema version
|
|
| 360 | 369 |
at 1. |
| 361 | 370 |
""" |
| 362 | 371 |
for definition in index_obj['definitions']: |
| 363 |
monkeypatch.setitem(definition, 'permissions', {'cors_bypass': value})
|
|
| 372 |
monkeypatch.setitem(definition, 'permissions', {permission: value})
|
|
| 364 | 373 |
|
| 365 |
@variant_maker
|
|
| 366 |
def sample_source_cors_bypass(monkeypatch, sample_source):
|
|
| 367 |
"""Specify CORS bypass permissions in sources."""
|
|
| 368 |
sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=True)
|
|
| 374 |
@collect(permission_variant_makers)
|
|
| 375 |
def sample_source_bool_perm(permission, monkeypatch, sample_source):
|
|
| 376 |
"""Specify a boolean permission in sources."""
|
|
| 377 |
sample_source_bool_perm_ignored(permission, monkeypatch, sample_source)
|
|
| 369 | 378 |
sample_source_make_version_2(monkeypatch, sample_source, expected_items) |
| 370 | 379 |
|
| 371 | 380 |
for obj in expected_items: |
| 372 |
monkeypatch.setitem(obj, 'permissions', {'cors_bypass': True})
|
|
| 381 |
monkeypatch.setitem(obj, 'permissions', {permission: True})
|
|
| 373 | 382 |
|
| 374 |
@variant_maker
|
|
| 375 |
def sample_source_cors_bypass_defaults(monkeypatch, sample_source):
|
|
| 383 |
@collect(permission_variant_makers)
|
|
| 384 |
def sample_source_bool_perm_defaults(permission, monkeypatch, sample_source):
|
|
| 376 | 385 |
""" |
| 377 |
Specify CORS bypass permissions in sources but use the default value |
|
| 378 |
("False").
|
|
| 386 |
Specify a boolean permission in sources but use the default value ("False").
|
|
| 379 | 387 |
""" |
| 380 |
sample_source_cors_bypass_ignored(monkeypatch, sample_source, value=False) |
|
| 388 |
sample_source_bool_perm_ignored(permission, monkeypatch, sample_source, |
|
| 389 |
value=False) |
|
| 381 | 390 |
sample_source_make_version_2(monkeypatch, sample_source) |
| 382 | 391 |
|
| 383 |
@variant_maker |
|
| 392 |
for permission in 'cors_bypass', 'eval': |
|
| 393 |
for variant_maker in permission_variant_makers: |
|
| 394 |
variant_makers.append(ft.partial(variant_maker, permission)) |
|
| 395 |
|
|
| 396 |
@collect(variant_makers) |
|
| 384 | 397 |
def sample_source_req_mappings_ignored(monkeypatch, sample_source, |
| 385 | 398 |
value=[{'identifier': 'mapping-dep'}]):
|
| 386 | 399 |
""" |
| ... | ... | |
| 389 | 402 |
for definition in index_obj['definitions']: |
| 390 | 403 |
monkeypatch.setitem(definition, 'required_mappings', value); |
| 391 | 404 |
|
| 392 |
@variant_maker
|
|
| 405 |
@collect(variant_makers)
|
|
| 393 | 406 |
def sample_source_req_mappings(monkeypatch, sample_source): |
| 394 | 407 |
"""Specify dependencies on mappings.""" |
| 395 | 408 |
sample_source_req_mappings_ignored(monkeypatch, sample_source) |
| ... | ... | |
| 399 | 412 |
monkeypatch.setitem(obj, 'required_mappings', |
| 400 | 413 |
[{'identifier': 'mapping-dep'}])
|
| 401 | 414 |
|
| 402 |
@variant_maker
|
|
| 415 |
@collect(variant_makers)
|
|
| 403 | 416 |
def sample_source_req_mappings_defaults(monkeypatch, sample_source): |
| 404 | 417 |
"""Specify dependencies of a mapping, but use the default value ("[]")."""
|
| 405 | 418 |
sample_source_req_mappings_ignored(monkeypatch, sample_source, value=[]) |
| 406 | 419 |
sample_source_make_version_2(monkeypatch, sample_source) |
| 407 | 420 |
|
| 408 |
@variant_maker
|
|
| 421 |
@collect(variant_makers)
|
|
| 409 | 422 |
def sample_source_combined_def(monkeypatch, sample_source): |
| 410 | 423 |
"""Define mapping and resource together.""" |
| 411 | 424 |
sample_source_make_version_2(monkeypatch, sample_source) |
| ... | ... | |
| 432 | 445 |
monkeypatch.setitem(expected_source_description['definitions'][0], |
| 433 | 446 |
'version', new_mapping_ver) |
| 434 | 447 |
|
| 435 |
@variant_maker
|
|
| 448 |
@collect(variant_makers)
|
|
| 436 | 449 |
def sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source, |
| 437 | 450 |
min_ver=[1, 2], max_ver=[1, 2]): |
| 438 | 451 |
""" |
| ... | ... | |
| 443 | 456 |
monkeypatch.setitem(mapping_def, 'min_haketilo_version', min_ver) |
| 444 | 457 |
monkeypatch.setitem(mapping_def, 'max_haketilo_version', max_ver) |
| 445 | 458 |
|
| 446 |
@variant_maker
|
|
| 459 |
@collect(variant_makers)
|
|
| 447 | 460 |
def sample_source_minmax_haketilo_ver(monkeypatch, sample_source): |
| 448 | 461 |
"""Specify version constraints on Haketilo.""" |
| 449 | 462 |
sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source) |
| ... | ... | |
| 452 | 465 |
monkeypatch.setitem(expected_mapping, 'min_haketilo_version', [1, 2]) |
| 453 | 466 |
monkeypatch.setitem(expected_mapping, 'max_haketilo_version', [1, 2]) |
| 454 | 467 |
|
| 455 |
@variant_maker
|
|
| 468 |
@collect(variant_makers)
|
|
| 456 | 469 |
def sample_source_minmax_haketilo_ver_default(monkeypatch, sample_source): |
| 457 | 470 |
"""Specify version constraints on Haketilo, but use default values.""" |
| 458 | 471 |
sample_source_minmax_haketilo_ver_ignored(monkeypatch, sample_source, |
| ... | ... | |
| 466 | 479 |
'othersystem/other-something.tar.gz' |
| 467 | 480 |
] |
| 468 | 481 |
|
| 469 |
@variant_maker
|
|
| 482 |
@collect(variant_makers)
|
|
| 470 | 483 |
def sample_source_add_piggyback_ignored(monkeypatch, sample_source, |
| 471 | 484 |
extra_build_args={}):
|
| 472 | 485 |
""" |
| ... | ... | |
| 484 | 497 |
'dependencies': False |
| 485 | 498 |
}) |
| 486 | 499 |
|
| 487 |
@variant_maker
|
|
| 500 |
@collect(variant_makers)
|
|
| 488 | 501 |
def sample_source_add_piggyback(monkeypatch, sample_source, |
| 489 | 502 |
extra_build_args={}):
|
| 490 | 503 |
"""Add piggybacked foreign system packages.""" |
| ... | ... | |
| 528 | 541 |
archive_path.parent.mkdir(parents=True, exist_ok=True) |
| 529 | 542 |
archive_path.write_text(f'dummy {archive_path.name}')
|
| 530 | 543 |
|
| 531 |
@variant_maker
|
|
| 544 |
@collect(variant_makers)
|
|
| 532 | 545 |
def sample_source_add_piggyback_pass_archives(monkeypatch, sample_source): |
| 533 | 546 |
""" |
| 534 | 547 |
Add piggybacked foreign system packages, use pre-downloaded foreign package |
| ... | ... | |
| 542 | 555 |
sample_source_add_piggyback(monkeypatch, sample_source, |
| 543 | 556 |
{'piggyback_files': foreign_packages_dir})
|
| 544 | 557 |
|
| 545 |
@variant_maker
|
|
| 558 |
@collect(variant_makers)
|
|
| 546 | 559 |
def sample_source_add_piggyback_find_archives(monkeypatch, sample_source): |
| 547 | 560 |
""" |
| 548 | 561 |
Add piggybacked foreign system packages, use pre-downloaded foreign package |
| ... | ... | |
| 555 | 568 |
|
| 556 | 569 |
sample_source_add_piggyback(monkeypatch, sample_source) |
| 557 | 570 |
|
| 558 |
@variant_maker
|
|
| 571 |
@collect(variant_makers)
|
|
| 559 | 572 |
def sample_source_add_piggyback_no_download(monkeypatch, sample_source, |
| 560 | 573 |
pass_directory_to_build=False): |
| 561 | 574 |
""" |
| ... | ... | |
| 678 | 691 |
try_validate('api_source_description', expected_source_description)
|
| 679 | 692 |
|
| 680 | 693 |
error_makers = [] |
| 681 |
def error_maker(function): |
|
| 682 |
"""Decorate function by placing it in error_makers array.""" |
|
| 683 |
error_makers.append(function) |
|
| 684 | 694 |
|
| 685 |
@error_maker
|
|
| 695 |
@collect(error_makers)
|
|
| 686 | 696 |
def sample_source_error_missing_file(monkeypatch, sample_source): |
| 687 | 697 |
""" |
| 688 | 698 |
Modify index.json to expect missing report.spdx file and cause an error. |
| ... | ... | |
| 690 | 700 |
monkeypatch.delitem(index_obj, 'reuse_generate_spdx_report') |
| 691 | 701 |
return FileReferenceError, '^referenced_file_report.spdx_missing$' |
| 692 | 702 |
|
| 693 |
@error_maker
|
|
| 703 |
@collect(error_makers)
|
|
| 694 | 704 |
def sample_source_error_index_schema(monkeypatch, sample_source): |
| 695 | 705 |
"""Modify index.json to be incompliant with the schema.""" |
| 696 | 706 |
monkeypatch.delitem(index_obj, 'definitions') |
| 697 | 707 |
return ValidationError, |
| 698 | 708 |
|
| 699 |
@error_maker
|
|
| 709 |
@collect(error_makers)
|
|
| 700 | 710 |
def sample_source_error_bad_comment(monkeypatch, sample_source): |
| 701 | 711 |
"""Modify index.json to have an invalid '/' in it.""" |
| 702 | 712 |
return json.JSONDecodeError, '^bad_comment: .*', \ |
| 703 | 713 |
json.dumps(index_obj) + '/something\n' |
| 704 | 714 |
|
| 705 |
@error_maker
|
|
| 715 |
@collect(error_makers)
|
|
| 706 | 716 |
def sample_source_error_bad_json(monkeypatch, sample_source): |
| 707 | 717 |
"""Modify index.json to not be valid json even after comment stripping.""" |
| 708 | 718 |
return json.JSONDecodeError, '', json.dumps(index_obj) + '???\n' |
| 709 | 719 |
|
| 710 |
@error_maker
|
|
| 720 |
@collect(error_makers)
|
|
| 711 | 721 |
def sample_source_error_missing_reuse(monkeypatch, sample_source): |
| 712 | 722 |
"""Cause mocked reuse process invocation to fail with FileNotFoundError.""" |
| 713 | 723 |
(sample_source / 'mock_reuse_missing').touch() |
| 714 | 724 |
return build.ReuseError, '^couldnt_execute_reuse_is_it_installed$' |
| 715 | 725 |
|
| 716 |
@error_maker
|
|
| 726 |
@collect(error_makers)
|
|
| 717 | 727 |
def sample_source_error_missing_license(monkeypatch, sample_source): |
| 718 | 728 |
"""Remove a file to make package REUSE-incompliant.""" |
| 719 | 729 |
(sample_source / 'README.txt.license').unlink() |
| ... | ... | |
| 733 | 743 |
|
| 734 | 744 |
return build.ReuseError, error_regex |
| 735 | 745 |
|
| 736 |
@error_maker
|
|
| 746 |
@collect(error_makers)
|
|
| 737 | 747 |
def sample_source_error_file_outside(monkeypatch, sample_source): |
| 738 | 748 |
"""Make index.json illegally reference a file outside srcdir.""" |
| 739 | 749 |
new_list = [*index_obj['copyright'], {'file': '../abc'}]
|
| 740 | 750 |
monkeypatch.setitem(index_obj, 'copyright', new_list) |
| 741 | 751 |
return FileReferenceError, '^path_contains_double_dot_\\.\\./abc$' |
| 742 | 752 |
|
| 743 |
@error_maker
|
|
| 753 |
@collect(error_makers)
|
|
| 744 | 754 |
def sample_source_error_reference_itself(monkeypatch, sample_source): |
| 745 | 755 |
"""Make index.json illegally reference index.json.""" |
| 746 | 756 |
new_list = [*index_obj['copyright'], {'file': 'index.json'}]
|
| 747 | 757 |
monkeypatch.setitem(index_obj, 'copyright', new_list) |
| 748 | 758 |
return FileReferenceError, '^loading_reserved_index_json$' |
| 749 | 759 |
|
| 750 |
@error_maker
|
|
| 760 |
@collect(error_makers)
|
|
| 751 | 761 |
def sample_source_error_report_excluded(monkeypatch, sample_source): |
| 752 | 762 |
""" |
| 753 | 763 |
Make index.json require generation of report.spdx but don't include it among |
| ... | ... | |
| 758 | 768 |
monkeypatch.setitem(index_obj, 'copyright', new_list) |
| 759 | 769 |
return FileReferenceError, '^report_spdx_not_in_copyright_list$' |
| 760 | 770 |
|
| 761 |
@error_maker
|
|
| 771 |
@collect(error_makers)
|
|
| 762 | 772 |
def sample_source_error_combined_unsupported(monkeypatch, sample_source): |
| 763 | 773 |
""" |
| 764 | 774 |
Define mapping and resource together but leave source schema version at 1.x |
Also available in: Unified diff
add "eval" permission