evegem 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +14 -0
- data/Gemfile +5 -0
- data/Rakefile +5 -0
- data/autotest/discover.rb +2 -0
- data/bin/eve +18 -0
- data/config.ru +2 -0
- data/config/database.yml.example +16 -0
- data/config/reset_db.rb +10 -0
- data/eve.gemspec +39 -0
- data/lib/eve/application.rb +465 -0
- data/lib/eve/ci.rake +68 -0
- data/lib/eve/event_server.rb +67 -0
- data/lib/eve/file_notifier_server.rb +77 -0
- data/lib/eve/io.rb +25 -0
- data/lib/eve/layout.rb +22 -0
- data/lib/eve/message.rb +181 -0
- data/lib/eve/messenger.rb +138 -0
- data/lib/eve/registry.rb +35 -0
- data/lib/eve/version.rb +3 -0
- data/lib/eve/web_server.rb +22 -0
- data/lib/evegem.rb +23 -0
- data/lib/registry/base_registry.rb +60 -0
- data/lib/registry/charlie_test.rb +18 -0
- data/lib/registry/echo_test.rb +22 -0
- data/lib/registry/empty_registry.rb +11 -0
- data/spec/application_spec.rb +738 -0
- data/spec/base_registry_spec.rb +134 -0
- data/spec/event_server_spec.rb +73 -0
- data/spec/file_notifier_server_spec.rb +89 -0
- data/spec/files/niner_registry.rb +23 -0
- data/spec/layout_spec.rb +28 -0
- data/spec/message_spec.rb +246 -0
- data/spec/messenger_spec.rb +399 -0
- data/spec/spec_helper.rb +35 -0
- metadata +276 -0
@@ -0,0 +1,138 @@
|
|
1
|
+
module Eve
|
2
|
+
|
3
|
+
class Messenger
|
4
|
+
|
5
|
+
attr_accessor :display, :history, :piggy_backs, :ok_filters, :nok_filters
|
6
|
+
|
7
|
+
def initialize(data = {})
|
8
|
+
@display = data[:display] || :stdio
|
9
|
+
@piggy_backs = []
|
10
|
+
@ok_filters = []
|
11
|
+
@nok_filters = []
|
12
|
+
reset
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_filter(raw_input)
|
16
|
+
raw_input = "#{raw_input}"
|
17
|
+
if raw_input.start_with?("!")
|
18
|
+
@nok_filters << raw_input[1..-1]
|
19
|
+
else
|
20
|
+
@ok_filters << raw_input
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def display=(val)
|
25
|
+
@display = val || :stdio
|
26
|
+
end
|
27
|
+
|
28
|
+
def event_machine?
|
29
|
+
@display.kind_of?(Hash) && !@display[:event_machine].nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def event_machine
|
33
|
+
@display[:event_machine]
|
34
|
+
end
|
35
|
+
|
36
|
+
def file?
|
37
|
+
@display.kind_of?(Hash) && !@display[:filename].nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def overwrite_file?
|
41
|
+
file? && @display[:mode] == :overwrite
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_data_only?
|
45
|
+
@display.kind_of?(Hash) && @display[:mode] == "data_only"
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset
|
49
|
+
@flagged_history = {}
|
50
|
+
@history = []
|
51
|
+
@piggy_backs.each { |m| m.reset }
|
52
|
+
end
|
53
|
+
|
54
|
+
def history(flag = nil)
|
55
|
+
return @history if flag.nil?
|
56
|
+
@flagged_history[flag] || []
|
57
|
+
end
|
58
|
+
|
59
|
+
def has_flag?(flag)
|
60
|
+
return !@flagged_history[flag].nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def was_printed?(msg)
|
64
|
+
@history.include?(msg)
|
65
|
+
end
|
66
|
+
|
67
|
+
[:info, :debug, :error].each do |name|
|
68
|
+
plural_name = "#{name}s".to_sym
|
69
|
+
has_message_name = "#{name}s?"
|
70
|
+
has_specific_message_name = "#{name}?"
|
71
|
+
|
72
|
+
define_method name do |msg|
|
73
|
+
self.print(msg,{ :flag => name })
|
74
|
+
end
|
75
|
+
|
76
|
+
define_method plural_name do
|
77
|
+
self.history(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
define_method has_message_name do
|
81
|
+
self.has_flag?(name)
|
82
|
+
end
|
83
|
+
|
84
|
+
define_method has_specific_message_name do |msg|
|
85
|
+
return false unless self.has_flag?(name)
|
86
|
+
@flagged_history[name].include?(msg)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def print(output, options = {})
|
91
|
+
@piggy_backs.each { |m| m.print(output,options.clone) }
|
92
|
+
return unless should_print?(options)
|
93
|
+
add_history(output,options.delete(:flag))
|
94
|
+
if @display == :stdio && options.empty?
|
95
|
+
STDOUT.print output
|
96
|
+
elsif @display == :stdio
|
97
|
+
Kernel.ap output, options
|
98
|
+
elsif event_machine?
|
99
|
+
event_machine.send_data(output)
|
100
|
+
elsif file?
|
101
|
+
system("mkdir -p #{Pathname.new(@display[:filename]).parent}")
|
102
|
+
open(@display[:filename], overwrite_file? ? "w" : "a+") { |f| f.puts(output) }
|
103
|
+
else
|
104
|
+
output
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def should_print?(options)
|
111
|
+
return true if @ok_filters.empty? && @nok_filters.empty?
|
112
|
+
all_flags = options[:flag].kind_of?(Array) ? options[:flag] : [ options[:flag] ]
|
113
|
+
all_flags.each do |f|
|
114
|
+
return true if should_print_flag?(f)
|
115
|
+
end
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
119
|
+
def should_print_flag?(input)
|
120
|
+
flag = "#{input}"
|
121
|
+
should_add = @ok_filters.include?(flag)
|
122
|
+
should_not_add = @nok_filters.include?(flag) || @nok_filters.empty?
|
123
|
+
should_add || !should_not_add
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def add_history(output,flag)
|
128
|
+
unless flag.nil?
|
129
|
+
(flag.kind_of?(Array) ? flag : [flag]).each do |f|
|
130
|
+
@flagged_history[f] ||= []
|
131
|
+
@flagged_history[f] << output
|
132
|
+
end
|
133
|
+
end
|
134
|
+
@history << output
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/lib/eve/registry.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Eve
|
2
|
+
|
3
|
+
class Registry
|
4
|
+
|
5
|
+
def self.handle?(cmd)
|
6
|
+
action, data = action_and_input(cmd)
|
7
|
+
available.include?(action)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.handle(app,cmd,display_messages)
|
11
|
+
result = app.default_result
|
12
|
+
action, data = action_and_input(cmd)
|
13
|
+
inner_action, inner_data = action_and_input(data)
|
14
|
+
if available[action].include?(inner_action)
|
15
|
+
result = send(Application.methodize("call_#{action}_#{inner_action}"), app, result, inner_data, display_messages)
|
16
|
+
else
|
17
|
+
result = send(Application.methodize("call_#{action}"), app, result, data, display_messages)
|
18
|
+
end
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.action_and_input(raw)
|
25
|
+
return [ "", nil ] if raw.nil?
|
26
|
+
action = raw.split.shift
|
27
|
+
return [ "", nil ] if (action.nil? || action.starts_with?("#"))
|
28
|
+
data = raw[(action.size)..-1].strip
|
29
|
+
[ action, data ]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/eve/version.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Eve
|
2
|
+
|
3
|
+
class WebServer
|
4
|
+
|
5
|
+
def call(env)
|
6
|
+
|
7
|
+
response = ""
|
8
|
+
Application.ids.each do |id|
|
9
|
+
app = Application.new(:id => id)
|
10
|
+
response += "<div>ID: #{app.id} (#{app.alive?})</div>"
|
11
|
+
end
|
12
|
+
|
13
|
+
[
|
14
|
+
200,
|
15
|
+
{"Content-Type" => "text/html"},
|
16
|
+
[response]
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/evegem.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'awesome_print'
|
2
|
+
require 'pathname'
|
3
|
+
require 'net/ftp'
|
4
|
+
require 'net/ssh'
|
5
|
+
require 'net/telnet'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'eventmachine'
|
8
|
+
require 'utest'
|
9
|
+
require 'watchme'
|
10
|
+
require 'csv'
|
11
|
+
require "redis"
|
12
|
+
|
13
|
+
dir = File.dirname(__FILE__)
|
14
|
+
require "#{dir}/eve/io"
|
15
|
+
require "#{dir}/eve/registry"
|
16
|
+
require "#{dir}/eve/web_server"
|
17
|
+
require "#{dir}/eve/application"
|
18
|
+
require "#{dir}/eve/version"
|
19
|
+
require "#{dir}/eve/messenger"
|
20
|
+
require "#{dir}/eve/message"
|
21
|
+
require "#{dir}/eve/layout"
|
22
|
+
require "#{dir}/eve/file_notifier_server"
|
23
|
+
require "#{dir}/eve/event_server"
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Eve
|
2
|
+
|
3
|
+
class BaseRegistry < Registry
|
4
|
+
|
5
|
+
@@cmd_data = {
|
6
|
+
"export" => [],
|
7
|
+
"import" => [],
|
8
|
+
"sleep" => [],
|
9
|
+
"ruby" => [],
|
10
|
+
}
|
11
|
+
|
12
|
+
def self.available
|
13
|
+
@@cmd_data
|
14
|
+
end
|
15
|
+
|
16
|
+
#------------
|
17
|
+
# CALLER METHODS
|
18
|
+
#------------
|
19
|
+
|
20
|
+
def self.call_export(app,result,filename,display_messages)
|
21
|
+
filename = "./eve.cmd" if filename == "" || filename.nil?
|
22
|
+
result[:data] = filename
|
23
|
+
IO.write(filename,app.cmds.join("\n"))
|
24
|
+
app.message.print_exported_commands(filename) if display_messages
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.call_import(app,result,filename,display_messages)
|
29
|
+
filename = "./eve.cmd" if filename == "" || filename.nil?
|
30
|
+
result[:data] = filename
|
31
|
+
result[:track_cmd] = false
|
32
|
+
app.message.print_importing_commands(filename) if display_messages
|
33
|
+
count = 0
|
34
|
+
IO.readlines(filename).each do |raw|
|
35
|
+
script = raw.strip
|
36
|
+
next if script == "" || script[0] == "#"
|
37
|
+
count += 1
|
38
|
+
app.cmd(script,display_messages,true)
|
39
|
+
end
|
40
|
+
app.message.print_importing_complete(filename,count) if display_messages
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.call_sleep(app,result,duration,display_messages)
|
45
|
+
in_secs = WatchMe::Timer.to_seconds(duration)
|
46
|
+
result[:data] = in_secs
|
47
|
+
app.message.print_sleep(in_secs) if display_messages
|
48
|
+
Kernel.sleep(in_secs)
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.call_ruby(app,result,call,display_messages)
|
53
|
+
result[:data] = eval(call)
|
54
|
+
app.message.print_ruby_call(call,result[:data]) if display_messages
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CharlieTest
|
2
|
+
|
3
|
+
def self.handle?(cmd)
|
4
|
+
cmd.start_with?("charlie-test")
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.available
|
8
|
+
{ "charlie-test" => [] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.handle(app,cmd,display_messages)
|
12
|
+
result = app.default_result
|
13
|
+
result[:data] = cmd["charlie-test".size..-1].strip
|
14
|
+
app.console.print("CHARLIE: #{result[:data]}\n") if display_messages
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sample
|
2
|
+
|
3
|
+
class EchoTest
|
4
|
+
|
5
|
+
def self.handle?(cmd)
|
6
|
+
cmd.start_with?("echo-test")
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.available
|
10
|
+
{ "echo-test" => [] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.handle(app,cmd,display_messages)
|
14
|
+
result = app.default_result
|
15
|
+
result[:data] = cmd["echo-test".size..-1].strip
|
16
|
+
app.console.print("ECHO: #{result[:data]}") if display_messages
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,738 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Eve
|
4
|
+
|
5
|
+
describe Application do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@now = Time.parse('2010-09-21 23:15:20')
|
9
|
+
@now_plus_four = Time.parse('2010-09-21 23:19:20')
|
10
|
+
@now_plus_six = Time.parse('2010-09-21 23:21:20')
|
11
|
+
Time.stub!(:now).and_return(@now)
|
12
|
+
|
13
|
+
`mkdir -p ./application_test`
|
14
|
+
`mkdir -p ./application_test2`
|
15
|
+
@redis = Utest::InmemoryRedis.new
|
16
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
17
|
+
end
|
18
|
+
|
19
|
+
after(:each) do
|
20
|
+
`rm -rf ./application_test`
|
21
|
+
`rm -rf ./application_test2`
|
22
|
+
`rm -f deleteme.txt deleteme2.txt`
|
23
|
+
`rm -rf ./eve.cmd`
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "initialize" do
|
27
|
+
|
28
|
+
it "should initalize things" do
|
29
|
+
@app.console.should_not == nil
|
30
|
+
@app.message.should_not == nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should pass display to console" do
|
34
|
+
@app.console.display.should == :string
|
35
|
+
|
36
|
+
app = Application.new(:display => :stdio, :redis => @redis)
|
37
|
+
app.console.display.should == :stdio
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should map directly to messenger history" do
|
41
|
+
@app.history.should == @app.console.history
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should default mode to queue" do
|
45
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
46
|
+
@redis.set("Eve.#{@app.id}.mode",nil)
|
47
|
+
@app.cmd("appid")
|
48
|
+
@app.mode.should == :queue
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should raise an error if id not set" do
|
52
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
53
|
+
lambda { @app.lookup_id("blah") }.should raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "mode" do
|
57
|
+
|
58
|
+
it "should default to fixed" do
|
59
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
60
|
+
@app.mode.should == :queue
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should set mode locally" do
|
66
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
67
|
+
@app.mode.should == :queue
|
68
|
+
@app.mode = :poll
|
69
|
+
@app.mode.should == :poll
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#handle_args" do
|
75
|
+
|
76
|
+
it "should accept an id" do
|
77
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
78
|
+
@app.handle_args([ "--id", "123" ]).should == [ "appid 123" ]
|
79
|
+
@app.cmd("appid 123")
|
80
|
+
@app.id.should == "123"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should set the id if not provided" do
|
84
|
+
redis = Utest::InmemoryRedis.new
|
85
|
+
@app = Application.new(:display => :string, :redis => redis)
|
86
|
+
@app.handle_args([]).should == [ "appid" ]
|
87
|
+
@app.cmd("appid")
|
88
|
+
@app.id.should == $$.to_s
|
89
|
+
Application.ids(redis).should == [ $$.to_s ]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should default to check every 5 minutes (5*60 seconds)" do
|
93
|
+
@app.poll.should == 300
|
94
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
95
|
+
@app.handle_args([ "--poll", "10minutes"]).should == [ "appid", "poll 10minutes" ]
|
96
|
+
@app.cmd("appid")
|
97
|
+
@app.cmd("poll set 10minutes")
|
98
|
+
@app.poll.should == 600
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should default to fixed" do
|
102
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
103
|
+
@app.cmd("appid")
|
104
|
+
@app.mode.should == :queue
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "register" do
|
108
|
+
|
109
|
+
it "should understand default" do
|
110
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
111
|
+
@app.handle_args(["--register","Eve::BaseRegister","--shell"]).should == ["appid","register add Eve::BaseRegister","shell"]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should understand both the name and " do
|
115
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
116
|
+
@app.handle_args(["--register","AnotherRegister","/path/to/another_register.rb","--shell"]).should == ["appid","register add AnotherRegister /path/to/another_register.rb","shell"]
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should understand multiple" do
|
120
|
+
@app = Application.new(:display => :string, :redis => @redis)
|
121
|
+
@app.handle_args(["--register","Eve::BaseRegister","--register","AnotherRegister","/path/to/another_register.rb","--shell"]).should == ["appid","register add Eve::BaseRegister","register add AnotherRegister /path/to/another_register.rb","shell"]
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should understand --shell" do
|
127
|
+
@app.handle_args(["--shell"]).should == ["appid","shell"]
|
128
|
+
@app.cmd("appid")
|
129
|
+
@app.cmd("shell")
|
130
|
+
@app.mode.should == :shell
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should understand --poll" do
|
134
|
+
@app.handle_args(["--poll","123"]).should == ["appid", "poll 123"]
|
135
|
+
@app.cmd("appid")
|
136
|
+
@app.cmd("poll set 123")
|
137
|
+
@app.mode.should == :poll
|
138
|
+
@app.poll.should == 123
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "event" do
|
142
|
+
|
143
|
+
it "should understand --event" do
|
144
|
+
@app.handle_args(["--event", "1.1.1.1:4848"]).should == ["event 1.1.1.1:4848"]
|
145
|
+
@app.cmd("event")
|
146
|
+
@app.mode.should == :event
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "run" do
|
152
|
+
|
153
|
+
it "should understand --run" do
|
154
|
+
@app.handle_args(["--run","source", "add", "/tmp/source", "--run", "target", "add", "/tmp/target"]).should == ["appid","source add /tmp/source","target add /tmp/target"]
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "#lookup_id" do
|
162
|
+
|
163
|
+
it "should be based on the app id" do
|
164
|
+
@app.id = 123
|
165
|
+
@app.lookup_id("Blah").should == "Eve.123.Blah"
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
# describe "#run" do
|
171
|
+
#
|
172
|
+
# it "should print the version" do
|
173
|
+
# @app.run
|
174
|
+
# @app.history.should == ["eve, version 0.1.2\n", "Appid: #{$$}\n", "bye\n"]
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# it "should run the input commands" do
|
178
|
+
# @app.stub!(:user_input).and_return("version","exit")
|
179
|
+
# @app.run(["--shell"])
|
180
|
+
# @app.history.should == ["eve, version 0.1.2\n", "Appid: #{$$}\n", "Entering shell mode, to exit this mode, type 'poll'\n", "eve #{$$}, version 0.1.2\n", "bye\n"]
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# it "should set the id if provided" do
|
184
|
+
# app = Application.new(:display => :string, :redis => @redis)
|
185
|
+
# app.stub!(:user_input).and_return("exit")
|
186
|
+
# app.run(["--id","abc123", "--shell"])
|
187
|
+
# app.history.should == ["eve, version 0.1.2\n", "Appid: abc123\n", "Entering shell mode, to exit this mode, type 'poll'\n", "bye\n"]
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# it "should exit if --interrupt" do
|
191
|
+
# @app.mode = :poll
|
192
|
+
# @app.run(["--interrupt", "acb123"])
|
193
|
+
# @app.history.should == ["eve, version 0.1.2\n", "Interrupted eve acb123, should now be in shell mode\n", "bye\n"]
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# it "should pop things off the queue" do
|
197
|
+
# @app.cmd("appid")
|
198
|
+
# @app.enqueue_cmd("version")
|
199
|
+
# @app.enqueue_cmd("exit")
|
200
|
+
# @app.run
|
201
|
+
# @app.history.should == ["Appid: #{$$}\n", "eve #{$$}, version 0.1.2\n", "eve #{$$}, version 0.1.2\n", "bye\n"]
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# end
|
205
|
+
|
206
|
+
describe "#cmd" do
|
207
|
+
|
208
|
+
before(:each) do
|
209
|
+
@app.cmd("appid")
|
210
|
+
@app.reset
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "bam" do
|
214
|
+
|
215
|
+
it "should report exceptions" do
|
216
|
+
@app.should_receive(:call_version).and_raise("bam!")
|
217
|
+
@app.cmd("version 1 2 3")
|
218
|
+
@app.history[0].should == "An error occurred for 'version 1 2 3'\n"
|
219
|
+
@app.history.size.should == 3
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "appid" do
|
225
|
+
|
226
|
+
it "should not call reload if no id provided" do
|
227
|
+
@app.should_not_receive(:call_register_reload)
|
228
|
+
@app.cmd("appid")
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should not call reload if new id" do
|
232
|
+
@app.should_not_receive(:call_register_reload)
|
233
|
+
@app.cmd("appid 1234")
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should call if it already exists" do
|
237
|
+
@redis.sadd("Eve.ApplicationIds","youreve")
|
238
|
+
@app.should_receive(:call_register_reload)
|
239
|
+
@app.cmd("appid youreve")
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "version" do
|
246
|
+
|
247
|
+
it "should display the version" do
|
248
|
+
@app.cmd("version").should == { :data => "0.1.2", :status => :continue, :track_cmd => true }
|
249
|
+
@app.history.should == [ "eve #{$$}, version 0.1.2\n" ]
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should handle remote events via telnet" do
|
253
|
+
@app.cmd("event 0.0.0.0:1234")
|
254
|
+
telnet = mock(Net::Telnet)
|
255
|
+
Net::Telnet.should_receive(:new).with("Host" => "0.0.0.0", "Port" => "1234", "Timeout" => 10, "Telnetmode" => false).and_return(telnet)
|
256
|
+
telnet.should_receive(:cmd).with("version")
|
257
|
+
@app.cmd("version")
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
describe "help" do
|
263
|
+
|
264
|
+
it "should diplay all help" do
|
265
|
+
|
266
|
+
@app.cmd("help")[:data].should == Application.cmd_data
|
267
|
+
|
268
|
+
expected = "Available commands are:\n"
|
269
|
+
expected += " version\n"
|
270
|
+
expected += " help\n"
|
271
|
+
expected += " appid\n"
|
272
|
+
expected += " shell\n"
|
273
|
+
expected += " poll [ set | add | rm ]\n"
|
274
|
+
expected += " event\n"
|
275
|
+
expected += " remote\n"
|
276
|
+
expected += " interrupt\n"
|
277
|
+
expected += " register [ add | rm | reload | add-path | rm-path | path ]\n"
|
278
|
+
expected += " print\n"
|
279
|
+
expected += " exit\n"
|
280
|
+
|
281
|
+
@app.history.should == [ expected ]
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should merge all" do
|
285
|
+
@app.cmd("register add CharlieTest #{File.dirname(__FILE__) + "/../lib/registry/charlie_test.rb"}")
|
286
|
+
@app.cmd("help")
|
287
|
+
|
288
|
+
expected = "Available commands are:\n"
|
289
|
+
expected += " version\n"
|
290
|
+
expected += " help\n"
|
291
|
+
expected += " appid\n"
|
292
|
+
expected += " shell\n"
|
293
|
+
expected += " poll [ set | add | rm ]\n"
|
294
|
+
expected += " event\n"
|
295
|
+
expected += " remote\n"
|
296
|
+
expected += " interrupt\n"
|
297
|
+
expected += " register [ add | rm | reload | add-path | rm-path | path ]\n"
|
298
|
+
expected += " print\n"
|
299
|
+
expected += " exit\n"
|
300
|
+
expected += " charlie-test\n"
|
301
|
+
@app.history.should == [ expected ]
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should allow filtering based on handler" do
|
305
|
+
@app.cmd("register add CharlieTest #{File.dirname(__FILE__) + "/../lib/registry/charlie_test.rb"}")
|
306
|
+
@app.cmd("help CharlieTest")[:data].should == { "charlie-test" => [] }
|
307
|
+
expected = "Available commands (CharlieTest) are:\n"
|
308
|
+
expected += " charlie-test\n"
|
309
|
+
@app.history.should == [ expected ]
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should not report unknown handlers" do
|
313
|
+
@app.cmd("help Blah")[:data].should == { }
|
314
|
+
expected = "Unknown handler Blah\n"
|
315
|
+
@app.history.should == [ expected ]
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "exit" do
|
321
|
+
|
322
|
+
it "should say bye" do
|
323
|
+
@app.cmd("exit").should == { :data => nil, :status => :exited, :track_cmd => true }
|
324
|
+
@app.history.should == [ "bye\n" ]
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
describe "shell" do
|
330
|
+
|
331
|
+
it "should update mode" do
|
332
|
+
@app.cmd("shell").should == { :data => :shell, :status => :continue, :track_cmd => true }
|
333
|
+
@app.mode.should == :shell
|
334
|
+
@app.history.should == [ "Entering shell mode, to exit this mode, type 'poll'\n" ]
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "poll" do
|
340
|
+
|
341
|
+
it "should say nothing to poll" do
|
342
|
+
@app.cmd("poll")
|
343
|
+
@app.history.should == [ "Poll will check every 5 minutes (300 seconds), but it has nothing to run.\n" ]
|
344
|
+
end
|
345
|
+
|
346
|
+
describe "add" do
|
347
|
+
|
348
|
+
it "should add the cmd" do
|
349
|
+
result = @app.cmd("poll add do_blah a b c")
|
350
|
+
@app.cmd("poll")[:data].should == [ "do_blah a b c" ]
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should allow mulitple" do
|
354
|
+
result = @app.cmd("poll add do_blah a b c")
|
355
|
+
result = @app.cmd("poll add do_blah a b c")
|
356
|
+
@app.cmd("poll")[:data].should == [ "do_blah a b c", "do_blah a b c" ]
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should add in order" do
|
360
|
+
result = @app.cmd("poll add do_blah 1")
|
361
|
+
result = @app.cmd("poll add do_blah 2")
|
362
|
+
@app.cmd("poll")[:data].should == [ "do_blah 1", "do_blah 2" ]
|
363
|
+
end
|
364
|
+
|
365
|
+
end
|
366
|
+
|
367
|
+
describe "rm" do
|
368
|
+
|
369
|
+
it "should rm the cmd at the particular index" do
|
370
|
+
result = @app.cmd("poll add do_blah 1")
|
371
|
+
result = @app.cmd("poll add do_blah 2")
|
372
|
+
result = @app.cmd("poll add do_blah 3")
|
373
|
+
@app.cmd("poll rm 2")
|
374
|
+
@app.cmd("poll rm 0")
|
375
|
+
@app.cmd("poll")[:data].should == [ "do_blah 2" ]
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should rm all instances of the cmd" do
|
379
|
+
result = @app.cmd("poll add do_blah a")
|
380
|
+
result = @app.cmd("poll add do_blah b")
|
381
|
+
result = @app.cmd("poll add do_blah a")
|
382
|
+
@app.cmd("poll rm do_blah a")
|
383
|
+
@app.cmd("poll")[:data].should == [ "do_blah b" ]
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should ignore unknown indexes" do
|
387
|
+
@app.cmd("poll rm 99")
|
388
|
+
@app.cmd("poll")[:data].should == [ ]
|
389
|
+
end
|
390
|
+
|
391
|
+
it "should allow mulitple" do
|
392
|
+
result = @app.cmd("poll add do_blah a b c")
|
393
|
+
result = @app.cmd("poll add do_blah a b c")
|
394
|
+
@app.cmd("poll")[:data].should == [ "do_blah a b c", "do_blah a b c" ]
|
395
|
+
end
|
396
|
+
|
397
|
+
it "should add in order" do
|
398
|
+
result = @app.cmd("poll add do_blah 1")
|
399
|
+
result = @app.cmd("poll add do_blah 2")
|
400
|
+
@app.cmd("poll")[:data].should == [ "do_blah 1", "do_blah 2" ]
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
describe "set" do
|
406
|
+
|
407
|
+
it "should update how often it polls for data" do
|
408
|
+
@app.cmd("poll set 10minutes").should == { :data => 600, :status => :continue, :track_cmd => true }
|
409
|
+
@app.history.should == ["Entering poll mode with checks every 10 minutes (600 seconds), to exit this mode, run 'eve --interrupt #{$$}' from another terminal session\n"]
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should update mode" do
|
413
|
+
@app.id = "abc456"
|
414
|
+
@app.cmd("poll set 10").should == { :data => 10, :status => :continue, :track_cmd => true }
|
415
|
+
@app.mode.should == :poll
|
416
|
+
@app.history.should == ["Entering poll mode with checks every 10 seconds, to exit this mode, run 'eve --interrupt abc456' from another terminal session\n"]
|
417
|
+
end
|
418
|
+
|
419
|
+
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
describe "event" do
|
425
|
+
|
426
|
+
it "should update mode" do
|
427
|
+
@app.cmd("event")
|
428
|
+
@app.mode.should == :event
|
429
|
+
@app.history.should == [ "Messages will be routed to 0.0.0.0:4848\n" ]
|
430
|
+
end
|
431
|
+
|
432
|
+
it "should default the server ip and port" do
|
433
|
+
@app.cmd("event")[:data].should == { :server => "0.0.0.0", :port => "4848" }
|
434
|
+
@app.server.should == "0.0.0.0"
|
435
|
+
@app.port.should == "4848"
|
436
|
+
end
|
437
|
+
|
438
|
+
it "should be overrideable" do
|
439
|
+
@app.cmd("event 1.1.1.1:2020")[:data].should == { :server => "1.1.1.1", :port => "2020" }
|
440
|
+
@app.server.should == "1.1.1.1"
|
441
|
+
@app.port.should == "2020"
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
describe "interrupt" do
|
447
|
+
|
448
|
+
it "should update mode" do
|
449
|
+
@redis.set("Eve.123.mode","poll")
|
450
|
+
@app.cmd("interrupt 123").should == { :data => nil, :status => :continue, :track_cmd => true }
|
451
|
+
@redis.get("Eve.123.mode").should == "shell"
|
452
|
+
end
|
453
|
+
|
454
|
+
end
|
455
|
+
|
456
|
+
describe "print" do
|
457
|
+
|
458
|
+
it "should echo to the 'console'" do
|
459
|
+
@app.cmd("print hello my friends\nHow are you\n")
|
460
|
+
@app.history.should == [ "hello my friends\nHow are you\n" ]
|
461
|
+
end
|
462
|
+
|
463
|
+
end
|
464
|
+
|
465
|
+
describe "register" do
|
466
|
+
|
467
|
+
it "should show nothing registered" do
|
468
|
+
result = @app.cmd("register")
|
469
|
+
result[:data].should == {}
|
470
|
+
@app.history.should == [ "Nothing registered.\n" ]
|
471
|
+
end
|
472
|
+
|
473
|
+
it "Should show the class name and the filename" do
|
474
|
+
@app.cmd("register add CharlieTest")
|
475
|
+
@app.cmd("register add Sample::EchoTest")
|
476
|
+
result = @app.cmd("register")
|
477
|
+
|
478
|
+
result[:data].should == { "CharlieTest" => [p("./lib/registry/charlie_test.rb")], "Sample::EchoTest" => [p("./lib/registry/echo_test.rb")] }
|
479
|
+
@app.history.should == [ "The following has been registered:\n - CharlieTest (#{p("./lib/registry/charlie_test.rb")})\n - Sample::EchoTest (#{p("./lib/registry/echo_test.rb")})\n" ]
|
480
|
+
end
|
481
|
+
|
482
|
+
describe "path" do
|
483
|
+
|
484
|
+
it "should show the default" do
|
485
|
+
@app.cmd("register path")
|
486
|
+
@app.history.should == [ "The following paths have been set:\n -- #{p("#{File.dirname(__FILE__)}/../lib/registry")}\n" ]
|
487
|
+
end
|
488
|
+
|
489
|
+
it "should also show any added paths" do
|
490
|
+
@app.cmd("register add-path ./application_test")
|
491
|
+
@app.reset
|
492
|
+
@app.cmd("register path")
|
493
|
+
@app.history.should == [ "The following paths have been set:\n -- #{p("#{File.dirname(__FILE__)}/../lib/registry")}\n -- #{p("./application_test")}\n" ]
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|
497
|
+
|
498
|
+
describe "rm-path" do
|
499
|
+
|
500
|
+
it "should ignore if not set" do
|
501
|
+
@app.cmd("register rm-path ./blah")[:data].should == 0
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should remove the path" do
|
505
|
+
@app.cmd("register add-path ./application_test")
|
506
|
+
@app.cmd("register add-path ./application_test2")
|
507
|
+
@app.reset
|
508
|
+
@app.cmd("register rm-path ./application_test")
|
509
|
+
@app.reset
|
510
|
+
@app.cmd("register path")
|
511
|
+
@app.history.should == [ "The following paths have been set:\n -- #{p("#{File.dirname(__FILE__)}/../lib/registry")}\n -- #{p("./application_test2")}\n" ]
|
512
|
+
end
|
513
|
+
|
514
|
+
end
|
515
|
+
|
516
|
+
describe "add-path" do
|
517
|
+
|
518
|
+
it "should validate path" do
|
519
|
+
result = @app.cmd("register add-path ./application_test")
|
520
|
+
result[:data].should == 1
|
521
|
+
|
522
|
+
result = @app.cmd("register add-path ./unknown_dir")
|
523
|
+
result[:data].should == false
|
524
|
+
end
|
525
|
+
|
526
|
+
it "should use path to load files" do
|
527
|
+
@app.cmd("register add-path #{File.dirname(__FILE__)}/files")
|
528
|
+
@app.cmd("register add Sample::NinerRegistry")
|
529
|
+
@app.cmd("register")
|
530
|
+
@app.history.should == [ "The following has been registered:\n - Sample::NinerRegistry (#{p("#{File.dirname(__FILE__)}/files/niner_registry.rb")})\n" ]
|
531
|
+
@app.reset
|
532
|
+
@app.cmd("niner-test blah")[:data].should == "blah"
|
533
|
+
@app.history.should == [ "NINER: blah\n"]
|
534
|
+
end
|
535
|
+
|
536
|
+
it "should allow for multiple handlers" do
|
537
|
+
@app.cmd("register add-path #{File.dirname(__FILE__)}/files")
|
538
|
+
@app.cmd("register add Sample::NinerRegistry")
|
539
|
+
@app.reset
|
540
|
+
result = @app.cmd("version")
|
541
|
+
result[:data][0][:data].should == "0.1.2"
|
542
|
+
result[:data][1][:data].should == "4848"
|
543
|
+
@app.history.should == [ "eve #{$$}, version 0.1.2\n", "version 4848\n" ]
|
544
|
+
end
|
545
|
+
|
546
|
+
|
547
|
+
end
|
548
|
+
|
549
|
+
describe "add" do
|
550
|
+
|
551
|
+
it "should return a result" do
|
552
|
+
result = @app.cmd("register add CharlieTest")
|
553
|
+
result[:data].should == true
|
554
|
+
|
555
|
+
result = @app.cmd("register add Blah")
|
556
|
+
result[:data].should == nil
|
557
|
+
end
|
558
|
+
|
559
|
+
it "should look in registry if filename not provided" do
|
560
|
+
@app.cmd("register add CharlieTest")
|
561
|
+
@app.cmd("register add Sample::EchoTest")
|
562
|
+
@app.cmd("echo-test blah blah blah")[:data].should == "blah blah blah"
|
563
|
+
@app.cmd("charlie-test ra ra ra")[:data].should == "ra ra ra"
|
564
|
+
end
|
565
|
+
|
566
|
+
it "should add extra calls" do
|
567
|
+
@app.cmd("register add CharlieTest #{File.dirname(__FILE__)}/../lib/registry/charlie_test.rb")
|
568
|
+
@app.cmd("register add Sample::EchoTest #{File.dirname(__FILE__) + "/../lib/registry/echo_test.rb"}")
|
569
|
+
@app.cmd("echo-test blah blah blah")[:data].should == "blah blah blah"
|
570
|
+
@app.cmd("charlie-test ra ra ra")[:data].should == "ra ra ra"
|
571
|
+
end
|
572
|
+
|
573
|
+
it "should ignore unknown commands" do
|
574
|
+
@app.cmd("charlie-test ra ra ra")[:data].should == nil
|
575
|
+
@app.history.should == ["UNKNOWN CMD: charlie-test ra ra ra\n"]
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should not registry twice" do
|
579
|
+
@app.cmd("register add CharlieTest")
|
580
|
+
@app.cmd("register add CharlieTest")
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
describe "rm" do
|
585
|
+
|
586
|
+
it "should return a result" do
|
587
|
+
@app.cmd("register add CharlieTest")
|
588
|
+
result = @app.cmd("register rm CharlieTest")
|
589
|
+
result[:data].should == 1
|
590
|
+
|
591
|
+
result = @app.cmd("register rm Blah")
|
592
|
+
result[:data].should == 0
|
593
|
+
end
|
594
|
+
|
595
|
+
it "should look in registry if filename not provided" do
|
596
|
+
@app.cmd("register add Sample::EchoTest")
|
597
|
+
@app.cmd("register rm Sample::EchoTest")
|
598
|
+
@app.cmd("echo-test blah blah blah")[:data].should == nil
|
599
|
+
@app.history.should == ["UNKNOWN CMD: echo-test blah blah blah\n"]
|
600
|
+
end
|
601
|
+
|
602
|
+
end
|
603
|
+
|
604
|
+
describe "reload" do
|
605
|
+
|
606
|
+
it "should reload what is in redis" do
|
607
|
+
@redis.sadd("Eve.#{$$}.registers","CharlieTest")
|
608
|
+
@redis.sadd("Eve.#{$$}.register_files","#{File.dirname(__FILE__)}/../lib/registry/charlie_test.rb")
|
609
|
+
@app.cmd("register reload")
|
610
|
+
@app.cmd("charlie-test ra ra ra")[:data].should == "ra ra ra"
|
611
|
+
end
|
612
|
+
|
613
|
+
end
|
614
|
+
|
615
|
+
end
|
616
|
+
|
617
|
+
end
|
618
|
+
|
619
|
+
describe "#alive?" do
|
620
|
+
|
621
|
+
it "should check to see if process still running" do
|
622
|
+
Application.alive?($$).should == true
|
623
|
+
Application.alive?(-999).should == false
|
624
|
+
end
|
625
|
+
|
626
|
+
it "should access nil / empty" do
|
627
|
+
Application.alive?(nil).should == false
|
628
|
+
Application.alive?("").should == false
|
629
|
+
end
|
630
|
+
|
631
|
+
end
|
632
|
+
|
633
|
+
describe "#system_call" do
|
634
|
+
|
635
|
+
it "should track the command" do
|
636
|
+
IO.write("deleteme.txt","hello")
|
637
|
+
@app.system_call("cp deleteme.txt deleteme2.txt")
|
638
|
+
@app.system_calls.history.should == ["CALLING: cp deleteme.txt deleteme2.txt\n"]
|
639
|
+
File.exists?("deleteme2.txt").should == true
|
640
|
+
IO.read("deleteme2.txt").should == "hello"
|
641
|
+
end
|
642
|
+
|
643
|
+
end
|
644
|
+
|
645
|
+
describe "#self.ids" do
|
646
|
+
|
647
|
+
it "should lookup in redis" do
|
648
|
+
redis = Utest::InmemoryRedis.new
|
649
|
+
|
650
|
+
Application.ids(redis).should == []
|
651
|
+
|
652
|
+
redis.sadd("Eve.ApplicationIds","123")
|
653
|
+
Application.ids(redis).should == [ "123" ]
|
654
|
+
|
655
|
+
redis.sadd("Eve.ApplicationIds","456")
|
656
|
+
Application.ids(redis).should == [ "123", "456" ]
|
657
|
+
end
|
658
|
+
|
659
|
+
end
|
660
|
+
|
661
|
+
describe "#next_cmds" do
|
662
|
+
|
663
|
+
before(:each) do
|
664
|
+
@app.cmd("appid")
|
665
|
+
end
|
666
|
+
|
667
|
+
it "should grab from the queue first" do
|
668
|
+
@app.enqueue_cmd("version")
|
669
|
+
@app.next_cmds.should == ["version"]
|
670
|
+
@app.enqueue_cmd("source")
|
671
|
+
@app.next_cmds.should == ["source"]
|
672
|
+
end
|
673
|
+
|
674
|
+
it "should quit if fixed" do
|
675
|
+
@app.mode = :queue
|
676
|
+
@app.next_cmds.should == ["exit"]
|
677
|
+
end
|
678
|
+
|
679
|
+
it "should look to console if shell" do
|
680
|
+
@app.mode = :shell
|
681
|
+
@app.stub!(:user_input).and_return("version","exit")
|
682
|
+
@app.next_cmds.should == ["version"]
|
683
|
+
end
|
684
|
+
|
685
|
+
it "should look to console if event" do
|
686
|
+
@app.mode = :event
|
687
|
+
@app.stub!(:user_input).and_return("version","exit")
|
688
|
+
@app.next_cmds.should == ["version"]
|
689
|
+
@app.next_cmds.should == ["exit"]
|
690
|
+
end
|
691
|
+
|
692
|
+
describe "poll" do
|
693
|
+
|
694
|
+
before(:each) do
|
695
|
+
@app.mode = :poll
|
696
|
+
end
|
697
|
+
|
698
|
+
it "should be nothing if no sources/targets and on poll" do
|
699
|
+
@app.next_cmds.should == ["sleep 300"]
|
700
|
+
end
|
701
|
+
|
702
|
+
it "should call the cmds and then sleep" do
|
703
|
+
@app.cmd("poll add do_blah a")
|
704
|
+
@app.cmd("poll add do_blah b")
|
705
|
+
@app.next_cmds.should == [ "do_blah a", "do_blah b", "sleep 300"]
|
706
|
+
end
|
707
|
+
|
708
|
+
end
|
709
|
+
|
710
|
+
it "should be gather if sources/targets and on poll" do
|
711
|
+
@app.mode = :poll
|
712
|
+
@app.cmd("source add /a/b/c")
|
713
|
+
@app.cmd("target add /a/b/d")
|
714
|
+
@app.next_cmds.should == ["sleep 300"]
|
715
|
+
end
|
716
|
+
|
717
|
+
end
|
718
|
+
|
719
|
+
describe "#post_init" do
|
720
|
+
|
721
|
+
it "should say hello" do
|
722
|
+
@app.post_init
|
723
|
+
@app.history.should == [ "Connection Established\n" ]
|
724
|
+
end
|
725
|
+
|
726
|
+
end
|
727
|
+
|
728
|
+
describe "#receive_data" do
|
729
|
+
|
730
|
+
it "should delegate to cmd" do
|
731
|
+
@app.should_receive(:cmd).with("blah",true,true)
|
732
|
+
@app.receive_data("blah")
|
733
|
+
end
|
734
|
+
|
735
|
+
end
|
736
|
+
|
737
|
+
end
|
738
|
+
end
|