@@ -2,7 +2,7 @@ module Agents |
||
| 2 | 2 |
class TriggerAgent < Agent |
| 3 | 3 |
cannot_be_scheduled! |
| 4 | 4 |
|
| 5 |
- VALID_COMPARISON_TYPES = %w[regex !regex field<value field<=value field==value field!=value field>=value field>value] |
|
| 5 |
+ VALID_COMPARISON_TYPES = %w[regex !regex field<value field<=value field==value field!=value field>=value field>value not\ in] |
|
| 6 | 6 |
|
| 7 | 7 |
description <<-MD |
| 8 | 8 |
The Trigger Agent will watch for a specific value in an Event payload. |
@@ -11,7 +11,7 @@ module Agents |
||
| 11 | 11 |
|
| 12 | 12 |
The `type` can be one of #{VALID_COMPARISON_TYPES.map { |t| "`#{t}`" }.to_sentence} and compares with the `value`. Note that regex patterns are matched case insensitively. If you want case sensitive matching, prefix your pattern with `(?-i)`.
|
| 13 | 13 |
|
| 14 |
- The `value` can be a single value or an array of values. In the case of an array, if one or more values match then the rule matches. |
|
| 14 |
+ The `value` can be a single value or an array of values. In the case of an array, all items must be strings, and if one or more values match, then the rule matches. Note: avoid using `field!=value` with arrays, you should use `not in` instead. |
|
| 15 | 15 |
|
| 16 | 16 |
By default, all rules must match for the Agent to trigger. You can switch this so that only one rule must match by |
| 17 | 17 |
setting `must_match` to `1`. |
@@ -75,26 +75,30 @@ module Agents |
||
| 75 | 75 |
rule_values = rule['value'] |
| 76 | 76 |
rule_values = [rule_values] unless rule_values.is_a?(Array) |
| 77 | 77 |
|
| 78 |
- rule_values.any? do |rule_value| |
|
| 79 |
- case rule['type'] |
|
| 80 |
- when "regex" |
|
| 81 |
- value_at_path.to_s =~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 82 |
- when "!regex" |
|
| 83 |
- value_at_path.to_s !~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 84 |
- when "field>value" |
|
| 85 |
- value_at_path.to_f > rule_value.to_f |
|
| 86 |
- when "field>=value" |
|
| 87 |
- value_at_path.to_f >= rule_value.to_f |
|
| 88 |
- when "field<value" |
|
| 89 |
- value_at_path.to_f < rule_value.to_f |
|
| 90 |
- when "field<=value" |
|
| 91 |
- value_at_path.to_f <= rule_value.to_f |
|
| 92 |
- when "field==value" |
|
| 93 |
- value_at_path.to_s == rule_value.to_s |
|
| 94 |
- when "field!=value" |
|
| 95 |
- value_at_path.to_s != rule_value.to_s |
|
| 96 |
- else |
|
| 97 |
- raise "Invalid type of #{rule['type']} in TriggerAgent##{id}"
|
|
| 78 |
+ if rule['type'] == 'not in' |
|
| 79 |
+ !rule_values.include?(value_at_path.to_s) |
|
| 80 |
+ elsif rule['type'] == 'field==value' |
|
| 81 |
+ rule_values.include?(value_at_path.to_s) |
|
| 82 |
+ else |
|
| 83 |
+ rule_values.any? do |rule_value| |
|
| 84 |
+ case rule['type'] |
|
| 85 |
+ when "regex" |
|
| 86 |
+ value_at_path.to_s =~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 87 |
+ when "!regex" |
|
| 88 |
+ value_at_path.to_s !~ Regexp.new(rule_value, Regexp::IGNORECASE) |
|
| 89 |
+ when "field>value" |
|
| 90 |
+ value_at_path.to_f > rule_value.to_f |
|
| 91 |
+ when "field>=value" |
|
| 92 |
+ value_at_path.to_f >= rule_value.to_f |
|
| 93 |
+ when "field<value" |
|
| 94 |
+ value_at_path.to_f < rule_value.to_f |
|
| 95 |
+ when "field<=value" |
|
| 96 |
+ value_at_path.to_f <= rule_value.to_f |
|
| 97 |
+ when "field!=value" |
|
| 98 |
+ value_at_path.to_s != rule_value.to_s |
|
| 99 |
+ else |
|
| 100 |
+ raise "Invalid type of #{rule['type']} in TriggerAgent##{id}"
|
|
| 101 |
+ end |
|
| 98 | 102 |
end |
| 99 | 103 |
end |
| 100 | 104 |
end |
@@ -270,6 +270,28 @@ describe Agents::TriggerAgent do |
||
| 270 | 270 |
}.to change { Event.count }.by(1)
|
| 271 | 271 |
end |
| 272 | 272 |
|
| 273 |
+ it "handles array of `not in` comparisons" do |
|
| 274 |
+ @event.payload['foo']['bar']['baz'] = "hello world" |
|
| 275 |
+ @checker.options['rules'].first['type'] = "not in" |
|
| 276 |
+ @checker.options['rules'].first['value'] = ["hello world", "hello world"] |
|
| 277 |
+ |
|
| 278 |
+ expect {
|
|
| 279 |
+ @checker.receive([@event]) |
|
| 280 |
+ }.not_to change { Event.count }
|
|
| 281 |
+ |
|
| 282 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello world"] |
|
| 283 |
+ |
|
| 284 |
+ expect {
|
|
| 285 |
+ @checker.receive([@event]) |
|
| 286 |
+ }.not_to change { Event.count }
|
|
| 287 |
+ |
|
| 288 |
+ @checker.options['rules'].first['value'] = ["hello there", "hello here"] |
|
| 289 |
+ |
|
| 290 |
+ expect {
|
|
| 291 |
+ @checker.receive([@event]) |
|
| 292 |
+ }.to change { Event.count }.by(1)
|
|
| 293 |
+ end |
|
| 294 |
+ |
|
| 273 | 295 |
it "does fine without dots in the path" do |
| 274 | 296 |
@event.payload = { 'hello' => "world" }
|
| 275 | 297 |
@checker.options['rules'].first['type'] = "field==value" |