@@ -16,7 +16,7 @@ class Agent < ActiveRecord::Base |
||
16 | 16 |
load_types_in "Agents" |
17 | 17 |
|
18 | 18 |
SCHEDULES = %w[every_2m every_5m every_10m every_30m every_1h every_2h every_5h every_12h every_1d every_2d every_7d |
19 |
- midnight 1am 2am 3am 4am 5am 6am 7am 8am 9am 10am 11am noon 1pm 2pm 3pm 4pm 5pm 6pm 7pm 8pm 9pm 10pm 11pm] |
|
19 |
+ midnight 1am 2am 3am 4am 5am 6am 7am 8am 9am 10am 11am noon 1pm 2pm 3pm 4pm 5pm 6pm 7pm 8pm 9pm 10pm 11pm never] |
|
20 | 20 |
|
21 | 21 |
EVENT_RETENTION_SCHEDULES = [["Forever", 0], ["1 day", 1], *([2, 3, 4, 5, 7, 14, 21, 30, 45, 90, 180, 365].map {|n| ["#{n} days", n] })] |
22 | 22 |
|
@@ -296,6 +296,7 @@ class Agent < ActiveRecord::Base |
||
296 | 296 |
# Given a schedule name, run `check` via `bulk_check` on all Agents with that schedule. |
297 | 297 |
# This is called by bin/schedule.rb for each schedule in `SCHEDULES`. |
298 | 298 |
def run_schedule(schedule) |
299 |
+ return if schedule == 'never' |
|
299 | 300 |
types = where(:schedule => schedule).group(:type).pluck(:type) |
300 | 301 |
types.each do |type| |
301 | 302 |
type.constantize.bulk_check(schedule) |
@@ -1,108 +0,0 @@ |
||
1 |
-require 'date' |
|
2 |
-require 'cgi' |
|
3 |
-module Agents |
|
4 |
- class CodeAgent < Agent |
|
5 |
- #cannot_receive_events! |
|
6 |
- #cannot_be_scheduled! |
|
7 |
- description <<-MD |
|
8 |
- Here is an agent that gives you the ability to specify your own code. We have already provided you |
|
9 |
- a javascript object that has read and write access to this agent's memory, and read access to events, options and the attributes of the agent. |
|
10 |
- We also provide you with a method to create events on the server. |
|
11 |
- You will be provided with an instance of the Agent object in javascript, with access to the above data. |
|
12 |
- You can create events based on your own logic. |
|
13 |
- Specifically, you have the following class, lets say, present is a string "js_code". |
|
14 |
- |
|
15 |
- function Agent(e, o, agent){ |
|
16 |
- this.events = JSON.parse(e); |
|
17 |
- this.options = JSON.parse(o); |
|
18 |
- this.agent = JSON.parse(agent); |
|
19 |
- } |
|
20 |
- Agent.prototype.check = function(){ |
|
21 |
- // Implement me |
|
22 |
- } |
|
23 |
- Agent.prototype.receive = function(){ |
|
24 |
- // Implement me |
|
25 |
- } |
|
26 |
- You need to provide the code for the Agent::check and Agent::receive function. You code will override any methods already present in the Agent if it has to, and you can use other methods as well with access to the agent properties. You need to at least provide the implementation of Agent.prototype.check and Agent.prototype.receive so that it can be called periodically, or it can execute when an event happens. |
|
27 |
- |
|
28 |
- We will yield control to your implementation in the following way: |
|
29 |
- |
|
30 |
- context.eval(js_code); //this is the code that declares the class Agent, and provides a global create_event method. |
|
31 |
- context.eval("a = new Agent(events, options, agent)") |
|
32 |
- context.eval(options['code']) |
|
33 |
- If you agent fires periodically { |
|
34 |
- context.eval("a.check();") |
|
35 |
- } else if your agent responds when an event happens { |
|
36 |
- context.eval("a.receive();") |
|
37 |
- } |
|
38 |
- |
|
39 |
- If your agent responds to events it receive, you need to implement the receive() method, and if you agent fires periodically, you need to implement check(). If your agent does both, please implement both! |
|
40 |
- |
|
41 |
- MD |
|
42 |
- def example_js |
|
43 |
- <<-H |
|
44 |
- function Agent(e, o, agent){ |
|
45 |
- this.events = JSON.parse(e); |
|
46 |
- this.options = JSON.parse(o); |
|
47 |
- this.agent = JSON.parse(agent); |
|
48 |
- } |
|
49 |
- Agent.prototype.memory = function(key,value){ |
|
50 |
- if (typeof(key) != "undefined" && typeof(value) != "undefined") { |
|
51 |
- var mem = JSON.parse(access_memory(JSON.stringify(key), JSON.stringify(value))); |
|
52 |
- return JSON.stringify(mem); |
|
53 |
- } else { |
|
54 |
- var mem = JSON.parse(access_memory()); |
|
55 |
- return JSON.stringify(mem); |
|
56 |
- } |
|
57 |
- } |
|
58 |
- Agent.prototype.check = function(){ |
|
59 |
- } |
|
60 |
- Agent.prototype.receive = function(){ |
|
61 |
- } |
|
62 |
- H |
|
63 |
- end |
|
64 |
- |
|
65 |
- def working? |
|
66 |
- return false if recent_error_logs? |
|
67 |
- if options['expected_update_period_in_days'].present? |
|
68 |
- return false unless event_created_within?(options['expected_update_period_in_days']) |
|
69 |
- end |
|
70 |
- if options['expected_receive_period_in_days'].present? |
|
71 |
- return false unless last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago |
|
72 |
- end |
|
73 |
- true |
|
74 |
- end |
|
75 |
- |
|
76 |
- def execute_js(incoming_events, js_function = "check") |
|
77 |
- js_function = (js_function == "check" ? "check" : "receive") |
|
78 |
- context = V8::Context.new |
|
79 |
- context.eval(example_js) |
|
80 |
- context["create_event"] = lambda {|x,y| puts x; puts y; create_event payload: JSON.parse(y)} |
|
81 |
- context["access_memory"] = lambda {|a, x, y| x && y ? (memory[x] = y; memory.to_json) : memory.to_json } |
|
82 |
- |
|
83 |
- context.eval(options['code']) # should override the run function. |
|
84 |
- a, e, o = [self.attributes.to_json, incoming_events.to_json, self.options.to_json] |
|
85 |
- string = "a = new Agent('#{e}','#{o}','#{a}');" |
|
86 |
- context.eval(string) |
|
87 |
- runner = "a.#{js_function}();" |
|
88 |
- context.eval(runner) |
|
89 |
- end |
|
90 |
- |
|
91 |
- def check |
|
92 |
- execute_js("") |
|
93 |
- end |
|
94 |
- |
|
95 |
- def receive(incoming_events) |
|
96 |
- execute_js(incoming_events) |
|
97 |
- end |
|
98 |
- |
|
99 |
- def default_options |
|
100 |
- js_code = "Agent.prototype.check = function(){ var pd = JSON.stringify({memory: this.memory(), events: this.events, options: this.options});create_event(pd); };Agent.prototype.receive = function(){ var pd = JSON.stringify({memory: this.memory(), events: this.events, options: this.options});create_event(pd); }" |
|
101 |
- { |
|
102 |
- "code" => js_code, |
|
103 |
- 'expected_receive_period_in_days' => "2", |
|
104 |
- 'expected_update_period_in_days' => "2" |
|
105 |
- } |
|
106 |
- end |
|
107 |
- end |
|
108 |
-end |
@@ -0,0 +1,169 @@ |
||
1 |
+require 'date' |
|
2 |
+require 'cgi' |
|
3 |
+ |
|
4 |
+module Agents |
|
5 |
+ class JavaScriptAgent < Agent |
|
6 |
+ default_schedule "never" |
|
7 |
+ |
|
8 |
+ description <<-MD |
|
9 |
+ This Agent allows you to write code in JavaScript that can create and receive events. If other Agents aren't meeting your needs, try this one! |
|
10 |
+ |
|
11 |
+ At the moment, all code should be written in the `code` option. In the future, a full editor will be provided. |
|
12 |
+ |
|
13 |
+ You can implement `Agent.check` and `Agent.receive` as you see fit. The following methods will be available on Agent in the JavaScript environment: |
|
14 |
+ |
|
15 |
+ * `this.createEvent(payload)` |
|
16 |
+ * `this.incomingEvents()` |
|
17 |
+ * `this.memory()` |
|
18 |
+ * `this.memory(key)` |
|
19 |
+ * `this.memory(keyToSet, valueToSet)` |
|
20 |
+ * `this.options()` |
|
21 |
+ * `this.options(key)` |
|
22 |
+ * `this.log(message)` |
|
23 |
+ * `this.error(message)` |
|
24 |
+ |
|
25 |
+ MD |
|
26 |
+ |
|
27 |
+ def validate_options |
|
28 |
+ errors.add(:base, "The 'code' option is required") unless options['code'].present? |
|
29 |
+ end |
|
30 |
+ |
|
31 |
+ def working? |
|
32 |
+ return false if recent_error_logs? |
|
33 |
+ |
|
34 |
+ if options['expected_update_period_in_days'].present? |
|
35 |
+ return false unless event_created_within?(options['expected_update_period_in_days']) |
|
36 |
+ end |
|
37 |
+ |
|
38 |
+ if options['expected_receive_period_in_days'].present? |
|
39 |
+ return false unless last_receive_at && last_receive_at > options['expected_receive_period_in_days'].to_i.days.ago |
|
40 |
+ end |
|
41 |
+ |
|
42 |
+ true |
|
43 |
+ end |
|
44 |
+ |
|
45 |
+ def check |
|
46 |
+ log_errors do |
|
47 |
+ execute_js("check") |
|
48 |
+ end |
|
49 |
+ end |
|
50 |
+ |
|
51 |
+ def receive(incoming_events) |
|
52 |
+ log_errors do |
|
53 |
+ execute_js("receive", incoming_events) |
|
54 |
+ end |
|
55 |
+ end |
|
56 |
+ |
|
57 |
+ def default_options |
|
58 |
+ js_code = <<-JS |
|
59 |
+ Agent.check = function() { |
|
60 |
+ if (this.options('make_event')) { |
|
61 |
+ this.createEvent({ 'message': 'I made an event!' }); |
|
62 |
+ var callCount = this.memory('callCount') || 0; |
|
63 |
+ this.memory('callCount', callCount + 1); |
|
64 |
+ } |
|
65 |
+ }; |
|
66 |
+ |
|
67 |
+ Agent.receive = function() { |
|
68 |
+ var events = this.incomingEvents(); |
|
69 |
+ for(var i = 0; i < events.length; i++) { |
|
70 |
+ this.createEvent({ 'message': 'I got an event!', 'event_was': events[i].payload }); |
|
71 |
+ } |
|
72 |
+ } |
|
73 |
+ JS |
|
74 |
+ |
|
75 |
+ { |
|
76 |
+ "code" => js_code.gsub(/[\n\r\t]/, '').strip, |
|
77 |
+ 'expected_receive_period_in_days' => "2", |
|
78 |
+ 'expected_update_period_in_days' => "2" |
|
79 |
+ } |
|
80 |
+ end |
|
81 |
+ |
|
82 |
+ private |
|
83 |
+ |
|
84 |
+ def execute_js(js_function, incoming_events = []) |
|
85 |
+ js_function = js_function == "check" ? "check" : "receive" |
|
86 |
+ context = V8::Context.new |
|
87 |
+ context.eval(setup_javascript) |
|
88 |
+ |
|
89 |
+ context["doCreateEvent"] = lambda { |a, y| create_event(payload: clean_nans(JSON.parse(y))).payload.to_json } |
|
90 |
+ context["getIncomingEvents"] = lambda { |a| incoming_events.to_json } |
|
91 |
+ context["getOptions"] = lambda { |a, x| options.to_json } |
|
92 |
+ context["doLog"] = lambda { |a, x| log x } |
|
93 |
+ context["doError"] = lambda { |a, x| error x } |
|
94 |
+ context["getMemory"] = lambda do |a, x, y| |
|
95 |
+ if x && y |
|
96 |
+ memory[x] = clean_nans(y) |
|
97 |
+ else |
|
98 |
+ memory.to_json |
|
99 |
+ end |
|
100 |
+ end |
|
101 |
+ |
|
102 |
+ context.eval(options['code']) |
|
103 |
+ context.eval("Agent.#{js_function}();") |
|
104 |
+ end |
|
105 |
+ |
|
106 |
+ def setup_javascript |
|
107 |
+ <<-JS |
|
108 |
+ function Agent() {}; |
|
109 |
+ |
|
110 |
+ Agent.createEvent = function(opts) { |
|
111 |
+ return JSON.parse(doCreateEvent(JSON.stringify(opts))); |
|
112 |
+ } |
|
113 |
+ |
|
114 |
+ Agent.incomingEvents = function() { |
|
115 |
+ return JSON.parse(getIncomingEvents()); |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ Agent.memory = function(key, value) { |
|
119 |
+ if (typeof(key) !== "undefined" && typeof(value) !== "undefined") { |
|
120 |
+ getMemory(key, value); |
|
121 |
+ } else if (typeof(key) !== "undefined") { |
|
122 |
+ return JSON.parse(getMemory())[key]; |
|
123 |
+ } else { |
|
124 |
+ return JSON.parse(getMemory()); |
|
125 |
+ } |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ Agent.options = function(key) { |
|
129 |
+ if (typeof(key) !== "undefined") { |
|
130 |
+ return JSON.parse(getOptions())[key]; |
|
131 |
+ } else { |
|
132 |
+ return JSON.parse(getOptions()); |
|
133 |
+ } |
|
134 |
+ } |
|
135 |
+ |
|
136 |
+ Agent.log = function(message) { |
|
137 |
+ doLog(message); |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ Agent.error = function(message) { |
|
141 |
+ doError(message); |
|
142 |
+ } |
|
143 |
+ |
|
144 |
+ Agent.check = function(){}; |
|
145 |
+ Agent.receive = function(){}; |
|
146 |
+ JS |
|
147 |
+ end |
|
148 |
+ |
|
149 |
+ def log_errors |
|
150 |
+ begin |
|
151 |
+ yield |
|
152 |
+ rescue V8::Error => e |
|
153 |
+ error "JavaScript error: #{e.message}" |
|
154 |
+ end |
|
155 |
+ end |
|
156 |
+ |
|
157 |
+ def clean_nans(input) |
|
158 |
+ if input.is_a?(Array) |
|
159 |
+ input.map {|v| clean_nans(v) } |
|
160 |
+ elsif input.is_a?(Hash) |
|
161 |
+ input.inject({}) { |m, (k, v)| m[k] = clean_nans(v); m } |
|
162 |
+ elsif input.is_a?(Float) && input.nan? |
|
163 |
+ 'NaN' |
|
164 |
+ else |
|
165 |
+ input |
|
166 |
+ end |
|
167 |
+ end |
|
168 |
+ end |
|
169 |
+end |
@@ -1,9 +1,9 @@ |
||
1 | 1 |
bob_website_agent_event: |
2 | 2 |
user: bob |
3 | 3 |
agent: bob_website_agent |
4 |
- payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_json.inspect %> |
|
4 |
+ payload: <%= { :title => "foo", :url => "http://foo.com" }.to_json.inspect %> |
|
5 | 5 |
|
6 | 6 |
jane_website_agent_event: |
7 | 7 |
user: jane |
8 | 8 |
agent: jane_website_agent |
9 |
- payload: <%= [{ :title => "foo", :url => "http://foo.com" }].to_json.inspect %> |
|
9 |
+ payload: <%= { :title => "foo", :url => "http://foo.com" }.to_json.inspect %> |
@@ -0,0 +1,200 @@ |
||
1 |
+require 'spec_helper' |
|
2 |
+ |
|
3 |
+describe Agents::JavaScriptAgent do |
|
4 |
+ before do |
|
5 |
+ @valid_params = { |
|
6 |
+ :name => "somename", |
|
7 |
+ :options => { |
|
8 |
+ :code => "Agent.check = function() { this.createEvent({ 'message': 'hi' }); };", |
|
9 |
+ } |
|
10 |
+ } |
|
11 |
+ |
|
12 |
+ @agent = Agents::JavaScriptAgent.new(@valid_params) |
|
13 |
+ @agent.user = users(:jane) |
|
14 |
+ @agent.save! |
|
15 |
+ end |
|
16 |
+ |
|
17 |
+ describe "validations" do |
|
18 |
+ it "requires 'code'" do |
|
19 |
+ @agent.should be_valid |
|
20 |
+ @agent.options['code'] = '' |
|
21 |
+ @agent.should_not be_valid |
|
22 |
+ @agent.options.delete('code') |
|
23 |
+ @agent.should_not be_valid |
|
24 |
+ end |
|
25 |
+ end |
|
26 |
+ |
|
27 |
+ describe "#working?" do |
|
28 |
+ describe "when expected_update_period_in_days is set" do |
|
29 |
+ it "returns false when more than expected_update_period_in_days have passed since the last event creation" do |
|
30 |
+ @agent.options['expected_update_period_in_days'] = 1 |
|
31 |
+ @agent.save! |
|
32 |
+ @agent.should_not be_working |
|
33 |
+ @agent.check |
|
34 |
+ @agent.reload.should be_working |
|
35 |
+ three_days_from_now = 3.days.from_now |
|
36 |
+ stub(Time).now { three_days_from_now } |
|
37 |
+ @agent.should_not be_working |
|
38 |
+ end |
|
39 |
+ end |
|
40 |
+ |
|
41 |
+ describe "when expected_receive_period_in_days is set" do |
|
42 |
+ it "returns false when more than expected_receive_period_in_days have passed since the last event was received" do |
|
43 |
+ @agent.options['expected_receive_period_in_days'] = 1 |
|
44 |
+ @agent.save! |
|
45 |
+ @agent.should_not be_working |
|
46 |
+ Agents::JavaScriptAgent.async_receive @agent.id, [events(:bob_website_agent_event).id] |
|
47 |
+ @agent.reload.should be_working |
|
48 |
+ two_days_from_now = 2.days.from_now |
|
49 |
+ stub(Time).now { two_days_from_now } |
|
50 |
+ @agent.reload.should_not be_working |
|
51 |
+ end |
|
52 |
+ end |
|
53 |
+ end |
|
54 |
+ |
|
55 |
+ describe "executing code" do |
|
56 |
+ it "works by default" do |
|
57 |
+ @agent.options = @agent.default_options |
|
58 |
+ @agent.options['make_event'] = true; |
|
59 |
+ @agent.save! |
|
60 |
+ |
|
61 |
+ lambda { |
|
62 |
+ lambda { |
|
63 |
+ @agent.receive([events(:bob_website_agent_event)]) |
|
64 |
+ @agent.check |
|
65 |
+ }.should_not change { AgentLog.count } |
|
66 |
+ }.should change { Event.count }.by(2) |
|
67 |
+ end |
|
68 |
+ |
|
69 |
+ describe "error handling" do |
|
70 |
+ it "should log an error when V8 has issues" do |
|
71 |
+ @agent.options['code'] = 'syntax error!' |
|
72 |
+ @agent.save! |
|
73 |
+ lambda { |
|
74 |
+ lambda { |
|
75 |
+ @agent.check |
|
76 |
+ }.should_not raise_error |
|
77 |
+ }.should change { AgentLog.count }.by(1) |
|
78 |
+ AgentLog.last.message.should =~ /Unexpected identifier/ |
|
79 |
+ AgentLog.last.level.should == 4 |
|
80 |
+ end |
|
81 |
+ |
|
82 |
+ it "should log an error when JavaScript throws" do |
|
83 |
+ @agent.options['code'] = 'Agent.check = function() { throw "oh no"; };' |
|
84 |
+ @agent.save! |
|
85 |
+ lambda { |
|
86 |
+ lambda { |
|
87 |
+ @agent.check |
|
88 |
+ }.should_not raise_error |
|
89 |
+ }.should change { AgentLog.count }.by(1) |
|
90 |
+ AgentLog.last.message.should =~ /oh no/ |
|
91 |
+ AgentLog.last.level.should == 4 |
|
92 |
+ end |
|
93 |
+ |
|
94 |
+ it "won't store NaNs" do |
|
95 |
+ @agent.options['code'] = 'Agent.check = function() { this.memory("foo", NaN); };' |
|
96 |
+ @agent.save! |
|
97 |
+ @agent.check |
|
98 |
+ @agent.memory['foo'].should == 'NaN' # string |
|
99 |
+ @agent.save! |
|
100 |
+ lambda { @agent.reload.memory }.should_not raise_error |
|
101 |
+ end |
|
102 |
+ end |
|
103 |
+ |
|
104 |
+ describe "creating events" do |
|
105 |
+ it "creates events with this.createEvent in the JavaScript environment" do |
|
106 |
+ @agent.options['code'] = 'Agent.check = function() { this.createEvent({ message: "This is an event!", stuff: { foo: 5 } }); };' |
|
107 |
+ @agent.save! |
|
108 |
+ lambda { |
|
109 |
+ lambda { |
|
110 |
+ @agent.check |
|
111 |
+ }.should_not change { AgentLog.count } |
|
112 |
+ }.should change { Event.count }.by(1) |
|
113 |
+ created_event = @agent.events.last |
|
114 |
+ created_event.payload.should == { 'message' => "This is an event!", 'stuff' => { 'foo' => 5 } } |
|
115 |
+ end |
|
116 |
+ end |
|
117 |
+ |
|
118 |
+ describe "logging" do |
|
119 |
+ it "can output AgentLogs with this.log and this.error in the JavaScript environment" do |
|
120 |
+ @agent.options['code'] = 'Agent.check = function() { this.log("woah"); this.error("WOAH!"); };' |
|
121 |
+ @agent.save! |
|
122 |
+ lambda { |
|
123 |
+ lambda { |
|
124 |
+ @agent.check |
|
125 |
+ }.should_not raise_error |
|
126 |
+ }.should change { AgentLog.count }.by(2) |
|
127 |
+ |
|
128 |
+ log1, log2 = AgentLog.last(2) |
|
129 |
+ |
|
130 |
+ log1.message.should == "woah" |
|
131 |
+ log1.level.should == 3 |
|
132 |
+ log2.message.should == "WOAH!" |
|
133 |
+ log2.level.should == 4 |
|
134 |
+ end |
|
135 |
+ end |
|
136 |
+ |
|
137 |
+ describe "getting incoming events" do |
|
138 |
+ it "can access incoming events in the JavaScript enviroment via this.incomingEvents" do |
|
139 |
+ event = Event.new |
|
140 |
+ event.agent = agents(:bob_rain_notifier_agent) |
|
141 |
+ event.payload = { :data => "Something you should know about" } |
|
142 |
+ event.save! |
|
143 |
+ event.reload |
|
144 |
+ |
|
145 |
+ @agent.options['code'] = <<-JS |
|
146 |
+ Agent.receive = function() { |
|
147 |
+ var events = this.incomingEvents(); |
|
148 |
+ for(var i = 0; i < events.length; i++) { |
|
149 |
+ this.createEvent({ 'message': 'I got an event!', 'event_was': events[i].payload }); |
|
150 |
+ } |
|
151 |
+ } |
|
152 |
+ JS |
|
153 |
+ |
|
154 |
+ @agent.save! |
|
155 |
+ lambda { |
|
156 |
+ lambda { |
|
157 |
+ @agent.receive([events(:bob_website_agent_event), event]) |
|
158 |
+ }.should_not change { AgentLog.count } |
|
159 |
+ }.should change { Event.count }.by(2) |
|
160 |
+ created_event = @agent.events.first |
|
161 |
+ created_event.payload.should == { 'message' => "I got an event!", 'event_was' => { 'data' => "Something you should know about" } } |
|
162 |
+ end |
|
163 |
+ end |
|
164 |
+ |
|
165 |
+ describe "getting and setting memory, getting options" do |
|
166 |
+ it "can access options via this.options and work with memory via this.memory" do |
|
167 |
+ @agent.options['code'] = <<-JS |
|
168 |
+ Agent.check = function() { |
|
169 |
+ if (this.options('make_event')) { |
|
170 |
+ var callCount = this.memory('callCount') || 0; |
|
171 |
+ this.memory('callCount', callCount + 1); |
|
172 |
+ } |
|
173 |
+ }; |
|
174 |
+ JS |
|
175 |
+ |
|
176 |
+ @agent.save! |
|
177 |
+ |
|
178 |
+ lambda { |
|
179 |
+ lambda { |
|
180 |
+ |
|
181 |
+ @agent.check |
|
182 |
+ @agent.memory['callCount'].should_not be_present |
|
183 |
+ |
|
184 |
+ @agent.options['make_event'] = true |
|
185 |
+ @agent.check |
|
186 |
+ @agent.memory['callCount'].should == 1 |
|
187 |
+ |
|
188 |
+ @agent.check |
|
189 |
+ @agent.memory['callCount'].should == 2 |
|
190 |
+ |
|
191 |
+ @agent.memory['callCount'] = 20 |
|
192 |
+ @agent.check |
|
193 |
+ @agent.memory['callCount'].should == 21 |
|
194 |
+ |
|
195 |
+ }.should_not change { AgentLog.count } |
|
196 |
+ }.should_not change { Event.count } |
|
197 |
+ end |
|
198 |
+ end |
|
199 |
+ end |
|
200 |
+end |