Skip to content
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

Expressions with null #1946

Merged
merged 4 commits into from
Oct 25, 2022

Conversation

kkondaka
Copy link
Collaborator

Description

Added support for checking for "null" in the expressions.
With this change expressions like /response == null or /response != null can be specified as shown below

 processor:
     - grok:
        match:
          message: ['%{IPORHOST:clientip} (?:%{WORD:ident}|-) (%{USER:auth}|-) \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{BASE10NUM:timetaken} "(?:%{WORD:ref}|-)" %{GREEDYDATA:useragent}']
    - drop_events:
         drop_when '/request == null'

Issues Resolved

[List any issues this PR will resolve]
#1136

Check List

  • [X ] New functionality includes testing.
  • [X ] New functionality has been documented.
    • New functionality has javadoc added
  • [X ] Commits are signed with a real name per the DCO

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@kkondaka kkondaka requested a review from a team as a code owner October 19, 2022 18:18
@codecov-commenter
Copy link

codecov-commenter commented Oct 19, 2022

Codecov Report

Merging #1946 (10820ef) into main (941f808) will increase coverage by 0.04%.
The diff coverage is 100.00%.

@@             Coverage Diff              @@
##               main    #1946      +/-   ##
============================================
+ Coverage     93.88%   93.92%   +0.04%     
- Complexity     1536     1537       +1     
============================================
  Files           197      197              
  Lines          4561     4562       +1     
  Branches        367      367              
============================================
+ Hits           4282     4285       +3     
+ Misses          196      194       -2     
  Partials         83       83              
Impacted Files Coverage Δ
...taprepper/expression/ParseTreeCoercionService.java 100.00% <100.00%> (ø)
...rwarder/discovery/AwsCloudMapPeerListProvider.java 95.12% <0.00%> (+2.43%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@@ -83,6 +83,8 @@ Examples
/status_code == 200 and /message == "Hello world"
/status_code == 200 or /status_code == 202
not /status_code in {200, 202}
/response == null
/response != null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there another place where we can state that null is the syntax for null checking?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a statement in the "literals" section. - Null _(Supports null check to see if a Json Pointer is present or not)_. Is that not clear enough?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more documentation with examples.

@@ -42,6 +42,8 @@ public Object coercePrimaryTerminalNode(final TerminalNode node, final Event eve
return Float.valueOf(nodeStringValue);
case DataPrepperExpressionParser.Boolean:
return Boolean.valueOf(nodeStringValue);
case DataPrepperExpressionParser.Null:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class has a unit test and this change should be tested there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought that's what the change in this file - data-prepper-expression/src/test/java/org/opensearch/dataprepper/expression/ParseTreeEvaluatorListenerTest.java? Is there another unit test file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a unit test in data-prepper-expression/src/test/java/org/opensearch/dataprepper/expression/ParseTreeCoercionServiceTest.java

@@ -129,6 +129,9 @@ private static Stream<Arguments> validExpressionArguments() {
Arguments.of("true == (/is_cool == true)", event("{\"is_cool\": true}"), true),
Arguments.of("not /is_cool", event("{\"is_cool\": true}"), false),
Arguments.of("/status_code < 300", event("{\"status_code\": 200}"), true),
Arguments.of("/status_code != null", event("{\"status_code\": 200}"), true),
Arguments.of("/response == null", event("{\"status_code\": 200}"), true),
Arguments.of("/response != null", event("{\"status_code\": 200}"), false),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think there is any use in adding a test like the following?

Arguments.of("/status_code == null", event("{\"status_code\": null}"), true),

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend adding a few test cases with null on the left had side to test operators do not throw unexpected exceptions.

An example where a bug could occur:
Given a hypothetical operator foo that checks for class equality implemented as (lhs, rhs) -> lhs.getClass().equals(rhs.getClass())

When invoked null foo null

Then a NullPointerException will be thrown instead of true

Copy link
Collaborator Author

@kkondaka kkondaka Oct 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting... Is it possible to have such input? I can add the test case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added few test cases with null on the left side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@@ -42,6 +42,8 @@ public Object coercePrimaryTerminalNode(final TerminalNode node, final Event eve
return Float.valueOf(nodeStringValue);
case DataPrepperExpressionParser.Boolean:
return Boolean.valueOf(nodeStringValue);
case DataPrepperExpressionParser.Null:
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that this works out of box with the operators. But, should this be some sort of special class - like NullValue? I suppose this could come later if that provides specific value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly, I have no idea. I will follow what you suggest here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not matter. And we can change it later since these are internal classes.

Copy link
Member

@sbayer55 sbayer55 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding null value support. It's cool to see Data Prepper Expressions syntax grow.

@@ -129,6 +129,9 @@ private static Stream<Arguments> validExpressionArguments() {
Arguments.of("true == (/is_cool == true)", event("{\"is_cool\": true}"), true),
Arguments.of("not /is_cool", event("{\"is_cool\": true}"), false),
Arguments.of("/status_code < 300", event("{\"status_code\": 200}"), true),
Arguments.of("/status_code != null", event("{\"status_code\": 200}"), true),
Arguments.of("/response == null", event("{\"status_code\": 200}"), true),
Arguments.of("/response != null", event("{\"status_code\": 200}"), false),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend adding a few test cases with null on the left had side to test operators do not throw unexpected exceptions.

An example where a bug could occur:
Given a hypothetical operator foo that checks for class equality implemented as (lhs, rhs) -> lhs.getClass().equals(rhs.getClass())

When invoked null foo null

Then a NullPointerException will be thrown instead of true

…Expressions

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
…Expressions - added more tests

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
…Expressions - updated docs

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
Copy link
Member

@dlvenable dlvenable left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for expanding the conditional support with this! And thanks for making the requested test changes to help ensure quality!

@dlvenable dlvenable merged commit 7a6f747 into opensearch-project:main Oct 25, 2022
@kkondaka kkondaka deleted the expressions-with-null branch February 2, 2023 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants