diff --git a/tests/fixtures/core/config/component_validation/basic/configuration.yaml b/tests/fixtures/core/config/component_validation/basic/configuration.yaml index 158a32a7d69..9c3d1eb190b 100644 --- a/tests/fixtures/core/config/component_validation/basic/configuration.yaml +++ b/tests/fixtures/core/config/component_validation/basic/configuration.yaml @@ -43,3 +43,16 @@ adr_0007_4: adr_0007_5: no_such_option: foo port: foo + +# This is correct and should not generate errors +custom_validator_ok_1: + host: blah.com + +# Host is missing +custom_validator_ok_2: + +# This always raises HomeAssistantError +custom_validator_bad_1: + +# This always raises ValueError +custom_validator_bad_2: diff --git a/tests/fixtures/core/config/component_validation/basic_include/configuration.yaml b/tests/fixtures/core/config/component_validation/basic_include/configuration.yaml index d67ae673901..5744e3005fa 100644 --- a/tests/fixtures/core/config/component_validation/basic_include/configuration.yaml +++ b/tests/fixtures/core/config/component_validation/basic_include/configuration.yaml @@ -4,3 +4,7 @@ adr_0007_2: !include integrations/adr_0007_2.yaml adr_0007_3: !include integrations/adr_0007_3.yaml adr_0007_4: !include integrations/adr_0007_4.yaml adr_0007_5: !include integrations/adr_0007_5.yaml +custom_validator_ok_1: !include integrations/custom_validator_ok_1.yaml +custom_validator_ok_2: !include integrations/custom_validator_ok_2.yaml +custom_validator_bad_1: !include integrations/custom_validator_bad_1.yaml +custom_validator_bad_2: !include integrations/custom_validator_bad_2.yaml diff --git a/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_1.yaml b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_1.yaml new file mode 100644 index 00000000000..12d6d869f35 --- /dev/null +++ b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_1.yaml @@ -0,0 +1 @@ +# This always raises HomeAssistantError diff --git a/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_2.yaml b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_2.yaml new file mode 100644 index 00000000000..7af4b20c016 --- /dev/null +++ b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_bad_2.yaml @@ -0,0 +1 @@ +# This always raises ValueError diff --git a/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_1.yaml b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_1.yaml new file mode 100644 index 00000000000..d246d73c257 --- /dev/null +++ b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_1.yaml @@ -0,0 +1,2 @@ +# This is correct and should not generate errors +host: blah.com diff --git a/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_2.yaml b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_2.yaml new file mode 100644 index 00000000000..8b592b01e2d --- /dev/null +++ b/tests/fixtures/core/config/component_validation/basic_include/integrations/custom_validator_ok_2.yaml @@ -0,0 +1 @@ +# Host is missing diff --git a/tests/fixtures/core/config/component_validation/packages/configuration.yaml b/tests/fixtures/core/config/component_validation/packages/configuration.yaml index dff25efd749..b8116b5988e 100644 --- a/tests/fixtures/core/config/component_validation/packages/configuration.yaml +++ b/tests/fixtures/core/config/component_validation/packages/configuration.yaml @@ -54,3 +54,17 @@ homeassistant: adr_0007_5: no_such_option: foo port: foo + + pack_custom_validator_ok_1: + # This is correct and should not generate errors + custom_validator_ok_1: + host: blah.com + pack_custom_validator_ok_2: + # Host is missing + custom_validator_ok_2: + pack_custom_validator_bad_1: + # This always raises HomeAssistantError + custom_validator_bad_1: + pack_custom_validator_bad_2: + # This always raises ValueError + custom_validator_bad_2: diff --git a/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_1.yaml b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_1.yaml new file mode 100644 index 00000000000..2e17b766800 --- /dev/null +++ b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_1.yaml @@ -0,0 +1,2 @@ +# This always raises HomeAssistantError +custom_validator_bad_1: diff --git a/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_2.yaml b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_2.yaml new file mode 100644 index 00000000000..213c3ea03f8 --- /dev/null +++ b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_bad_2.yaml @@ -0,0 +1,2 @@ +# This always raises ValueError +custom_validator_bad_2: diff --git a/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_1.yaml b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_1.yaml new file mode 100644 index 00000000000..257ff66d10b --- /dev/null +++ b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_1.yaml @@ -0,0 +1,3 @@ +# This is correct and should not generate errors +custom_validator_ok_1: + host: blah.com diff --git a/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_2.yaml b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_2.yaml new file mode 100644 index 00000000000..59a240defaf --- /dev/null +++ b/tests/fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_2.yaml @@ -0,0 +1,2 @@ +# Host is missing +custom_validator_ok_2: diff --git a/tests/snapshots/test_config.ambr b/tests/snapshots/test_config.ambr index e116a1255be..9df27e02f90 100644 --- a/tests/snapshots/test_config.ambr +++ b/tests/snapshots/test_config.ambr @@ -1,106 +1,290 @@ # serializer version: 1 # name: test_component_config_validation_error[basic] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 6: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 9: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 12: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 18: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 19: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 20: expected str for dictionary value 'option2', got 123. - ''', - "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 27: required key 'host' not provided.", - "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 32: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", - "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 37: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", - ''' - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 43: required key 'host' not provided. - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 44: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 45: expected int for dictionary value 'adr_0007_5->port', got 'foo'. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 6: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 9: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 12: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 18: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 19: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 20: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 27: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 32: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 37: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 43: required key 'host' not provided. + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 44: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 45: expected int for dictionary value 'adr_0007_5->port', got 'foo'. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [custom_validator_ok_2] at /fixtures/core/config/component_validation/basic/configuration.yaml, line 52: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error[basic_include] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 5: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 8: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 11: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 17: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 18: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 19: expected str for dictionary value 'option2', got 123. - ''', - "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/basic_include/configuration.yaml, line 3: required key 'host' not provided.", - "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_3.yaml, line 3: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", - "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_4.yaml, line 3: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", - ''' - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/configuration.yaml, line 6: required key 'host' not provided. - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_5.yaml, line 5: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_5.yaml, line 6: expected int for dictionary value 'adr_0007_5->port', got 'foo'. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 5: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 8: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 11: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 17: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 18: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/basic_include/integrations/iot_domain.yaml, line 19: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/basic_include/configuration.yaml, line 3: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_3.yaml, line 3: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_4.yaml, line 3: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/configuration.yaml, line 6: required key 'host' not provided. + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_5.yaml, line 5: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/basic_include/integrations/adr_0007_5.yaml, line 6: expected int for dictionary value 'adr_0007_5->port', got 'foo'. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [custom_validator_ok_2] at /fixtures/core/config/component_validation/basic_include/configuration.yaml, line 8: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error[include_dir_list] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_2.yaml, line 2: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_3.yaml, line 3: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_4.yaml, line 3: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 5: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 6: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 7: expected str for dictionary value 'option2', got 123. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_2.yaml, line 2: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_3.yaml, line 3: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_4.yaml, line 3: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 5: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 6: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_list/iot_domain/iot_domain_5.yaml, line 7: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error[include_dir_merge_list] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_1.yaml, line 5: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 3: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 6: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 12: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 13: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 14: expected str for dictionary value 'option2', got 123. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_1.yaml, line 5: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 3: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 6: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 12: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 13: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/include_dir_merge_list/iot_domain/iot_domain_2.yaml, line 14: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error[packages] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 11: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 16: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 21: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 29: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 30: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 31: expected str for dictionary value 'option2', got 123. - ''', - "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 38: required key 'host' not provided.", - "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 43: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", - "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 48: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", - ''' - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 54: required key 'host' not provided. - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 55: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 56: expected int for dictionary value 'adr_0007_5->port', got 'foo'. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 11: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 16: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 21: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 29: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 30: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 31: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 38: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 43: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 48: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 54: required key 'host' not provided. + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 55: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 56: expected int for dictionary value 'adr_0007_5->port', got 'foo'. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [custom_validator_ok_2] at /fixtures/core/config/component_validation/packages/configuration.yaml, line 64: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error[packages_include_dir_named] list([ - "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 6: required key 'platform' not provided.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 9: expected str for dictionary value 'option1', got 123.", - "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 12: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", - ''' - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 18: required key 'option1' not provided. - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 19: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option - Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 20: expected str for dictionary value 'option2', got 123. - ''', - "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_2.yaml, line 2: required key 'host' not provided.", - "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_3.yaml, line 4: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", - "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_4.yaml, line 4: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", - ''' - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 5: required key 'host' not provided. - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 6: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option - Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 7: expected int for dictionary value 'adr_0007_5->port', got 'foo'. - ''', + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 6: required key 'platform' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 9: expected str for dictionary value 'option1', got 123.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 12: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 18: required key 'option1' not provided. + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 19: 'no_such_option' is an invalid option for [iot_domain.non_adr_0007], check: no_such_option + Invalid config for [iot_domain.non_adr_0007] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/iot_domain.yaml, line 20: expected str for dictionary value 'option2', got 123. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_2] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_2.yaml, line 2: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_3] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_3.yaml, line 4: expected int for dictionary value 'adr_0007_3->port', got 'foo'.", + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [adr_0007_4] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_4.yaml, line 4: 'no_such_option' is an invalid option for [adr_0007_4], check: adr_0007_4->no_such_option", + }), + dict({ + 'has_exc_info': False, + 'message': ''' + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 5: required key 'host' not provided. + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 6: 'no_such_option' is an invalid option for [adr_0007_5], check: adr_0007_5->no_such_option + Invalid config for [adr_0007_5] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/adr_0007_5.yaml, line 7: expected int for dictionary value 'adr_0007_5->port', got 'foo'. + ''', + }), + dict({ + 'has_exc_info': False, + 'message': "Invalid config for [custom_validator_ok_2] at /fixtures/core/config/component_validation/packages_include_dir_named/integrations/custom_validator_ok_2.yaml, line 2: required key 'host' not provided.", + }), + dict({ + 'has_exc_info': True, + 'message': 'Invalid config for [custom_validator_bad_1]: broken', + }), + dict({ + 'has_exc_info': True, + 'message': 'Unknown error calling custom_validator_bad_2 config validator', + }), ]) # --- # name: test_component_config_validation_error_with_docs[basic] diff --git a/tests/test_config.py b/tests/test_config.py index ca6fb3b52bc..2abb2f08d60 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -33,6 +33,7 @@ from homeassistant.core import ConfigSource, HomeAssistant, HomeAssistantError from homeassistant.helpers import config_validation as cv, issue_registry as ir import homeassistant.helpers.check_config as check_config from homeassistant.helpers.entity import Entity +from homeassistant.helpers.typing import ConfigType from homeassistant.loader import Integration, async_get_integration from homeassistant.util.unit_system import ( _CONF_UNIT_SYSTEM_US_CUSTOMARY, @@ -193,7 +194,7 @@ async def mock_adr_0007_integrations(hass: HomeAssistant) -> list[Integration]: domain: vol.Schema( { vol.Required("host"): str, - vol.Required("port", default=8080): int, + vol.Optional("port", default=8080): int, } ) }, @@ -226,7 +227,7 @@ async def mock_adr_0007_integrations_with_docs( domain: vol.Schema( { vol.Required("host"): str, - vol.Required("port", default=8080): int, + vol.Optional("port", default=8080): int, } ) }, @@ -247,6 +248,53 @@ async def mock_adr_0007_integrations_with_docs( return integrations +@pytest.fixture +async def mock_custom_validator_integrations(hass: HomeAssistant) -> list[Integration]: + """Mock integrations with custom validator.""" + integrations = [] + + for domain in ("custom_validator_ok_1", "custom_validator_ok_2"): + + def gen_async_validate_config(domain): + schema = vol.Schema( + { + domain: vol.Schema( + { + vol.Required("host"): str, + vol.Optional("port", default=8080): int, + } + ) + }, + extra=vol.ALLOW_EXTRA, + ) + + async def async_validate_config( + hass: HomeAssistant, config: ConfigType + ) -> ConfigType: + """Validate config.""" + return schema(config) + + return async_validate_config + + integrations.append(mock_integration(hass, MockModule(domain))) + mock_platform( + hass, + f"{domain}.config", + Mock(async_validate_config=gen_async_validate_config(domain)), + ) + + for domain, exception in [ + ("custom_validator_bad_1", HomeAssistantError("broken")), + ("custom_validator_bad_2", ValueError("broken")), + ]: + integrations.append(mock_integration(hass, MockModule(domain))) + mock_platform( + hass, + f"{domain}.config", + Mock(async_validate_config=AsyncMock(side_effect=exception)), + ) + + async def test_create_default_config(hass: HomeAssistant) -> None: """Test creation of default config.""" assert not os.path.isfile(YAML_PATH) @@ -1581,6 +1629,7 @@ async def test_component_config_validation_error( mock_iot_domain_integration: Integration, mock_non_adr_0007_integration: None, mock_adr_0007_integrations: list[Integration], + mock_custom_validator_integrations: list[Integration], snapshot: SnapshotAssertion, ) -> None: """Test schema error in component.""" @@ -1598,6 +1647,10 @@ async def test_component_config_validation_error( "adr_0007_3", "adr_0007_4", "adr_0007_5", + "custom_validator_ok_1", + "custom_validator_ok_2", + "custom_validator_bad_1", + "custom_validator_bad_2", ]: integration = await async_get_integration(hass, domain) await config_util.async_process_component_config( @@ -1607,7 +1660,10 @@ async def test_component_config_validation_error( ) error_records = [ - record.message.replace(base_path, "") + { + "message": record.message.replace(base_path, ""), + "has_exc_info": bool(record.exc_info), + } for record in caplog.get_records("call") if record.levelno == logging.ERROR ]