|
| 1 | +from unittest.mock import AsyncMock, MagicMock |
| 2 | + |
1 | 3 | import pytest |
2 | 4 | from fhirpy.base.exceptions import OperationOutcome |
3 | 5 |
|
| 6 | +from app.sdc.assemble import assemble |
4 | 7 | from tests.factories import ( |
5 | 8 | create_address_questionnaire, |
6 | 9 | create_questionnaire, |
|
9 | 12 | make_initial_expression_ext, |
10 | 13 | make_item_population_context_ext, |
11 | 14 | make_launch_context_ext, |
| 15 | + make_questionnaire_mapper_ext, |
| 16 | + make_source_queries_ext, |
12 | 17 | make_sub_questionnaire_ext, |
13 | 18 | make_target_structure_map_ext, |
14 | 19 | make_variable_ext, |
@@ -556,3 +561,209 @@ async def test_validate_assemble_context(fhir_client): |
556 | 561 | ) |
557 | 562 | with pytest.raises(OperationOutcome): |
558 | 563 | await q.execute("$assemble", method="get") |
| 564 | + |
| 565 | + |
| 566 | +@pytest.mark.asyncio |
| 567 | +async def test_assemble_propagates_mapping(fhir_client, safe_db): |
| 568 | + m1 = fhir_client.resource("Mapping", body={"resourceType": "Bundle", "type": "transaction"}) |
| 569 | + await m1.save() |
| 570 | + m2 = fhir_client.resource("Mapping", body={"resourceType": "Bundle", "type": "transaction"}) |
| 571 | + await m2.save() |
| 572 | + |
| 573 | + sub1 = await create_questionnaire( |
| 574 | + fhir_client, |
| 575 | + { |
| 576 | + "status": "active", |
| 577 | + "extension": [make_questionnaire_mapper_ext(m1.id)], |
| 578 | + "item": [{"type": "string", "linkId": "q1"}], |
| 579 | + }, |
| 580 | + ) |
| 581 | + sub2 = await create_questionnaire( |
| 582 | + fhir_client, |
| 583 | + { |
| 584 | + "status": "active", |
| 585 | + "extension": [ |
| 586 | + make_questionnaire_mapper_ext(m1.id), |
| 587 | + make_questionnaire_mapper_ext(m2.id), |
| 588 | + ], |
| 589 | + "item": [{"type": "string", "linkId": "q2"}], |
| 590 | + }, |
| 591 | + ) |
| 592 | + |
| 593 | + q = await create_questionnaire( |
| 594 | + fhir_client, |
| 595 | + { |
| 596 | + "status": "active", |
| 597 | + "item": [ |
| 598 | + { |
| 599 | + "type": "display", |
| 600 | + "linkId": "sub1-placeholder", |
| 601 | + "text": "Sub questionnaire is not supported", |
| 602 | + "extension": [make_sub_questionnaire_ext(sub1.id)], |
| 603 | + }, |
| 604 | + { |
| 605 | + "type": "display", |
| 606 | + "linkId": "sub2-placeholder", |
| 607 | + "text": "Sub questionnaire is not supported", |
| 608 | + "extension": [make_sub_questionnaire_ext(sub2.id)], |
| 609 | + }, |
| 610 | + ], |
| 611 | + }, |
| 612 | + ) |
| 613 | + |
| 614 | + assembled = await q.execute("$assemble", method="get") |
| 615 | + del assembled["meta"] |
| 616 | + |
| 617 | + assert assembled == { |
| 618 | + "resourceType": "Questionnaire", |
| 619 | + "status": "active", |
| 620 | + "extension": [ |
| 621 | + make_questionnaire_mapper_ext(m1.id), |
| 622 | + make_questionnaire_mapper_ext(m2.id), |
| 623 | + make_assembled_from_ext(q.id), |
| 624 | + ], |
| 625 | + "item": [ |
| 626 | + {"type": "string", "linkId": "q1"}, |
| 627 | + {"type": "string", "linkId": "q2"}, |
| 628 | + ], |
| 629 | + } |
| 630 | + |
| 631 | + |
| 632 | +@pytest.mark.asyncio |
| 633 | +async def test_assemble_propagates_source_queries(fhir_client, safe_db): |
| 634 | + sub1 = await create_questionnaire( |
| 635 | + fhir_client, |
| 636 | + { |
| 637 | + "status": "active", |
| 638 | + "extension": [make_source_queries_ext("#bundle-1")], |
| 639 | + "item": [{"type": "string", "linkId": "q1"}], |
| 640 | + }, |
| 641 | + ) |
| 642 | + sub2 = await create_questionnaire( |
| 643 | + fhir_client, |
| 644 | + { |
| 645 | + "status": "active", |
| 646 | + "extension": [ |
| 647 | + make_source_queries_ext("#bundle-1"), |
| 648 | + make_source_queries_ext("#bundle-2"), |
| 649 | + ], |
| 650 | + "item": [{"type": "string", "linkId": "q2"}], |
| 651 | + }, |
| 652 | + ) |
| 653 | + |
| 654 | + q = await create_questionnaire( |
| 655 | + fhir_client, |
| 656 | + { |
| 657 | + "status": "active", |
| 658 | + "item": [ |
| 659 | + { |
| 660 | + "type": "display", |
| 661 | + "linkId": "sub1-placeholder", |
| 662 | + "text": "Sub questionnaire is not supported", |
| 663 | + "extension": [make_sub_questionnaire_ext(sub1.id)], |
| 664 | + }, |
| 665 | + { |
| 666 | + "type": "display", |
| 667 | + "linkId": "sub2-placeholder", |
| 668 | + "text": "Sub questionnaire is not supported", |
| 669 | + "extension": [make_sub_questionnaire_ext(sub2.id)], |
| 670 | + }, |
| 671 | + ], |
| 672 | + }, |
| 673 | + ) |
| 674 | + |
| 675 | + assembled = await q.execute("$assemble", method="get") |
| 676 | + del assembled["meta"] |
| 677 | + |
| 678 | + assert assembled == { |
| 679 | + "resourceType": "Questionnaire", |
| 680 | + "status": "active", |
| 681 | + "extension": [ |
| 682 | + make_source_queries_ext("#bundle-1"), |
| 683 | + make_source_queries_ext("#bundle-2"), |
| 684 | + make_assembled_from_ext(q.id), |
| 685 | + ], |
| 686 | + "item": [ |
| 687 | + {"type": "string", "linkId": "q1"}, |
| 688 | + {"type": "string", "linkId": "q2"}, |
| 689 | + ], |
| 690 | + } |
| 691 | + |
| 692 | + |
| 693 | +@pytest.mark.asyncio |
| 694 | +async def test_assemble_propagates_contained(fhir_client, safe_db): |
| 695 | + contained_resource = { |
| 696 | + "id": "PrePopQuery", |
| 697 | + "resourceType": "Bundle", |
| 698 | + "type": "batch", |
| 699 | + "entry": [{"request": {"method": "GET", "url": "Patient?_id=1"}}], |
| 700 | + } |
| 701 | + sub = await create_questionnaire( |
| 702 | + fhir_client, |
| 703 | + { |
| 704 | + "status": "active", |
| 705 | + "contained": [contained_resource], |
| 706 | + "extension": [make_source_queries_ext("#PrePopQuery")], |
| 707 | + "item": [{"type": "string", "linkId": "q1"}], |
| 708 | + }, |
| 709 | + ) |
| 710 | + |
| 711 | + q = await create_questionnaire( |
| 712 | + fhir_client, |
| 713 | + { |
| 714 | + "status": "active", |
| 715 | + "item": [ |
| 716 | + { |
| 717 | + "type": "display", |
| 718 | + "linkId": "sub-placeholder", |
| 719 | + "text": "Sub questionnaire is not supported", |
| 720 | + "extension": [make_sub_questionnaire_ext(sub.id)], |
| 721 | + } |
| 722 | + ], |
| 723 | + }, |
| 724 | + ) |
| 725 | + |
| 726 | + assembled = await q.execute("$assemble", method="get") |
| 727 | + |
| 728 | + contained = assembled.get("contained", []) |
| 729 | + assert len(contained) == 1 |
| 730 | + assert contained[0]["id"] == "PrePopQuery" |
| 731 | + assert contained[0]["resourceType"] == "Bundle" |
| 732 | + assert {"type": "string", "linkId": "q1"} in assembled["item"] |
| 733 | + |
| 734 | + |
| 735 | +@pytest.mark.asyncio |
| 736 | +async def test_assemble_propagates_cqf_library(): |
| 737 | + from app.sdc.getters import CQF_LIBRARY_URL |
| 738 | + |
| 739 | + cqf_ext = {"url": CQF_LIBRARY_URL, "valueCanonical": "http://example.org/Library/MyLib"} |
| 740 | + sub_fhir = { |
| 741 | + "id": "sub-1", |
| 742 | + "resourceType": "Questionnaire", |
| 743 | + "status": "active", |
| 744 | + "extension": [cqf_ext], |
| 745 | + "item": [{"type": "string", "linkId": "q1"}], |
| 746 | + } |
| 747 | + |
| 748 | + mock_client = MagicMock() |
| 749 | + mock_client.resources.return_value.search.return_value.fetch_all = AsyncMock( |
| 750 | + return_value=[sub_fhir] |
| 751 | + ) |
| 752 | + |
| 753 | + fhir_questionnaire = { |
| 754 | + "id": "parent-q", |
| 755 | + "resourceType": "Questionnaire", |
| 756 | + "status": "active", |
| 757 | + "item": [ |
| 758 | + { |
| 759 | + "type": "display", |
| 760 | + "linkId": "sub-placeholder", |
| 761 | + "extension": [make_sub_questionnaire_ext("sub-1")], |
| 762 | + } |
| 763 | + ], |
| 764 | + } |
| 765 | + |
| 766 | + result = await assemble(mock_client, fhir_questionnaire) |
| 767 | + |
| 768 | + assert cqf_ext in result.get("extension", []) |
| 769 | + assert "id" not in result |
0 commit comments