2020-06-29 23:19:23 -06:00
|
|
|
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
2021-03-03 22:12:11 -09:00
|
|
|
# or more contributor license agreements. Licensed under the Elastic License
|
|
|
|
|
# 2.0; you may not use this file except in compliance with the Elastic License
|
|
|
|
|
# 2.0.
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
import kql
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
document = {
|
|
|
|
|
"number": 1,
|
|
|
|
|
"boolean": True,
|
|
|
|
|
"ip": "192.168.16.3",
|
|
|
|
|
"string": "hello world",
|
|
|
|
|
"string_list": ["hello world", "example"],
|
|
|
|
|
"number_list": [1, 2, 3],
|
|
|
|
|
"boolean_list": [True, False],
|
|
|
|
|
"structured": [{"a": [{"b": 1}]}],
|
|
|
|
|
}
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
class EvaluatorTests(unittest.TestCase):
|
|
|
|
|
def evaluate(self, source_text):
|
2020-06-29 23:19:23 -06:00
|
|
|
evaluator = kql.get_evaluator(source_text, optimize=False)
|
|
|
|
|
return evaluator(document)
|
|
|
|
|
|
|
|
|
|
def test_single_value(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number:1"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertTrue(self.evaluate('number:"1"'))
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("boolean:true"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertTrue(self.evaluate('string:"hello world"'))
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("number:0"))
|
|
|
|
|
self.assertFalse(self.evaluate("boolean:false"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertFalse(self.evaluate('string:"missing"'))
|
|
|
|
|
|
|
|
|
|
def test_list_value(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number_list:1"))
|
|
|
|
|
self.assertTrue(self.evaluate("number_list:2"))
|
|
|
|
|
self.assertTrue(self.evaluate("number_list:3"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("boolean_list:true"))
|
|
|
|
|
self.assertTrue(self.evaluate("boolean_list:false"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
self.assertTrue(self.evaluate('string_list:"hello world"'))
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("string_list:example"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("number_list:4"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertFalse(self.evaluate('string_list:"missing"'))
|
|
|
|
|
|
|
|
|
|
def test_and_values(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number_list:(1 and 2)"))
|
|
|
|
|
self.assertTrue(self.evaluate("boolean_list:(false and true)"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertFalse(self.evaluate('string:("missing" and "hello world")'))
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("number:(0 and 1)"))
|
|
|
|
|
self.assertFalse(self.evaluate("boolean:(false and true)"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_not_value(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number_list:1"))
|
|
|
|
|
self.assertFalse(self.evaluate("not number_list:1"))
|
|
|
|
|
self.assertFalse(self.evaluate("number_list:(not 1)"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_or_values(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number:(0 or 1)"))
|
|
|
|
|
self.assertTrue(self.evaluate("number:(1 or 2)"))
|
|
|
|
|
self.assertTrue(self.evaluate("boolean:(false or true)"))
|
2020-06-29 23:19:23 -06:00
|
|
|
self.assertTrue(self.evaluate('string:("missing" or "hello world")'))
|
|
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("number:(0 or 3)"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_and_expr(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number:1 and boolean:true"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("number:1 and boolean:false"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_or_expr(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number:1 or boolean:false"))
|
|
|
|
|
self.assertFalse(self.evaluate("number:0 or boolean:false"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_range(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number < 2"))
|
|
|
|
|
self.assertFalse(self.evaluate("number > 2"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_cidr_match(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("ip:192.168.0.0/16"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertFalse(self.evaluate("ip:10.0.0.0/8"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_quoted_wildcard(self):
|
2022-04-22 03:44:39 +00:00
|
|
|
self.assertFalse(self.evaluate("string:'*'"))
|
|
|
|
|
self.assertFalse(self.evaluate("string:'?'"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_wildcard(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("string:hello*"))
|
|
|
|
|
self.assertTrue(self.evaluate("string:*world"))
|
|
|
|
|
self.assertFalse(self.evaluate("string:foobar*"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_field_exists(self):
|
2025-07-01 15:20:55 +02:00
|
|
|
self.assertTrue(self.evaluate("number:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("boolean:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("ip:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("string:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("string_list:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("number_list:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("boolean_list:*"))
|
|
|
|
|
|
|
|
|
|
self.assertFalse(self.evaluate("a:*"))
|
2020-06-29 23:19:23 -06:00
|
|
|
|
|
|
|
|
def test_flattening(self):
|
|
|
|
|
self.assertTrue(self.evaluate("structured.a.b:*"))
|
|
|
|
|
self.assertTrue(self.evaluate("structured.a.b:1"))
|
|
|
|
|
self.assertFalse(self.evaluate("structured.a.b:2"))
|