-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: improve regex validaiton message #5447
base: main
Are you sure you want to change the base?
Changes from all commits
2cd8c04
3082654
d4e8527
3d95b83
190e5ed
e88931f
aa9a727
9fda241
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.dataprepper.plugins.regex; | ||
|
||
import java.util.Objects; | ||
import java.util.regex.Pattern; | ||
import java.util.regex.PatternSyntaxException; | ||
|
||
public class RegexValueValidator { | ||
public static boolean validateRegex(final String pattern) { | ||
if (pattern != null && !Objects.equals(pattern, "")) { | ||
try { | ||
Pattern.compile(pattern); | ||
} catch (PatternSyntaxException e) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.dataprepper.plugins.regex; | ||
|
||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
import java.util.stream.Stream; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
|
||
class RegexValueValidatorTest { | ||
@ParameterizedTest | ||
@MethodSource("provideRegexAndExpectedResult") | ||
void testValidateRegex(final String delimiterRegex, final boolean isValid) { | ||
assertThat(RegexValueValidator.validateRegex(delimiterRegex), is(isValid)); | ||
} | ||
|
||
private static Stream<Arguments> provideRegexAndExpectedResult() { | ||
return Stream.of( | ||
Arguments.of(null, true), | ||
Arguments.of("", true), | ||
Arguments.of("abc", true), | ||
Arguments.of("(abc", false) | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import org.opensearch.dataprepper.metrics.PluginMetrics; | ||
import org.opensearch.dataprepper.model.configuration.PluginSetting; | ||
import org.opensearch.dataprepper.model.event.Event; | ||
import org.opensearch.dataprepper.model.plugin.InvalidPluginConfigurationException; | ||
import org.opensearch.dataprepper.model.record.Record; | ||
|
||
import java.util.ArrayList; | ||
|
@@ -30,6 +31,7 @@ | |
import java.util.stream.Stream; | ||
|
||
import static org.hamcrest.CoreMatchers.equalTo; | ||
import static org.hamcrest.CoreMatchers.instanceOf; | ||
import static org.hamcrest.CoreMatchers.notNullValue; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
@@ -453,9 +455,11 @@ public void testPatternsDirWithCustomPatternsFilesGlob() throws JsonProcessingEx | |
pluginSetting.getSettings().put(GrokProcessorConfig.MATCH, matchConfigWithPatterns2Pattern); | ||
grokProcessorConfig = OBJECT_MAPPER.convertValue(pluginSetting.getSettings(), GrokProcessorConfig.class); | ||
|
||
Throwable throwable = assertThrows(IllegalArgumentException.class, () -> new GrokProcessor( | ||
Throwable throwable = assertThrows(InvalidPluginConfigurationException.class, () -> new GrokProcessor( | ||
pluginMetrics, grokProcessorConfig, expressionEvaluator)); | ||
assertThat("No definition for key 'CUSTOMBIRTHDAYPATTERN' found, aborting", equalTo(throwable.getMessage())); | ||
assertThat(throwable.getCause(), instanceOf(IllegalArgumentException.class)); | ||
assertThat("No definition for key 'CUSTOMBIRTHDAYPATTERN' found, aborting", equalTo(throwable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we remove the "aborting" part of this message? Small but seems a little weird for users to get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is from java-grok: https://github.com/thekrakken/java-grok/blob/master/src/main/java/io/krakens/grok/api/GrokCompiler.java#L177. It would be fragile to overwrite |
||
.getCause().getMessage())); | ||
} | ||
|
||
@Test | ||
|
@@ -522,7 +526,7 @@ public void testCompileNonRegisteredPatternThrowsIllegalArgumentException() { | |
pluginSetting.getSettings().put(GrokProcessorConfig.MATCH, matchConfig); | ||
grokProcessorConfig = OBJECT_MAPPER.convertValue(pluginSetting.getSettings(), GrokProcessorConfig.class); | ||
|
||
assertThrows(IllegalArgumentException.class, () -> new GrokProcessor( | ||
assertThrows(InvalidPluginConfigurationException.class, () -> new GrokProcessor( | ||
pluginMetrics, grokProcessorConfig, expressionEvaluator)); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.dataprepper.plugins.processor.keyvalue; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.stream.Stream; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.opensearch.dataprepper.plugins.processor.keyvalue.KeyValueProcessorConfig.FIELD_DELIMITER_REGEX_KEY; | ||
import static org.opensearch.dataprepper.plugins.processor.keyvalue.KeyValueProcessorConfig.KEY_VALUE_DELIMITER_REGEX_KEY; | ||
|
||
class KeyValueProcessorConfigTest { | ||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||
|
||
private KeyValueProcessorConfig createObjectUnderTest(final String keyValueDelimiterRegex, | ||
final String deleteKeyRegex, | ||
final String deleteValueRegex, | ||
final String fieldDelimiterRegex) { | ||
final Map<String, Object> map = new HashMap<>(); | ||
map.put(KEY_VALUE_DELIMITER_REGEX_KEY, keyValueDelimiterRegex); | ||
map.put("delete_key_regex", deleteKeyRegex); | ||
map.put("delete_value_regex", deleteValueRegex); | ||
map.put(FIELD_DELIMITER_REGEX_KEY, fieldDelimiterRegex); | ||
return OBJECT_MAPPER.convertValue(map, KeyValueProcessorConfig.class); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("provideRegexAndIsValid") | ||
void testIsKeyValueDelimiterRegexValid(final String keyValueDelimiterRegex, final boolean isValid) { | ||
final KeyValueProcessorConfig objectUnderTest = createObjectUnderTest( | ||
keyValueDelimiterRegex, null, null, null); | ||
assertThat(objectUnderTest.isKeyValueDelimiterRegexValid(), is(isValid)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("provideRegexAndIsValid") | ||
void testIsDeleteKeyRegexValid(final String deleteKeyRegex, final boolean isValid) { | ||
final KeyValueProcessorConfig objectUnderTest = createObjectUnderTest( | ||
null, deleteKeyRegex, null, null); | ||
assertThat(objectUnderTest.isDeleteKeyRegexValid(), is(isValid)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("provideRegexAndIsValid") | ||
void testIsDeleteValueRegexValid(final String deleteValueRegex, final boolean isValid) { | ||
final KeyValueProcessorConfig objectUnderTest = createObjectUnderTest( | ||
null, null, deleteValueRegex, null); | ||
assertThat(objectUnderTest.isDeleteValueRegexValid(), is(isValid)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("provideRegexAndIsValid") | ||
void testIsFieldDelimiterRegexValid(final String fieldDelimiterRegex, final boolean isValid) { | ||
final KeyValueProcessorConfig objectUnderTest = createObjectUnderTest( | ||
null, null, null, fieldDelimiterRegex); | ||
assertThat(objectUnderTest.isFieldDelimiterRegexValid(), is(isValid)); | ||
} | ||
|
||
private static Stream<Arguments> provideRegexAndIsValid() { | ||
return Stream.of( | ||
Arguments.of(null, true), | ||
Arguments.of("", true), | ||
Arguments.of("abc", true), | ||
Arguments.of("(abc", false) | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.dataprepper.plugins.processor.mutateevent; | ||
|
||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.opensearch.dataprepper.model.event.EventKey; | ||
|
||
import java.util.stream.Stream; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
class RenameKeyProcessorConfigTest { | ||
@Mock | ||
private EventKey eventKey; | ||
|
||
@ParameterizedTest | ||
@MethodSource("provideFromKeyRegexAndIsValid") | ||
void testIsFromKeyRegexValid(final String fromKeyRegex, final boolean isValid) { | ||
final RenameKeyProcessorConfig.Entry objectUnderTest = new RenameKeyProcessorConfig.Entry( | ||
null, fromKeyRegex, eventKey, false, null); | ||
assertThat(objectUnderTest.isFromKeyRegexValid(), is(isValid)); | ||
} | ||
|
||
private static Stream<Arguments> provideFromKeyRegexAndIsValid() { | ||
return Stream.of( | ||
Arguments.of(null, true), | ||
Arguments.of("", true), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can add one |
||
Arguments.of("abc", true), | ||
Arguments.of("(abc", false) | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to stop the stream processing if we encounter IllegalArugmentException? or we want to collect the errors but continue with stream processing?
Also, in the exception we are throwing, we are attaching the original
e
. Depending on whoever is handling this exception, it could potentially print the entire stacktrace for each failure and create a lot of noise in the logs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be a config validation error which means data prepper will crash at runtime. The change I made is to increase clarity on the failure message:
previous:
now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. It is not a data processing error 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one thought, instead of RuntimeException, we could possibly throw
InvalidPluginConfigurationException
to be more explicit