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

Add hasTags() function to dataprepper expressions #2680

Merged
merged 6 commits into from
May 12, 2023

Conversation

kkondaka
Copy link
Collaborator

Description

Add hasTags() function to dataprepper expressions.
Data Prepper expressions can now check about presence of tags in the event.
For example an expression may look like
hasTag("tag1") and /status_code == 200
which returns true if the event has a tag with name "tag1" and status_code value is 200.

Resolves #629

Issues Resolved

#629

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.

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
tags = new ArrayList<>();
Random random = new Random();
numTags = random.nextInt(9) + 1;
for (int i = 0; i < numTags; i++) {
Copy link
Member

Choose a reason for hiding this comment

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

I think we should control the number of arguments in the testing.

That is, we should test with some specific number of arguments. I'd definitely recommend testing with 1 argument and "more than 1" argument - could be 2, could be 10.

This could be done through @Nested. But, I think this could also be done using @ParameterizedTest where you parameterize the number of tags.

e.g.

@ParameterizedTest
@ValueSource(ints = { 1, 2, 10 }    
void testHasTagsBasic(int numTags /* Also, remove the field used */) {
    hasTagsExpressionFunction = createObjectUnderTest();
    tags = generateTags(numTags); // refactor this code to generate the tags on the fly
    for (int i = 1; i <= numTags; i++) {
        assertThat(hasTagsExpressionFunction.evaluate(tags.subList(0, i), testEvent, testFunction), equalTo(true));
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

This might be improved upon by my more recent suggestion to add EventMetadata::hasTags.

if (args.size() == 0) {
throw new RuntimeException("hasTags() takes at least one argument");
}
Set<String> tags = event.getMetadata().getTags();
Copy link
Member

@dlvenable dlvenable May 11, 2023

Choose a reason for hiding this comment

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

I think we may benefit from adding the hasTags() method to the EventMetadata.

This has a couple benefits in my opinion:

  1. It separates the concerns - determining whether an Event has a tag versus interpreting the function arguments.
  2. It creates a function that could end up being useful elsewhere.
  3. You can make the tests for this focus more on the arguments.

In EventMetadata:

boolean hasTags(List<String> tags) {
  for(String tag : tags) {
    if(!tags.contains(tag)) {
      return false;
    }
  }
  return true;
}

This code can then be something like:

if(!args.stream()
  .allMatch(a -> a instanceof String)) {
    throw new RuntimeException("...");
}
final List<String> tags = args.stream()
  .map(a -> (String) a)
  .collect(Collectors.toList());
return event.getMetadata().hasTags(tags);

- takes at least one argument
- all arguments must be of String type
- returns true if all arguments are present in the event's tags, returns false otherwise
For example, if event has tags "tag1", "tag2", and "tag3", `hasTags("tag1")` or `hasTags("tag1", "tag2")` would return true and `hasTags("tag4")` would return false.
Copy link
Member

Choose a reason for hiding this comment

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

What about hasTags("tag1", "tag4")? False? Please add this as an example as well

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
assertTrue(result.hasTag("tag1"));
assertTrue(result.hasTag("tag2"));
assertTrue(result.hasTag("tag3"));
assertTrue(result.hasTags(List.of("tag1")));
Copy link
Member

Choose a reason for hiding this comment

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

We should have some negative tests cases.

assertFalse(result.hasTag("notPresent");
assertFalse(result.hasTag("notPresent1", "notPresent2");
assertFalse(result.hasTag("tag1", "notPresent");

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

codecov bot commented May 12, 2023

Codecov Report

Merging #2680 (0237ddb) into main (a63e5d8) will decrease coverage by 0.02%.
The diff coverage is 100.00%.

@@             Coverage Diff              @@
##               main    #2680      +/-   ##
============================================
- Coverage     93.56%   93.54%   -0.02%     
- Complexity     2238     2250      +12     
============================================
  Files           261      262       +1     
  Lines          6275     6291      +16     
  Branches        519      520       +1     
============================================
+ Hits           5871     5885      +14     
- Misses          266      268       +2     
  Partials        138      138              
Impacted Files Coverage Δ
.../dataprepper/model/event/DefaultEventMetadata.java 91.30% <100.00%> (+0.82%) ⬆️
...aprepper/expression/HasTagsExpressionFunction.java 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

…literals

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
@@ -21,11 +21,14 @@ public Object evaluate(final List<Object> args, Event event, Function<Object, Ob
if (args.size() == 0) {
throw new RuntimeException("hasTags() takes at least one argument");
}
if(!args.stream().allMatch(a -> a instanceof String)) {
throw new RuntimeException("hasTags() takes only String type arguments");
if(!args.stream().allMatch(a -> ((a instanceof String) && (((String)a).length() > 0) && (((String)a).charAt(0) == '"')))) {
Copy link
Member

Choose a reason for hiding this comment

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

I'd probably consider splitting this so that if this error pops up, we can better know which situation it is. But, I don't think this is critical for now.

}
final List<String> tags = args.stream()
.map(a -> (String) a)
.map(a -> {
Copy link
Member

Choose a reason for hiding this comment

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

You can split map functions so that you can use the compact lambda form. This is not critical though.

.map(a -> (String)a)
.map(str -> str.substring(1, str.length() - 1))

@kkondaka kkondaka merged commit ee43a60 into opensearch-project:main May 12, 2023
26 checks passed
rajeshLovesToCode pushed a commit to rajeshLovesToCode/data-prepper that referenced this pull request May 16, 2023
…#2680)

* Add hasTags() function to dataprepper expressions

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

* Addressed review comments

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

* Updated documentation

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

* Addressed review comments

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

* Fixed code coverage build failure

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

* Modified to make sure that the arguments passed to hasTags is string literals

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

---------

Signed-off-by: Krishna Kondaka <krishkdk@amazon.com>
Signed-off-by: rajeshLovesToCode <rajesh.dharamdasani3021@gmail.com>
rajeshLovesToCode added a commit to rajeshLovesToCode/data-prepper that referenced this pull request May 18, 2023
rajeshLovesToCode added a commit to rajeshLovesToCode/data-prepper that referenced this pull request May 18, 2023
@kkondaka kkondaka deleted the has-tags-func branch July 13, 2023 04:33
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.

Tagging Events in Data Prepper
3 participants