regscale-cli 6.21.2.0__py3-none-any.whl → 6.28.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- regscale/_version.py +1 -1
- regscale/airflow/hierarchy.py +2 -2
- regscale/core/app/api.py +5 -2
- regscale/core/app/application.py +36 -6
- regscale/core/app/internal/control_editor.py +73 -21
- regscale/core/app/internal/evidence.py +727 -204
- regscale/core/app/internal/login.py +4 -2
- regscale/core/app/internal/model_editor.py +219 -64
- regscale/core/app/utils/app_utils.py +86 -12
- regscale/core/app/utils/catalog_utils/common.py +1 -1
- regscale/core/login.py +21 -4
- regscale/core/utils/async_graphql_client.py +363 -0
- regscale/core/utils/date.py +77 -1
- regscale/dev/cli.py +26 -0
- regscale/dev/code_gen.py +109 -24
- regscale/dev/version.py +72 -0
- regscale/integrations/commercial/__init__.py +30 -2
- regscale/integrations/commercial/aws/audit_manager_compliance.py +3908 -0
- regscale/integrations/commercial/aws/cli.py +3107 -54
- regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
- regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
- regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
- regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
- regscale/integrations/commercial/{amazon → aws}/common.py +71 -19
- regscale/integrations/commercial/aws/config_compliance.py +914 -0
- regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
- regscale/integrations/commercial/aws/control_compliance_analyzer.py +439 -0
- regscale/integrations/commercial/aws/evidence_generator.py +283 -0
- regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
- regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
- regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
- regscale/integrations/commercial/aws/iam_evidence.py +574 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +338 -22
- regscale/integrations/commercial/aws/inventory/base.py +107 -5
- regscale/integrations/commercial/aws/inventory/resources/analytics.py +390 -0
- regscale/integrations/commercial/aws/inventory/resources/applications.py +234 -0
- regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +328 -9
- regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
- regscale/integrations/commercial/aws/inventory/resources/database.py +481 -31
- regscale/integrations/commercial/aws/inventory/resources/developer_tools.py +253 -0
- regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
- regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
- regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
- regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
- regscale/integrations/commercial/aws/inventory/resources/machine_learning.py +358 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +390 -67
- regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
- regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +288 -29
- regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
- regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
- regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
- regscale/integrations/commercial/aws/kms_evidence.py +879 -0
- regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
- regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
- regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
- regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
- regscale/integrations/commercial/aws/org_evidence.py +666 -0
- regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
- regscale/integrations/commercial/aws/s3_evidence.py +632 -0
- regscale/integrations/commercial/aws/scanner.py +1072 -205
- regscale/integrations/commercial/aws/security_hub.py +319 -0
- regscale/integrations/commercial/aws/session_manager.py +282 -0
- regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
- regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
- regscale/integrations/commercial/jira.py +489 -153
- regscale/integrations/commercial/microsoft_defender/defender.py +326 -5
- regscale/integrations/commercial/microsoft_defender/defender_api.py +348 -14
- regscale/integrations/commercial/microsoft_defender/defender_constants.py +157 -0
- regscale/integrations/commercial/qualys/__init__.py +167 -68
- regscale/integrations/commercial/qualys/scanner.py +305 -39
- regscale/integrations/commercial/sarif/sairf_importer.py +432 -0
- regscale/integrations/commercial/sarif/sarif_converter.py +67 -0
- regscale/integrations/commercial/sicura/api.py +79 -42
- regscale/integrations/commercial/sicura/commands.py +8 -2
- regscale/integrations/commercial/sicura/scanner.py +83 -44
- regscale/integrations/commercial/stigv2/ckl_parser.py +5 -5
- regscale/integrations/commercial/synqly/assets.py +133 -16
- regscale/integrations/commercial/synqly/edr.py +2 -8
- regscale/integrations/commercial/synqly/query_builder.py +536 -0
- regscale/integrations/commercial/synqly/ticketing.py +27 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +165 -28
- regscale/integrations/commercial/tenablev2/cis_parsers.py +453 -0
- regscale/integrations/commercial/tenablev2/cis_scanner.py +447 -0
- regscale/integrations/commercial/tenablev2/commands.py +146 -5
- regscale/integrations/commercial/tenablev2/scanner.py +1 -3
- regscale/integrations/commercial/tenablev2/stig_parsers.py +113 -57
- regscale/integrations/commercial/wizv2/WizDataMixin.py +1 -1
- regscale/integrations/commercial/wizv2/click.py +191 -76
- regscale/integrations/commercial/wizv2/compliance/__init__.py +15 -0
- regscale/integrations/commercial/wizv2/{policy_compliance_helpers.py → compliance/helpers.py} +78 -60
- regscale/integrations/commercial/wizv2/compliance_report.py +1592 -0
- regscale/integrations/commercial/wizv2/core/__init__.py +133 -0
- regscale/integrations/commercial/wizv2/{async_client.py → core/client.py} +7 -3
- regscale/integrations/commercial/wizv2/{constants.py → core/constants.py} +92 -89
- regscale/integrations/commercial/wizv2/core/file_operations.py +237 -0
- regscale/integrations/commercial/wizv2/fetchers/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{data_fetcher.py → fetchers/policy_assessment.py} +66 -9
- regscale/integrations/commercial/wizv2/file_cleanup.py +104 -0
- regscale/integrations/commercial/wizv2/issue.py +776 -28
- regscale/integrations/commercial/wizv2/models/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/parsers/__init__.py +34 -0
- regscale/integrations/commercial/wizv2/{parsers.py → parsers/main.py} +1 -1
- regscale/integrations/commercial/wizv2/processors/__init__.py +11 -0
- regscale/integrations/commercial/wizv2/{finding_processor.py → processors/finding.py} +1 -1
- regscale/integrations/commercial/wizv2/reports.py +243 -0
- regscale/integrations/commercial/wizv2/sbom.py +1 -1
- regscale/integrations/commercial/wizv2/scanner.py +1031 -441
- regscale/integrations/commercial/wizv2/utils/__init__.py +48 -0
- regscale/integrations/commercial/wizv2/{utils.py → utils/main.py} +116 -61
- regscale/integrations/commercial/wizv2/variables.py +89 -3
- regscale/integrations/compliance_integration.py +1036 -151
- regscale/integrations/control_matcher.py +432 -0
- regscale/integrations/due_date_handler.py +333 -0
- regscale/integrations/milestone_manager.py +291 -0
- regscale/integrations/public/__init__.py +14 -0
- regscale/integrations/public/cci_importer.py +834 -0
- regscale/integrations/public/csam/__init__.py +0 -0
- regscale/integrations/public/csam/csam.py +938 -0
- regscale/integrations/public/csam/csam_agency_defined.py +179 -0
- regscale/integrations/public/csam/csam_common.py +154 -0
- regscale/integrations/public/csam/csam_controls.py +432 -0
- regscale/integrations/public/csam/csam_poam.py +124 -0
- regscale/integrations/public/fedramp/click.py +77 -6
- regscale/integrations/public/fedramp/docx_parser.py +10 -1
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +675 -289
- regscale/integrations/public/fedramp/fedramp_five.py +1 -1
- regscale/integrations/public/fedramp/poam/scanner.py +75 -7
- regscale/integrations/public/fedramp/poam_export_v5.py +888 -0
- regscale/integrations/scanner_integration.py +1961 -430
- regscale/models/integration_models/CCI_List.xml +1 -0
- regscale/models/integration_models/aqua.py +2 -2
- regscale/models/integration_models/cisa_kev_data.json +805 -11
- regscale/models/integration_models/flat_file_importer/__init__.py +5 -8
- regscale/models/integration_models/nexpose.py +36 -10
- regscale/models/integration_models/qualys.py +3 -4
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +87 -18
- regscale/models/integration_models/synqly_models/filter_parser.py +332 -0
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +124 -25
- regscale/models/integration_models/synqly_models/synqly_model.py +89 -16
- regscale/models/locking.py +12 -8
- regscale/models/platform.py +4 -2
- regscale/models/regscale_models/__init__.py +7 -0
- regscale/models/regscale_models/assessment.py +2 -1
- regscale/models/regscale_models/catalog.py +1 -1
- regscale/models/regscale_models/compliance_settings.py +251 -1
- regscale/models/regscale_models/component.py +1 -0
- regscale/models/regscale_models/control_implementation.py +236 -41
- regscale/models/regscale_models/control_objective.py +74 -5
- regscale/models/regscale_models/file.py +2 -0
- regscale/models/regscale_models/form_field_value.py +5 -3
- regscale/models/regscale_models/inheritance.py +44 -0
- regscale/models/regscale_models/issue.py +301 -102
- regscale/models/regscale_models/milestone.py +33 -14
- regscale/models/regscale_models/organization.py +3 -0
- regscale/models/regscale_models/regscale_model.py +310 -73
- regscale/models/regscale_models/security_plan.py +4 -2
- regscale/models/regscale_models/vulnerability.py +3 -3
- regscale/regscale.py +25 -4
- regscale/templates/__init__.py +0 -0
- regscale/utils/threading/threadhandler.py +20 -15
- regscale/validation/record.py +23 -1
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/METADATA +17 -33
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/RECORD +310 -111
- tests/core/__init__.py +0 -0
- tests/core/utils/__init__.py +0 -0
- tests/core/utils/test_async_graphql_client.py +472 -0
- tests/fixtures/test_fixture.py +13 -8
- tests/regscale/core/test_login.py +171 -4
- tests/regscale/integrations/commercial/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
- tests/regscale/integrations/commercial/aws/test_aws_analytics_collector.py +260 -0
- tests/regscale/integrations/commercial/aws/test_aws_applications_collector.py +242 -0
- tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
- tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
- tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
- tests/regscale/integrations/commercial/aws/test_aws_developer_tools_collector.py +203 -0
- tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
- tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
- tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
- tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
- tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
- tests/regscale/integrations/commercial/aws/test_aws_machine_learning_collector.py +237 -0
- tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
- tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
- tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
- tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
- tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
- tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
- tests/regscale/integrations/commercial/aws/test_control_compliance_analyzer.py +375 -0
- tests/regscale/integrations/commercial/aws/test_datetime_parsing.py +223 -0
- tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
- tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
- tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
- tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
- tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
- tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
- tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
- tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
- tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
- tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
- tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
- tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
- tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
- tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
- tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
- tests/regscale/integrations/commercial/conftest.py +28 -0
- tests/regscale/integrations/commercial/microsoft_defender/__init__.py +1 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender.py +1517 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_api.py +1748 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_constants.py +327 -0
- tests/regscale/integrations/commercial/microsoft_defender/test_defender_scanner.py +487 -0
- tests/regscale/integrations/commercial/test_aws.py +3742 -0
- tests/regscale/integrations/commercial/test_burp.py +48 -0
- tests/regscale/integrations/commercial/test_crowdstrike.py +49 -0
- tests/regscale/integrations/commercial/test_dependabot.py +341 -0
- tests/regscale/integrations/commercial/test_gcp.py +1543 -0
- tests/regscale/integrations/commercial/test_gitlab.py +549 -0
- tests/regscale/integrations/commercial/test_ip_mac_address_length.py +84 -0
- tests/regscale/integrations/commercial/test_jira.py +2204 -0
- tests/regscale/integrations/commercial/test_npm_audit.py +42 -0
- tests/regscale/integrations/commercial/test_okta.py +1228 -0
- tests/regscale/integrations/commercial/test_sarif_converter.py +251 -0
- tests/regscale/integrations/commercial/test_sicura.py +349 -0
- tests/regscale/integrations/commercial/test_snow.py +423 -0
- tests/regscale/integrations/commercial/test_sonarcloud.py +394 -0
- tests/regscale/integrations/commercial/test_sqlserver.py +186 -0
- tests/regscale/integrations/commercial/test_stig.py +33 -0
- tests/regscale/integrations/commercial/test_stig_mapper.py +153 -0
- tests/regscale/integrations/commercial/test_stigv2.py +406 -0
- tests/regscale/integrations/commercial/test_wiz.py +1365 -0
- tests/regscale/integrations/commercial/test_wiz_inventory.py +256 -0
- tests/regscale/integrations/commercial/wizv2/__init__.py +339 -0
- tests/regscale/integrations/commercial/wizv2/compliance/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/compliance/test_helpers.py +903 -0
- tests/regscale/integrations/commercial/wizv2/core/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/core/test_auth.py +701 -0
- tests/regscale/integrations/commercial/wizv2/core/test_client.py +1037 -0
- tests/regscale/integrations/commercial/wizv2/core/test_file_operations.py +989 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/fetchers/test_policy_assessment.py +805 -0
- tests/regscale/integrations/commercial/wizv2/parsers/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/parsers/test_main.py +1153 -0
- tests/regscale/integrations/commercial/wizv2/processors/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/processors/test_finding.py +671 -0
- tests/regscale/integrations/commercial/wizv2/test_WizDataMixin.py +537 -0
- tests/regscale/integrations/commercial/wizv2/test_click_comprehensive.py +851 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_comprehensive.py +910 -0
- tests/regscale/integrations/commercial/wizv2/test_compliance_report_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_file_cleanup.py +283 -0
- tests/regscale/integrations/commercial/wizv2/test_file_operations.py +260 -0
- tests/regscale/integrations/commercial/wizv2/test_issue.py +343 -0
- tests/regscale/integrations/commercial/wizv2/test_issue_comprehensive.py +1203 -0
- tests/regscale/integrations/commercial/wizv2/test_reports.py +497 -0
- tests/regscale/integrations/commercial/wizv2/test_sbom.py +643 -0
- tests/regscale/integrations/commercial/wizv2/test_scanner_comprehensive.py +805 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_click_client_id.py +165 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_report.py +1394 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_compliance_unit.py +341 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_control_normalization.py +138 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_findings_comprehensive.py +364 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_inventory_comprehensive.py +644 -0
- tests/regscale/integrations/commercial/wizv2/test_wiz_status_mapping.py +149 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2.py +1218 -0
- tests/regscale/integrations/commercial/wizv2/test_wizv2_utils.py +519 -0
- tests/regscale/integrations/commercial/wizv2/utils/__init__.py +1 -0
- tests/regscale/integrations/commercial/wizv2/utils/test_main.py +1523 -0
- tests/regscale/integrations/public/__init__.py +0 -0
- tests/regscale/integrations/public/fedramp/__init__.py +1 -0
- tests/regscale/integrations/public/fedramp/test_gen_asset_list.py +150 -0
- tests/regscale/integrations/public/fedramp/test_poam_export_v5.py +1293 -0
- tests/regscale/integrations/public/test_alienvault.py +220 -0
- tests/regscale/integrations/public/test_cci.py +1053 -0
- tests/regscale/integrations/public/test_cisa.py +1021 -0
- tests/regscale/integrations/public/test_emass.py +518 -0
- tests/regscale/integrations/public/test_fedramp.py +1152 -0
- tests/regscale/integrations/public/test_fedramp_cis_crm.py +3661 -0
- tests/regscale/integrations/public/test_file_uploads.py +506 -0
- tests/regscale/integrations/public/test_oscal.py +453 -0
- tests/regscale/integrations/test_compliance_status_mapping.py +406 -0
- tests/regscale/integrations/test_control_matcher.py +1421 -0
- tests/regscale/integrations/test_control_matching.py +155 -0
- tests/regscale/integrations/test_milestone_manager.py +408 -0
- tests/regscale/models/test_control_implementation.py +118 -3
- tests/regscale/models/test_form_field_value_integration.py +304 -0
- tests/regscale/models/test_issue.py +378 -1
- tests/regscale/models/test_module_integration.py +582 -0
- tests/regscale/models/test_tenable_integrations.py +811 -105
- regscale/integrations/commercial/wizv2/policy_compliance.py +0 -3057
- regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +0 -7388
- regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +0 -9605
- regscale/integrations/public/fedramp/parts_mapper.py +0 -107
- /regscale/integrations/commercial/{amazon → sarif}/__init__.py +0 -0
- /regscale/integrations/commercial/wizv2/{wiz_auth.py → core/auth.py} +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/LICENSE +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/WHEEL +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.21.2.0.dist-info → regscale_cli-6.28.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Integration tests for Module model API endpoints"""
|
|
4
|
+
|
|
5
|
+
from typing import List
|
|
6
|
+
from unittest.mock import MagicMock, patch
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from requests import Response
|
|
10
|
+
|
|
11
|
+
from regscale.models.regscale_models.module import Module, FormTab, FormField, Choice
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestModuleIntegration:
|
|
15
|
+
"""Integration tests for Module model covering all API endpoints"""
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def mock_api_handler(self):
|
|
19
|
+
"""Mock API handler for testing"""
|
|
20
|
+
with patch("regscale.models.regscale_models.module.Module._get_api_handler") as mock:
|
|
21
|
+
yield mock.return_value
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def sample_module_data(self):
|
|
25
|
+
"""Sample module data for testing"""
|
|
26
|
+
return {
|
|
27
|
+
"id": 1,
|
|
28
|
+
"displayName": "Test Module",
|
|
29
|
+
"regScaleName": "test-module",
|
|
30
|
+
"regScaleInformalName": "testmodule",
|
|
31
|
+
"route": "/test-module",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def sample_detailed_module_data(self):
|
|
36
|
+
"""Sample detailed module data with form tabs and fields"""
|
|
37
|
+
return {
|
|
38
|
+
"id": 1,
|
|
39
|
+
"displayName": "Cases",
|
|
40
|
+
"regScaleName": "cases",
|
|
41
|
+
"regScaleInformalName": "cases",
|
|
42
|
+
"route": "/cases",
|
|
43
|
+
"formTabs": [
|
|
44
|
+
{
|
|
45
|
+
"id": 10,
|
|
46
|
+
"displayName": "Basic Info",
|
|
47
|
+
"regScaleName": "basic-info",
|
|
48
|
+
"isActive": True,
|
|
49
|
+
"formFields": [
|
|
50
|
+
{
|
|
51
|
+
"id": 100,
|
|
52
|
+
"displayName": "Title",
|
|
53
|
+
"regScaleName": "title",
|
|
54
|
+
"fieldType": "text",
|
|
55
|
+
"isRequired": True,
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": 20,
|
|
61
|
+
"displayName": "Custom Fields",
|
|
62
|
+
"regScaleName": "custom-fields",
|
|
63
|
+
"isActive": True,
|
|
64
|
+
"formFields": [
|
|
65
|
+
{
|
|
66
|
+
"id": 200,
|
|
67
|
+
"displayName": "Custom Field 1",
|
|
68
|
+
"regScaleName": "custom-field-1",
|
|
69
|
+
"fieldType": "text",
|
|
70
|
+
"isCustom": True,
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def sample_modules_list(self):
|
|
79
|
+
"""Sample list of modules for testing"""
|
|
80
|
+
return [
|
|
81
|
+
{"id": 1, "displayName": "Cases", "regScaleName": "cases", "regScaleInformalName": "cases"},
|
|
82
|
+
{"id": 2, "displayName": "Assets", "regScaleName": "assets", "regScaleInformalName": "assets"},
|
|
83
|
+
{"id": 3, "displayName": "Issues", "regScaleName": "issues", "regScaleInformalName": "issues"},
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
def test_create_module_success(self, mock_api_handler, sample_module_data):
|
|
87
|
+
"""Test POST /api/modules - Create new module success"""
|
|
88
|
+
# Setup
|
|
89
|
+
mock_response = MagicMock(spec=Response)
|
|
90
|
+
mock_response.ok = True
|
|
91
|
+
mock_response.json.return_value = sample_module_data
|
|
92
|
+
mock_api_handler.post.return_value = mock_response
|
|
93
|
+
|
|
94
|
+
# Execute
|
|
95
|
+
module = Module(**sample_module_data)
|
|
96
|
+
result = module.create()
|
|
97
|
+
|
|
98
|
+
# Assert
|
|
99
|
+
assert result is not None
|
|
100
|
+
assert isinstance(result, Module)
|
|
101
|
+
assert result.id == 1
|
|
102
|
+
assert result.displayName == "Test Module"
|
|
103
|
+
mock_api_handler.post.assert_called_once()
|
|
104
|
+
|
|
105
|
+
def test_create_module_failure(self, mock_api_handler, sample_module_data):
|
|
106
|
+
"""Test POST /api/modules - Create module failure"""
|
|
107
|
+
# Setup
|
|
108
|
+
mock_response = MagicMock(spec=Response)
|
|
109
|
+
mock_response.ok = False
|
|
110
|
+
mock_response.status_code = 400
|
|
111
|
+
mock_response.reason = "Bad Request"
|
|
112
|
+
mock_response.text = "Invalid module data"
|
|
113
|
+
mock_api_handler.post.return_value = mock_response
|
|
114
|
+
|
|
115
|
+
# Execute
|
|
116
|
+
module = Module(**sample_module_data)
|
|
117
|
+
|
|
118
|
+
# Assert that APIInsertionError is raised
|
|
119
|
+
from regscale.core.app.utils.api_handler import APIInsertionError
|
|
120
|
+
|
|
121
|
+
with pytest.raises(APIInsertionError) as exc_info:
|
|
122
|
+
module.create()
|
|
123
|
+
|
|
124
|
+
assert "Response Code: 400:Bad Request - Invalid module data" in str(exc_info.value)
|
|
125
|
+
|
|
126
|
+
def test_get_modules_success(self, mock_api_handler, sample_modules_list):
|
|
127
|
+
"""Test GET /api/modules - Get all modules success"""
|
|
128
|
+
# Setup
|
|
129
|
+
mock_response = MagicMock(spec=Response)
|
|
130
|
+
mock_response.ok = True
|
|
131
|
+
mock_response.json.return_value = sample_modules_list
|
|
132
|
+
mock_api_handler.get.return_value = mock_response
|
|
133
|
+
|
|
134
|
+
# Execute
|
|
135
|
+
result = Module.get_modules()
|
|
136
|
+
|
|
137
|
+
# Assert
|
|
138
|
+
assert len(result) == 3
|
|
139
|
+
assert all(isinstance(module, Module) for module in result)
|
|
140
|
+
assert result[0].displayName == "Cases"
|
|
141
|
+
assert result[1].displayName == "Assets"
|
|
142
|
+
assert result[2].displayName == "Issues"
|
|
143
|
+
|
|
144
|
+
mock_api_handler.get.assert_called_once()
|
|
145
|
+
call_args = mock_api_handler.get.call_args
|
|
146
|
+
assert call_args[1]["endpoint"] == "/api/modules"
|
|
147
|
+
|
|
148
|
+
def test_get_modules_failure(self, mock_api_handler):
|
|
149
|
+
"""Test GET /api/modules - Get all modules failure"""
|
|
150
|
+
# Setup
|
|
151
|
+
mock_response = MagicMock(spec=Response)
|
|
152
|
+
mock_response.ok = False
|
|
153
|
+
mock_response.status_code = 500
|
|
154
|
+
mock_response.reason = "Internal Server Error"
|
|
155
|
+
mock_response.text = "Database error"
|
|
156
|
+
mock_api_handler.get.return_value = mock_response
|
|
157
|
+
|
|
158
|
+
# Mock log_response_error
|
|
159
|
+
with patch.object(Module, "log_response_error") as mock_log:
|
|
160
|
+
# Execute
|
|
161
|
+
result = Module.get_modules()
|
|
162
|
+
|
|
163
|
+
# Assert
|
|
164
|
+
assert result == []
|
|
165
|
+
mock_log.assert_called_once_with(response=mock_response)
|
|
166
|
+
|
|
167
|
+
def test_get_module_by_id_success(self, mock_api_handler, sample_detailed_module_data):
|
|
168
|
+
"""Test GET /api/modules/{moduleId} - Get module by ID success"""
|
|
169
|
+
# Setup
|
|
170
|
+
mock_response = MagicMock(spec=Response)
|
|
171
|
+
mock_response.ok = True
|
|
172
|
+
mock_response.json.return_value = sample_detailed_module_data
|
|
173
|
+
mock_api_handler.get.return_value = mock_response
|
|
174
|
+
|
|
175
|
+
# Execute
|
|
176
|
+
result = Module.get_module_by_id(1)
|
|
177
|
+
|
|
178
|
+
# Assert
|
|
179
|
+
assert result is not None
|
|
180
|
+
assert isinstance(result, Module)
|
|
181
|
+
assert result.id == 1
|
|
182
|
+
assert result.displayName == "Cases"
|
|
183
|
+
assert len(result.formTabs) == 2
|
|
184
|
+
|
|
185
|
+
mock_api_handler.get.assert_called_once()
|
|
186
|
+
call_args = mock_api_handler.get.call_args
|
|
187
|
+
assert call_args[1]["endpoint"] == "/api/modules/1"
|
|
188
|
+
|
|
189
|
+
def test_get_module_by_id_failure(self, mock_api_handler):
|
|
190
|
+
"""Test GET /api/modules/{moduleId} - Get module by ID failure"""
|
|
191
|
+
# Setup
|
|
192
|
+
mock_response = MagicMock(spec=Response)
|
|
193
|
+
mock_response.ok = False
|
|
194
|
+
mock_response.status_code = 500
|
|
195
|
+
mock_response.reason = "Internal Server Error"
|
|
196
|
+
mock_response.text = "Database error"
|
|
197
|
+
mock_api_handler.get.return_value = mock_response
|
|
198
|
+
|
|
199
|
+
# Mock log_response_error
|
|
200
|
+
with patch.object(Module, "log_response_error") as mock_log:
|
|
201
|
+
# Execute
|
|
202
|
+
result = Module.get_module_by_id(999)
|
|
203
|
+
|
|
204
|
+
# Assert
|
|
205
|
+
assert result is None
|
|
206
|
+
mock_log.assert_called_once_with(response=mock_response)
|
|
207
|
+
|
|
208
|
+
def test_get_module_by_id_not_found(self, mock_api_handler):
|
|
209
|
+
"""Test GET /api/modules/{moduleId} - Module not found"""
|
|
210
|
+
# Setup
|
|
211
|
+
mock_response = MagicMock(spec=Response)
|
|
212
|
+
mock_response.ok = False
|
|
213
|
+
mock_response.status_code = 404
|
|
214
|
+
mock_response.reason = "Not Found"
|
|
215
|
+
mock_response.text = "Module not found"
|
|
216
|
+
mock_api_handler.get.return_value = mock_response
|
|
217
|
+
|
|
218
|
+
# Mock log_response_error
|
|
219
|
+
with patch.object(Module, "log_response_error") as mock_log:
|
|
220
|
+
# Execute
|
|
221
|
+
result = Module.get_module_by_id(999)
|
|
222
|
+
|
|
223
|
+
# Assert
|
|
224
|
+
assert result is None
|
|
225
|
+
mock_log.assert_called_once_with(response=mock_response)
|
|
226
|
+
|
|
227
|
+
def test_post_multiple_modules_endpoint(self, mock_api_handler):
|
|
228
|
+
"""Test POST /api/modules/multiple - Bulk create modules"""
|
|
229
|
+
# Setup
|
|
230
|
+
modules_data = [
|
|
231
|
+
{"displayName": "Module 1", "regScaleName": "module1"},
|
|
232
|
+
{"displayName": "Module 2", "regScaleName": "module2"},
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
mock_response = MagicMock(spec=Response)
|
|
236
|
+
mock_response.ok = True
|
|
237
|
+
mock_response.json.return_value = modules_data
|
|
238
|
+
mock_api_handler.post.return_value = mock_response
|
|
239
|
+
|
|
240
|
+
# This would be the method if implemented
|
|
241
|
+
def create_multiple(cls, modules_data: List[dict]) -> List[Module]:
|
|
242
|
+
result = cls._get_api_handler().post(endpoint="/api/modules/multiple", data=modules_data)
|
|
243
|
+
if result and result.ok:
|
|
244
|
+
return [cls(**module_data) for module_data in result.json()]
|
|
245
|
+
return []
|
|
246
|
+
|
|
247
|
+
# Add method to class temporarily for testing
|
|
248
|
+
Module.create_multiple = classmethod(create_multiple)
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
# Execute
|
|
252
|
+
result = Module.create_multiple(modules_data)
|
|
253
|
+
|
|
254
|
+
# Assert
|
|
255
|
+
assert len(result) == 2
|
|
256
|
+
assert all(isinstance(module, Module) for module in result)
|
|
257
|
+
mock_api_handler.post.assert_called_once()
|
|
258
|
+
call_args = mock_api_handler.post.call_args
|
|
259
|
+
assert call_args[1]["endpoint"] == "/api/modules/multiple"
|
|
260
|
+
assert call_args[1]["data"] == modules_data
|
|
261
|
+
finally:
|
|
262
|
+
# Clean up
|
|
263
|
+
delattr(Module, "create_multiple")
|
|
264
|
+
|
|
265
|
+
def test_get_all_modules_with_form_fields_endpoint(self, mock_api_handler, sample_detailed_module_data):
|
|
266
|
+
"""Test GET /api/modules/getAllModulesWithFormFields"""
|
|
267
|
+
# Setup
|
|
268
|
+
mock_response = MagicMock(spec=Response)
|
|
269
|
+
mock_response.ok = True
|
|
270
|
+
mock_response.json.return_value = [sample_detailed_module_data]
|
|
271
|
+
mock_api_handler.get.return_value = mock_response
|
|
272
|
+
|
|
273
|
+
# This would be the method if implemented
|
|
274
|
+
def get_all_modules_with_form_fields(cls) -> List[Module]:
|
|
275
|
+
result = cls._get_api_handler().get(endpoint="/api/modules/getAllModulesWithFormFields")
|
|
276
|
+
if result and result.ok:
|
|
277
|
+
return [cls(**module_data) for module_data in result.json()]
|
|
278
|
+
return []
|
|
279
|
+
|
|
280
|
+
# Add method to class temporarily for testing
|
|
281
|
+
Module.get_all_modules_with_form_fields = classmethod(get_all_modules_with_form_fields)
|
|
282
|
+
|
|
283
|
+
try:
|
|
284
|
+
# Execute
|
|
285
|
+
result = Module.get_all_modules_with_form_fields()
|
|
286
|
+
|
|
287
|
+
# Assert
|
|
288
|
+
assert len(result) == 1
|
|
289
|
+
assert isinstance(result[0], Module)
|
|
290
|
+
assert result[0].id == 1
|
|
291
|
+
assert len(result[0].formTabs) == 2
|
|
292
|
+
mock_api_handler.get.assert_called_once()
|
|
293
|
+
call_args = mock_api_handler.get.call_args
|
|
294
|
+
assert call_args[1]["endpoint"] == "/api/modules/getAllModulesWithFormFields"
|
|
295
|
+
finally:
|
|
296
|
+
# Clean up
|
|
297
|
+
delattr(Module, "get_all_modules_with_form_fields")
|
|
298
|
+
|
|
299
|
+
def test_reset_module_endpoint(self, mock_api_handler):
|
|
300
|
+
"""Test GET /api/modules/reset/{moduleId} - Reset module labeling"""
|
|
301
|
+
# Setup
|
|
302
|
+
mock_response = MagicMock(spec=Response)
|
|
303
|
+
mock_response.ok = True
|
|
304
|
+
mock_response.json.return_value = {"message": "Module reset successfully"}
|
|
305
|
+
mock_api_handler.get.return_value = mock_response
|
|
306
|
+
|
|
307
|
+
# This would be the method if implemented
|
|
308
|
+
def reset_module(cls, module_id: int) -> bool:
|
|
309
|
+
result = cls._get_api_handler().get(endpoint=f"/api/modules/reset/{module_id}")
|
|
310
|
+
return result and result.ok
|
|
311
|
+
|
|
312
|
+
# Add method to class temporarily for testing
|
|
313
|
+
Module.reset_module = classmethod(reset_module)
|
|
314
|
+
|
|
315
|
+
try:
|
|
316
|
+
# Execute
|
|
317
|
+
result = Module.reset_module(1)
|
|
318
|
+
|
|
319
|
+
# Assert
|
|
320
|
+
assert result is True
|
|
321
|
+
mock_api_handler.get.assert_called_once()
|
|
322
|
+
call_args = mock_api_handler.get.call_args
|
|
323
|
+
assert call_args[1]["endpoint"] == "/api/modules/reset/1"
|
|
324
|
+
finally:
|
|
325
|
+
# Clean up
|
|
326
|
+
delattr(Module, "reset_module")
|
|
327
|
+
|
|
328
|
+
def test_get_module_by_name_success(self, mock_api_handler, sample_modules_list):
|
|
329
|
+
"""Test get_module_by_name with existing module"""
|
|
330
|
+
# Setup
|
|
331
|
+
mock_response = MagicMock(spec=Response)
|
|
332
|
+
mock_response.ok = True
|
|
333
|
+
mock_response.json.return_value = sample_modules_list
|
|
334
|
+
mock_api_handler.get.return_value = mock_response
|
|
335
|
+
|
|
336
|
+
# Execute
|
|
337
|
+
result = Module.get_module_by_name("cases")
|
|
338
|
+
|
|
339
|
+
# Assert
|
|
340
|
+
assert result is not None
|
|
341
|
+
assert isinstance(result, Module)
|
|
342
|
+
assert result.regScaleInformalName == "cases"
|
|
343
|
+
|
|
344
|
+
def test_get_module_by_name_not_found(self, mock_api_handler, sample_modules_list):
|
|
345
|
+
"""Test get_module_by_name with non-existing module"""
|
|
346
|
+
# Setup
|
|
347
|
+
mock_response = MagicMock(spec=Response)
|
|
348
|
+
mock_response.ok = True
|
|
349
|
+
mock_response.json.return_value = sample_modules_list
|
|
350
|
+
mock_api_handler.get.return_value = mock_response
|
|
351
|
+
|
|
352
|
+
# Execute
|
|
353
|
+
result = Module.get_module_by_name("nonexistent")
|
|
354
|
+
|
|
355
|
+
# Assert
|
|
356
|
+
assert result is None
|
|
357
|
+
|
|
358
|
+
def test_get_tab_by_name_success(self, mock_api_handler, sample_modules_list, sample_detailed_module_data):
|
|
359
|
+
"""Test get_tab_by_name with existing tab"""
|
|
360
|
+
# Setup - Mock both get_modules and get_module_by_id calls
|
|
361
|
+
mock_response_modules = MagicMock(spec=Response)
|
|
362
|
+
mock_response_modules.ok = True
|
|
363
|
+
mock_response_modules.json.return_value = sample_modules_list
|
|
364
|
+
|
|
365
|
+
mock_response_detailed = MagicMock(spec=Response)
|
|
366
|
+
mock_response_detailed.ok = True
|
|
367
|
+
mock_response_detailed.json.return_value = sample_detailed_module_data
|
|
368
|
+
|
|
369
|
+
# Set up side effects for multiple calls
|
|
370
|
+
mock_api_handler.get.side_effect = [mock_response_modules, mock_response_detailed]
|
|
371
|
+
|
|
372
|
+
# Execute
|
|
373
|
+
result = Module.get_tab_by_name("cases", "basic-info")
|
|
374
|
+
|
|
375
|
+
# Assert
|
|
376
|
+
assert result is not None
|
|
377
|
+
assert isinstance(result, FormTab)
|
|
378
|
+
assert result.regScaleName == "basic-info"
|
|
379
|
+
assert result.id == 10
|
|
380
|
+
|
|
381
|
+
def test_get_tab_by_name_module_not_found(self, mock_api_handler, sample_modules_list):
|
|
382
|
+
"""Test get_tab_by_name with non-existing module"""
|
|
383
|
+
# Setup
|
|
384
|
+
mock_response = MagicMock(spec=Response)
|
|
385
|
+
mock_response.ok = True
|
|
386
|
+
mock_response.json.return_value = sample_modules_list
|
|
387
|
+
mock_api_handler.get.return_value = mock_response
|
|
388
|
+
|
|
389
|
+
# Execute
|
|
390
|
+
result = Module.get_tab_by_name("nonexistent", "basic-info")
|
|
391
|
+
|
|
392
|
+
# Assert
|
|
393
|
+
assert result is None
|
|
394
|
+
|
|
395
|
+
def test_get_tab_by_name_tab_not_found(self, mock_api_handler, sample_modules_list, sample_detailed_module_data):
|
|
396
|
+
"""Test get_tab_by_name with non-existing tab"""
|
|
397
|
+
# Setup
|
|
398
|
+
mock_response_modules = MagicMock(spec=Response)
|
|
399
|
+
mock_response_modules.ok = True
|
|
400
|
+
mock_response_modules.json.return_value = sample_modules_list
|
|
401
|
+
|
|
402
|
+
mock_response_detailed = MagicMock(spec=Response)
|
|
403
|
+
mock_response_detailed.ok = True
|
|
404
|
+
mock_response_detailed.json.return_value = sample_detailed_module_data
|
|
405
|
+
|
|
406
|
+
mock_api_handler.get.side_effect = [mock_response_modules, mock_response_detailed]
|
|
407
|
+
|
|
408
|
+
# Execute
|
|
409
|
+
result = Module.get_tab_by_name("cases", "nonexistent-tab")
|
|
410
|
+
|
|
411
|
+
# Assert
|
|
412
|
+
assert result is None
|
|
413
|
+
|
|
414
|
+
def test_get_new_custom_form_tab_id_success(
|
|
415
|
+
self, mock_api_handler, sample_modules_list, sample_detailed_module_data
|
|
416
|
+
):
|
|
417
|
+
"""Test get_new_custom_form_tab_id with existing tab"""
|
|
418
|
+
# Setup
|
|
419
|
+
mock_response_modules = MagicMock(spec=Response)
|
|
420
|
+
mock_response_modules.ok = True
|
|
421
|
+
mock_response_modules.json.return_value = sample_modules_list
|
|
422
|
+
|
|
423
|
+
mock_response_detailed = MagicMock(spec=Response)
|
|
424
|
+
mock_response_detailed.ok = True
|
|
425
|
+
mock_response_detailed.json.return_value = sample_detailed_module_data
|
|
426
|
+
|
|
427
|
+
mock_api_handler.get.side_effect = [mock_response_modules, mock_response_detailed]
|
|
428
|
+
|
|
429
|
+
# Execute
|
|
430
|
+
result = Module.get_new_custom_form_tab_id("cases", "basic-info")
|
|
431
|
+
|
|
432
|
+
# Assert
|
|
433
|
+
assert result == 10
|
|
434
|
+
|
|
435
|
+
def test_get_new_custom_form_tab_id_not_found(self, mock_api_handler, sample_modules_list):
|
|
436
|
+
"""Test get_new_custom_form_tab_id with non-existing module"""
|
|
437
|
+
# Setup
|
|
438
|
+
mock_response = MagicMock(spec=Response)
|
|
439
|
+
mock_response.ok = True
|
|
440
|
+
mock_response.json.return_value = sample_modules_list
|
|
441
|
+
mock_api_handler.get.return_value = mock_response
|
|
442
|
+
|
|
443
|
+
# Execute
|
|
444
|
+
result = Module.get_new_custom_form_tab_id("nonexistent", "basic-info")
|
|
445
|
+
|
|
446
|
+
# Assert
|
|
447
|
+
assert result is None
|
|
448
|
+
|
|
449
|
+
def test_get_form_fields_by_tab_id_success(
|
|
450
|
+
self, mock_api_handler, sample_modules_list, sample_detailed_module_data
|
|
451
|
+
):
|
|
452
|
+
"""Test get_form_fields_by_tab_id with existing tab"""
|
|
453
|
+
# Setup
|
|
454
|
+
mock_response_modules = MagicMock(spec=Response)
|
|
455
|
+
mock_response_modules.ok = True
|
|
456
|
+
mock_response_modules.json.return_value = sample_modules_list
|
|
457
|
+
|
|
458
|
+
mock_response_detailed = MagicMock(spec=Response)
|
|
459
|
+
mock_response_detailed.ok = True
|
|
460
|
+
mock_response_detailed.json.return_value = sample_detailed_module_data
|
|
461
|
+
|
|
462
|
+
mock_api_handler.get.side_effect = [mock_response_modules, mock_response_detailed]
|
|
463
|
+
|
|
464
|
+
# Execute
|
|
465
|
+
result = Module.get_form_fields_by_tab_id("cases", "basic-info")
|
|
466
|
+
|
|
467
|
+
# Assert
|
|
468
|
+
assert result is not None
|
|
469
|
+
assert len(result) == 1
|
|
470
|
+
assert isinstance(result[0], FormField)
|
|
471
|
+
assert result[0].regScaleName == "title"
|
|
472
|
+
|
|
473
|
+
def test_get_form_fields_by_tab_id_not_found(self, mock_api_handler, sample_modules_list):
|
|
474
|
+
"""Test get_form_fields_by_tab_id with non-existing module"""
|
|
475
|
+
# Setup
|
|
476
|
+
mock_response = MagicMock(spec=Response)
|
|
477
|
+
mock_response.ok = True
|
|
478
|
+
mock_response.json.return_value = sample_modules_list
|
|
479
|
+
mock_api_handler.get.return_value = mock_response
|
|
480
|
+
|
|
481
|
+
# Execute
|
|
482
|
+
result = Module.get_form_fields_by_tab_id("nonexistent", "basic-info")
|
|
483
|
+
|
|
484
|
+
# Assert
|
|
485
|
+
assert result is None
|
|
486
|
+
|
|
487
|
+
def test_module_slug(self):
|
|
488
|
+
"""Test that the module slug is correctly set"""
|
|
489
|
+
assert Module._module_slug == "modules"
|
|
490
|
+
|
|
491
|
+
def test_additional_endpoints(self):
|
|
492
|
+
"""Test that additional endpoints are correctly defined"""
|
|
493
|
+
endpoints = Module._get_additional_endpoints()
|
|
494
|
+
|
|
495
|
+
assert "get_modules" in endpoints
|
|
496
|
+
assert "get_module_by_id" in endpoints
|
|
497
|
+
|
|
498
|
+
assert endpoints["get_modules"] == "/api/{model_slug}"
|
|
499
|
+
assert endpoints["get_module_by_id"] == "/api/{model_slug}/{id}"
|
|
500
|
+
|
|
501
|
+
@pytest.mark.parametrize(
|
|
502
|
+
"module_id,expected_endpoint",
|
|
503
|
+
[
|
|
504
|
+
(1, "/api/modules/1"),
|
|
505
|
+
(999, "/api/modules/999"),
|
|
506
|
+
(42, "/api/modules/42"),
|
|
507
|
+
],
|
|
508
|
+
)
|
|
509
|
+
def test_get_module_by_id_endpoint_formation(self, mock_api_handler, module_id, expected_endpoint):
|
|
510
|
+
"""Test endpoint formation for get_module_by_id with different IDs"""
|
|
511
|
+
# Setup
|
|
512
|
+
mock_response = MagicMock(spec=Response)
|
|
513
|
+
mock_response.ok = True
|
|
514
|
+
mock_response.json.return_value = {"id": module_id, "displayName": f"Module {module_id}"}
|
|
515
|
+
mock_api_handler.get.return_value = mock_response
|
|
516
|
+
|
|
517
|
+
# Execute
|
|
518
|
+
Module.get_module_by_id(module_id)
|
|
519
|
+
|
|
520
|
+
# Assert
|
|
521
|
+
call_args = mock_api_handler.get.call_args
|
|
522
|
+
assert call_args[1]["endpoint"] == expected_endpoint
|
|
523
|
+
|
|
524
|
+
def test_form_tab_model_structure(self):
|
|
525
|
+
"""Test FormTab model structure and field access"""
|
|
526
|
+
form_tab_data = {
|
|
527
|
+
"id": 1,
|
|
528
|
+
"displayName": "Test Tab",
|
|
529
|
+
"regScaleName": "test-tab",
|
|
530
|
+
"isActive": True,
|
|
531
|
+
"formFields": [{"id": 10, "displayName": "Test Field", "regScaleName": "test-field", "fieldType": "text"}],
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
form_tab = FormTab(**form_tab_data)
|
|
535
|
+
|
|
536
|
+
assert form_tab.id == 1
|
|
537
|
+
assert form_tab.displayName == "Test Tab"
|
|
538
|
+
assert form_tab.regScaleName == "test-tab"
|
|
539
|
+
assert form_tab.isActive is True
|
|
540
|
+
assert len(form_tab.formFields) == 1
|
|
541
|
+
assert isinstance(form_tab.formFields[0], FormField)
|
|
542
|
+
|
|
543
|
+
def test_form_field_model_structure(self):
|
|
544
|
+
"""Test FormField model structure and field access"""
|
|
545
|
+
form_field_data = {
|
|
546
|
+
"id": 1,
|
|
547
|
+
"displayName": "Test Field",
|
|
548
|
+
"regScaleName": "test-field",
|
|
549
|
+
"fieldType": "select",
|
|
550
|
+
"isRequired": True,
|
|
551
|
+
"choices": [{"id": 1, "value": "option1", "label": "Option 1", "isActive": True}],
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
form_field = FormField(**form_field_data)
|
|
555
|
+
|
|
556
|
+
assert form_field.id == 1
|
|
557
|
+
assert form_field.displayName == "Test Field"
|
|
558
|
+
assert form_field.regScaleName == "test-field"
|
|
559
|
+
assert form_field.fieldType == "select"
|
|
560
|
+
assert form_field.isRequired is True
|
|
561
|
+
assert len(form_field.choices) == 1
|
|
562
|
+
assert isinstance(form_field.choices[0], Choice)
|
|
563
|
+
|
|
564
|
+
def test_choice_model_structure(self):
|
|
565
|
+
"""Test Choice model structure and field access"""
|
|
566
|
+
choice_data = {
|
|
567
|
+
"id": 1,
|
|
568
|
+
"value": "test_value",
|
|
569
|
+
"label": "Test Label",
|
|
570
|
+
"regScaleLabel": "Test RegScale Label",
|
|
571
|
+
"isActive": True,
|
|
572
|
+
"sequence": 1,
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
choice = Choice(**choice_data)
|
|
576
|
+
|
|
577
|
+
assert choice.id == 1
|
|
578
|
+
assert choice.value == "test_value"
|
|
579
|
+
assert choice.label == "Test Label"
|
|
580
|
+
assert choice.regScaleLabel == "Test RegScale Label"
|
|
581
|
+
assert choice.isActive is True
|
|
582
|
+
assert choice.sequence == 1
|