rule_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package engine
  11. import (
  12. "fmt"
  13. "regexp"
  14. "sort"
  15. "testing"
  16. )
  17. func TestRuleIndexSimple(t *testing.T) {
  18. ruleindexidcounter = 0
  19. defer func() {
  20. ruleindexidcounter = 0
  21. }()
  22. // Store a simple rule
  23. rule := &Rule{
  24. "TestRule", // Name
  25. "", // Description
  26. []string{"core.main.tester", "core.tmp.*"}, // Kind match
  27. []string{"data.read", "data.test"}, // Match on event cascade scope
  28. nil,
  29. 0, // Priority of the rule
  30. []string{"TestRule66"}, // List of suppressed rules by this rule
  31. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  32. return nil
  33. },
  34. }
  35. index := NewRuleIndex()
  36. index.AddRule(rule)
  37. // Check error cases
  38. err := index.AddRule(&Rule{
  39. "TestRuleError", // Name
  40. "", // Description
  41. []string{"core.main.tester"}, // Kind match
  42. nil,
  43. nil,
  44. 0, // Priority of the rule
  45. []string{"TestRule66"}, // List of suppressed rules by this rule
  46. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  47. return nil
  48. },
  49. })
  50. if err.Error() != "Cannot add rule without a scope match: TestRuleError" {
  51. t.Error("Unexpected result:", err)
  52. return
  53. }
  54. err = index.AddRule(&Rule{
  55. "TestRuleError2", // Name
  56. "", // Description
  57. nil, // Kind match
  58. []string{"data.read", "data.test"}, // Match on event cascade scope
  59. nil,
  60. 0, // Priority of the rule
  61. []string{"TestRule66"}, // List of suppressed rules by this rule
  62. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  63. return nil
  64. },
  65. })
  66. if err.Error() != "Cannot add rule without a kind match: TestRuleError2" {
  67. t.Error("Unexpected result:", err)
  68. return
  69. }
  70. // Check index layout
  71. if res := index.String(); res != `
  72. core - RuleIndexKind (0)
  73. main - RuleIndexKind (1)
  74. tester - RuleIndexKind (2)
  75. RuleIndexAll (3)
  76. Rule:TestRule [] (Priority:0 Kind:[core.main.tester core.tmp.*] Scope:[data.read data.test] StateMatch:null Suppress:[TestRule66])
  77. tmp - RuleIndexKind (1)
  78. * - RuleIndexKind (4)
  79. RuleIndexAll (5)
  80. Rule:TestRule [] (Priority:0 Kind:[core.main.tester core.tmp.*] Scope:[data.read data.test] StateMatch:null Suppress:[TestRule66])
  81. `[1:] {
  82. t.Error("Unexpected index layout:", res)
  83. return
  84. }
  85. // Check trigger queries
  86. if !index.IsTriggering(&Event{
  87. "bla",
  88. []string{"core", "tmp", "bla"},
  89. nil,
  90. }) {
  91. t.Error("Unexpected result")
  92. return
  93. }
  94. if index.IsTriggering(&Event{
  95. "bla",
  96. []string{"core", "tmp"},
  97. nil,
  98. }) {
  99. t.Error("Unexpected result")
  100. return
  101. }
  102. if index.IsTriggering(&Event{
  103. "bla",
  104. []string{"core", "tmpp", "bla"},
  105. nil,
  106. }) {
  107. t.Error("Unexpected result")
  108. return
  109. }
  110. if !index.IsTriggering(&Event{
  111. "bla",
  112. []string{"core", "main", "tester"},
  113. nil,
  114. }) {
  115. t.Error("Unexpected result")
  116. return
  117. }
  118. if index.IsTriggering(&Event{
  119. "bla",
  120. []string{"core", "main", "tester", "bla"},
  121. nil,
  122. }) {
  123. t.Error("Unexpected result")
  124. return
  125. }
  126. if index.IsTriggering(&Event{
  127. "bla",
  128. []string{"core", "main", "teste"},
  129. nil,
  130. }) {
  131. t.Error("Unexpected result")
  132. return
  133. }
  134. if index.IsTriggering(&Event{
  135. "bla",
  136. []string{"core", "main"},
  137. nil,
  138. }) {
  139. t.Error("Unexpected result")
  140. return
  141. }
  142. // Event matching
  143. if res := index.Match(&Event{
  144. "bla",
  145. []string{"core", "main", "tester"},
  146. nil,
  147. }); printRules(res) != "[TestRule]" {
  148. t.Error("Unexpected result:", res)
  149. return
  150. }
  151. if res := index.Match(&Event{
  152. "bla",
  153. []string{"core", "tmp", "x"},
  154. nil,
  155. }); printRules(res) != "[TestRule]" {
  156. t.Error("Unexpected result:", res)
  157. return
  158. }
  159. if res := index.Match(&Event{
  160. "bla",
  161. []string{"core", "tmp"},
  162. nil,
  163. }); printRules(res) != "[]" {
  164. t.Error("Unexpected result:", res)
  165. return
  166. }
  167. if res := index.Match(&Event{
  168. "bla",
  169. []string{"core", "tmp", "x", "y"},
  170. nil,
  171. }); printRules(res) != "[]" {
  172. t.Error("Unexpected result:", res)
  173. return
  174. }
  175. }
  176. func TestRuleIndexStateMatch(t *testing.T) {
  177. ruleindexidcounter = 0
  178. defer func() {
  179. ruleindexidcounter = 0
  180. }()
  181. rule1 := &Rule{
  182. "TestRule1", // Name
  183. "", // Description
  184. []string{"core.main.tester", "core.tmp.*"}, // Kind match
  185. []string{"data.read", "data.test"}, // Match on event cascade scope
  186. map[string]interface{}{ // Match on event state
  187. "name": nil,
  188. "test": "val1",
  189. },
  190. 0, // Priority of the rule
  191. []string{"TestRule66"}, // List of suppressed rules by this rule
  192. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  193. return nil
  194. },
  195. }
  196. rule2 := &Rule{
  197. "TestRule2", // Name
  198. "", // Description
  199. []string{"core.main.tester"}, // Kind match
  200. []string{"data.read"}, // Match on event cascade scope
  201. map[string]interface{}{ // Match on event state
  202. "name": nil,
  203. "test": "val2",
  204. "test2": 42,
  205. },
  206. 0, // Priority of the rule
  207. []string{"TestRule66"}, // List of suppressed rules by this rule
  208. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  209. return nil
  210. },
  211. }
  212. rule3 := &Rule{
  213. "TestRule3", // Name
  214. "", // Description
  215. []string{"core.main.tester"}, // Kind match
  216. []string{"data.read"}, // Match on event cascade scope
  217. map[string]interface{}{ // Match on event state
  218. "name": nil,
  219. "test": "val2",
  220. "test2": 42,
  221. "test3": 15,
  222. },
  223. 0, // Priority of the rule
  224. []string{"TestRule66"}, // List of suppressed rules by this rule
  225. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  226. return nil
  227. },
  228. }
  229. index := NewRuleIndex()
  230. index.AddRule(rule1)
  231. index.AddRule(rule2)
  232. index.AddRule(rule3)
  233. if err := index.AddRule(rule3); err.Error() != "Cannot add rule TestRule3 twice" {
  234. t.Error("Unexpected result:", err)
  235. return
  236. }
  237. if len(index.Rules()) != 3 {
  238. t.Error("Unexpected number of rules:", len(index.Rules()))
  239. }
  240. // Check index layout
  241. if res := index.String(); res != `
  242. core - RuleIndexKind (0)
  243. main - RuleIndexKind (1)
  244. tester - RuleIndexKind (2)
  245. RuleIndexState (3) [TestRule1 TestRule2 TestRule3 ]
  246. name - 00000007 *:00000007 [] []
  247. test - 00000007 *:00000000 [val1:00000001 val2:00000006 ] []
  248. test2 - 00000006 *:00000000 [42:00000006 ] []
  249. test3 - 00000004 *:00000000 [15:00000004 ] []
  250. tmp - RuleIndexKind (1)
  251. * - RuleIndexKind (4)
  252. RuleIndexState (5) [TestRule1 ]
  253. name - 00000001 *:00000001 [] []
  254. test - 00000001 *:00000000 [val1:00000001 ] []
  255. `[1:] {
  256. t.Error("Unexpected index layout:", res)
  257. return
  258. }
  259. // Make sure events without state do not match
  260. if res := index.Match(&Event{
  261. "bla",
  262. []string{"core", "tmp", "x"},
  263. nil,
  264. }); printRules(res) != "[]" {
  265. t.Error("Unexpected result:", res)
  266. return
  267. }
  268. // Single rule match
  269. if res := index.Match(&Event{
  270. "bla",
  271. []string{"core", "tmp", "x"},
  272. map[interface{}]interface{}{ // Match on event state
  273. "name": nil,
  274. "test": "val1",
  275. },
  276. }); printRules(res) != "[TestRule1]" {
  277. t.Error("Unexpected result:", res)
  278. return
  279. }
  280. if res := index.Match(&Event{
  281. "bla",
  282. []string{"core", "main", "tester"},
  283. map[interface{}]interface{}{ // Match on event state
  284. "name": nil,
  285. "test": "val1",
  286. },
  287. }); printRules(res) != "[TestRule1]" {
  288. t.Error("Unexpected result:", res)
  289. return
  290. }
  291. if res := index.Match(&Event{
  292. "bla",
  293. []string{"core", "main", "tester"},
  294. map[interface{}]interface{}{ // Match on event state
  295. "name": "foobar",
  296. "test": "val2",
  297. "test2": 42,
  298. },
  299. }); printRules(res) != "[TestRule2]" {
  300. t.Error("Unexpected result:", res)
  301. return
  302. }
  303. // Test multiple rule match
  304. if res := index.Match(&Event{
  305. "bla",
  306. []string{"core", "main", "tester"},
  307. map[interface{}]interface{}{ // Match on event state
  308. "name": nil,
  309. "test": "val2",
  310. "test2": 42,
  311. "test3": 15,
  312. },
  313. }); printRules(res) != "[TestRule2 TestRule3]" {
  314. t.Error("Unexpected result:", res)
  315. return
  316. }
  317. }
  318. func TestRuleIndexStateRegexMatch(t *testing.T) {
  319. ruleindexidcounter = 0
  320. defer func() {
  321. ruleindexidcounter = 0
  322. }()
  323. rule1 := &Rule{
  324. "TestRule1", // Name
  325. "", // Description
  326. []string{"core.main.tester", "core.tmp.*"}, // Kind match
  327. []string{"data.read", "data.test"}, // Match on event cascade scope
  328. map[string]interface{}{ // Match on event state
  329. "name": nil,
  330. "test": regexp.MustCompile("val.*"),
  331. },
  332. 0, // Priority of the rule
  333. []string{"TestRule66"}, // List of suppressed rules by this rule
  334. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  335. return nil
  336. },
  337. }
  338. rule2 := &Rule{
  339. "TestRule2", // Name
  340. "", // Description
  341. []string{"core.main.tester"}, // Kind match
  342. []string{"data.read"}, // Match on event cascade scope
  343. map[string]interface{}{ // Match on event state
  344. "name": nil,
  345. "test": regexp.MustCompile("va..*"),
  346. },
  347. 0, // Priority of the rule
  348. []string{"TestRule66"}, // List of suppressed rules by this rule
  349. func(p Processor, m Monitor, e *Event) error { // Action of the rule
  350. return nil
  351. },
  352. }
  353. index := NewRuleIndex()
  354. index.AddRule(rule1)
  355. index.AddRule(rule2)
  356. // Check index layout
  357. if res := index.String(); res != `
  358. core - RuleIndexKind (0)
  359. main - RuleIndexKind (1)
  360. tester - RuleIndexKind (2)
  361. RuleIndexState (3) [TestRule1 TestRule2 ]
  362. name - 00000003 *:00000003 [] []
  363. test - 00000003 *:00000003 [] [00000001:val.* 00000002:va..* ]
  364. tmp - RuleIndexKind (1)
  365. * - RuleIndexKind (4)
  366. RuleIndexState (5) [TestRule1 ]
  367. name - 00000001 *:00000001 [] []
  368. test - 00000001 *:00000001 [] [00000001:val.* ]
  369. `[1:] {
  370. t.Error("Unexpected index layout:", res)
  371. return
  372. }
  373. if res := index.Match(&Event{
  374. "bla",
  375. []string{"core", "tmp", "x"},
  376. map[interface{}]interface{}{ // Match on event state
  377. "name": "boo",
  378. "test": "val1",
  379. },
  380. }); printRules(res) != "[TestRule1]" {
  381. t.Error("Unexpected result:", res)
  382. return
  383. }
  384. if res := index.Match(&Event{
  385. "bla",
  386. []string{"core", "tmp", "x"},
  387. map[interface{}]interface{}{ // Match on event state
  388. "name": "boo",
  389. "test": "val",
  390. },
  391. }); printRules(res) != "[TestRule1]" {
  392. t.Error("Unexpected result:", res)
  393. return
  394. }
  395. if res := index.Match(&Event{
  396. "bla",
  397. []string{"core", "main", "tester"},
  398. map[interface{}]interface{}{ // Match on event state
  399. "name": "boo",
  400. "test": "var",
  401. },
  402. }); printRules(res) != "[TestRule2]" {
  403. t.Error("Unexpected result:", res)
  404. return
  405. }
  406. if res := index.Match(&Event{
  407. "bla",
  408. []string{"core", "main", "tester"},
  409. map[interface{}]interface{}{ // Match on event state
  410. "name": "boo",
  411. "test": "val",
  412. },
  413. }); printRules(res) != "[TestRule1 TestRule2]" {
  414. t.Error("Unexpected result:", res)
  415. return
  416. }
  417. // Test error cases
  418. if res := index.IsTriggering(&Event{
  419. "bla",
  420. []string{"core", "main", "tester", "a"},
  421. map[interface{}]interface{}{ // Match on event state
  422. "name": "boo",
  423. "test": "val",
  424. },
  425. }); res {
  426. t.Error("Unexpected result:", res)
  427. return
  428. }
  429. if res := index.Match(&Event{
  430. "bla",
  431. []string{"core", "main", "tester", "a"},
  432. map[interface{}]interface{}{ // Match on event state
  433. "name": "boo",
  434. "test": "val",
  435. },
  436. }); printRules(res) != "[]" {
  437. t.Error("Unexpected result:", res)
  438. return
  439. }
  440. }
  441. func printRules(rules []*Rule) string {
  442. var ret []string
  443. for _, r := range rules {
  444. ret = append(ret, r.Name)
  445. }
  446. sort.Strings(ret)
  447. return fmt.Sprint(ret)
  448. }