diff --git a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/configuration/PluginModel.java b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/configuration/PluginModel.java index 42801797b3..05ba86725b 100644 --- a/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/configuration/PluginModel.java +++ b/data-prepper-api/src/main/java/org/opensearch/dataprepper/model/configuration/PluginModel.java @@ -213,8 +213,9 @@ public PluginModel deserialize(final JsonParser jsonParser, final Deserializatio } else if (jsonParser.currentToken() == JsonToken.VALUE_STRING) { final String value = jsonParser.getValueAsString(); if (value.isEmpty()) { - throw context.weirdStringException(value, Map.class, - "Empty string is not allowed for plugin '" + pluginName + "'. Use null, empty (no value), or {} instead."); + // Treat empty string same as null (YAML bare keys like "stdout:" parse as "" in Jackson 2.13+) + isNull = true; + jsonParser.nextToken(); } else { throw context.weirdStringException(value, Map.class, "String values not allowed for plugin '" + pluginName + "'"); diff --git a/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/PluginModelTests.java b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/PluginModelTests.java index 086f73c1a5..151b87e1aa 100644 --- a/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/PluginModelTests.java +++ b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/PluginModelTests.java @@ -33,6 +33,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasKey; @@ -229,15 +230,27 @@ final void testRoundTrip_withEmptyValue() throws IOException { } @Test - final void testDeserialize_emptyString_throwsException() throws IOException { + final void testDeserialize_emptyString_treatedAsNull() throws IOException { final InputStream inputStream = PluginModelTests.class.getResourceAsStream("plugin_model_empty_string.yaml"); final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - final JsonMappingException exception = assertThrows( - JsonMappingException.class, - () -> mapper.readValue(inputStream, PluginModel.class) - ); - assertThat(exception.getMessage(), containsString("Empty string is not allowed")); + final PluginModel pluginModel = mapper.readValue(inputStream, PluginModel.class); + assertThat(pluginModel.getPluginName(), equalTo("customPlugin")); + assertThat(pluginModel.getPluginSettings(), nullValue()); + } + + @Test + final void testDeserialize_settingsWithEmptyStringValues_preservedInMap() throws IOException { + final InputStream inputStream = PluginModelTests.class.getResourceAsStream("plugin_model_with_empty_string_settings.yaml"); + final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + + final PluginModel pluginModel = mapper.readValue(inputStream, PluginModel.class); + assertThat(pluginModel.getPluginName(), equalTo("customPlugin")); + assertThat(pluginModel.getPluginSettings(), notNullValue()); + // Empty strings are preserved in the raw settings map + assertThat(pluginModel.getPluginSettings().get("setting_a"), equalTo("")); + assertThat(pluginModel.getPluginSettings().get("setting_b"), equalTo("valid_value")); + assertThat(pluginModel.getPluginSettings().get("setting_c"), equalTo("")); } @Test diff --git a/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/SamplePipelineConfigurationTest.java b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/SamplePipelineConfigurationTest.java index ccf53753c9..08c813125b 100644 --- a/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/SamplePipelineConfigurationTest.java +++ b/data-prepper-api/src/test/java/org/opensearch/dataprepper/model/configuration/SamplePipelineConfigurationTest.java @@ -9,7 +9,6 @@ package org.opensearch.dataprepper.model.configuration; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.junit.jupiter.api.BeforeEach; @@ -24,8 +23,6 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertThrows; /** * End-to-end tests for sample pipeline YAML configurations, verifying that @@ -109,13 +106,11 @@ void deserialize_pipeline_withEmptyPluginConfig_hasEmptySettings(final String re } @Test - void deserialize_pipeline_withEmptyStringPluginConfig_throwsException() { + void deserialize_pipeline_withEmptyStringPluginConfig_treatedAsNull() throws IOException { final InputStream inputStream = getClass().getResourceAsStream("sample_pipelines/sample_pipeline_plugin_empty_string.yaml"); - final JsonMappingException exception = assertThrows( - JsonMappingException.class, - () -> objectMapper.readValue(inputStream, PipelinesDataFlowModel.class) - ); - assertThat(exception.getMessage(), containsString("Empty string is not allowed")); + final PipelinesDataFlowModel model = objectMapper.readValue(inputStream, PipelinesDataFlowModel.class); + assertThat(model, notNullValue()); + assertThat(model.getPipelines().containsKey("test-pipeline"), equalTo(true)); } } diff --git a/data-prepper-api/src/test/resources/org/opensearch/dataprepper/model/configuration/plugin_model_with_empty_string_settings.yaml b/data-prepper-api/src/test/resources/org/opensearch/dataprepper/model/configuration/plugin_model_with_empty_string_settings.yaml new file mode 100644 index 0000000000..4433e4f31c --- /dev/null +++ b/data-prepper-api/src/test/resources/org/opensearch/dataprepper/model/configuration/plugin_model_with_empty_string_settings.yaml @@ -0,0 +1,13 @@ +# +# Copyright OpenSearch Contributors +# SPDX-License-Identifier: Apache-2.0 +# +# The OpenSearch Contributors require contributions made to +# this file be licensed under the Apache-2.0 license or a +# compatible open source license. +# +--- +customPlugin: + setting_a: "" + setting_b: "valid_value" + setting_c: ""