presence 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.simplecov +2 -1
- data/Rakefile +1 -1
- data/bin/presence_scan +14 -0
- data/lib/presence/commands.rb +2 -1
- data/lib/presence/listeners/http_notifier.rb +83 -0
- data/lib/presence/listeners/logger.rb +45 -18
- data/lib/presence/listeners/tracker.rb +9 -17
- data/lib/presence/scanner.rb +5 -6
- data/lib/presence/version.rb +1 -1
- data/lib/presence.rb +1 -0
- data/spec/presence/http_notifier_spec.rb +69 -0
- data/spec/presence/logger_spec.rb +103 -0
- data/spec/presence/scanner_spec.rb +58 -1
- data/spec/presence/tracker_spec.rb +4 -0
- data/spec/support/io_spec_helpers.rb +33 -0
- metadata +11 -2
data/.simplecov
CHANGED
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ begin
|
|
13
13
|
cane.abc_max = 15
|
14
14
|
cane.style_measure = 100
|
15
15
|
cane.style_glob = '{lib}/**/*.rb'
|
16
|
-
cane.gte = {'coverage/covered_percent' =>
|
16
|
+
cane.gte = {'coverage/covered_percent' => 80}
|
17
17
|
end
|
18
18
|
rescue LoadError
|
19
19
|
warn "cane not available, quality task not provided."
|
data/bin/presence_scan
CHANGED
@@ -8,14 +8,28 @@ if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
|
|
8
8
|
end
|
9
9
|
|
10
10
|
require 'presence'
|
11
|
+
|
11
12
|
# Presence::CLI::Root.start
|
12
13
|
|
14
|
+
# Usage: presence [OPTIONS]
|
15
|
+
#
|
16
|
+
# presence --start 10.0.1.1 --end 10.0.1.30
|
17
|
+
# presence --prefix 192.168.0
|
18
|
+
# presence --verbose
|
19
|
+
# presence --quiet
|
20
|
+
# presence --once
|
21
|
+
# presence --loop
|
22
|
+
# presence --listener Carnegie::Listener
|
23
|
+
|
24
|
+
# --once
|
13
25
|
# s = Presence::Scanner.new
|
14
26
|
# s.register_listener(Presence::Logger.new)
|
15
27
|
# s.register_listener(Presence::Tracker.new)
|
16
28
|
# s.scan
|
17
29
|
|
30
|
+
# --loop
|
18
31
|
Presence::Scanner.scan_loop do |s|
|
32
|
+
# s.options[:octet_range] = (30..32)
|
19
33
|
s.register_listener(Presence::Logger.new)
|
20
34
|
s.register_listener(Presence::Tracker.new)
|
21
35
|
end
|
data/lib/presence/commands.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module Presence
|
5
|
+
|
6
|
+
# Scanner listener that sends an HTTP notification whenever a new client
|
7
|
+
# connects or when a connected client disconnects. This listener is intended
|
8
|
+
# to be used with Presence::Tracker when scanning in a loop.
|
9
|
+
class HTTPNotifier
|
10
|
+
|
11
|
+
def initialize(options = nil)
|
12
|
+
options ||= {}
|
13
|
+
@options = {
|
14
|
+
use_ssl: false,
|
15
|
+
verify_mode: OpenSSL::SSL::VERIFY_PEER
|
16
|
+
}.merge(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def listener_registered(l, scanner)
|
20
|
+
@scanner ||= scanner
|
21
|
+
end
|
22
|
+
|
23
|
+
def mac_connected(mac, ip)
|
24
|
+
notify(:mac_connected, { mac: mac, ip: ip })
|
25
|
+
end
|
26
|
+
|
27
|
+
def mac_disconnected(mac, old_ip)
|
28
|
+
notify(:mac_disconnected, { mac: mac, ip: old_ip })
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def notify_uri
|
34
|
+
@notify_uri ||= URI.parse(@options[:url])
|
35
|
+
end
|
36
|
+
|
37
|
+
def notify(event, params)
|
38
|
+
request = prepare_request(event, params)
|
39
|
+
do_request(request)
|
40
|
+
end
|
41
|
+
|
42
|
+
def do_request(request)
|
43
|
+
response = nil
|
44
|
+
|
45
|
+
begin
|
46
|
+
http = prepare_http
|
47
|
+
response = http.request(request)
|
48
|
+
check_response(response)
|
49
|
+
rescue SocketError,
|
50
|
+
Timeout::Error,
|
51
|
+
Errno::ECONNREFUSED,
|
52
|
+
Errno::EHOSTDOWN,
|
53
|
+
Errno::EHOSTUNREACH,
|
54
|
+
Errno::ETIMEDOUT => e
|
55
|
+
@scanner.dispatch(:http_notification_failed, e.class.name, e.message)
|
56
|
+
end
|
57
|
+
|
58
|
+
response
|
59
|
+
end
|
60
|
+
|
61
|
+
def prepare_request(event, params)
|
62
|
+
request = Net::HTTP::Post.new(notify_uri.request_uri, @options[:headers])
|
63
|
+
request.set_form_data(params.merge(event: event))
|
64
|
+
if @options[:username]
|
65
|
+
request.basic_auth(@options[:username], @options[:password])
|
66
|
+
end
|
67
|
+
request
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_http
|
71
|
+
http = Net::HTTP.new(notify_uri.host, notify_uri.port)
|
72
|
+
http.use_ssl = @options[:use_ssl]
|
73
|
+
http.verify_mode = @options[:verify_mode]
|
74
|
+
http
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_response(response)
|
78
|
+
unless (200..206).map(&:to_s).include?(response.code)
|
79
|
+
@scanner.dispatch(:http_notification_failed, response.code, response.body)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -5,61 +5,88 @@ module Presence
|
|
5
5
|
# default, it uses a Logger instance that writes to stdout. To enable more
|
6
6
|
# verbose output, set:
|
7
7
|
#
|
8
|
-
# logger.level = ::Logger::INFO
|
8
|
+
# logger.log.level = ::Logger::INFO
|
9
9
|
#
|
10
10
|
# or:
|
11
11
|
#
|
12
|
-
# logger.level = ::Logger::DEBUG
|
12
|
+
# logger.log.level = ::Logger::DEBUG
|
13
13
|
#
|
14
|
-
# To write to a file or some other outlet, pass
|
14
|
+
# To write to a file or some other outlet, pass a Ruby Logger instance to the
|
15
15
|
# constructor.
|
16
16
|
class Logger
|
17
|
-
attr_accessor :
|
17
|
+
attr_accessor :log
|
18
18
|
|
19
19
|
def initialize(log = nil)
|
20
20
|
if log.nil?
|
21
|
-
log = ::Logger.new(
|
21
|
+
log = ::Logger.new($stdout)
|
22
22
|
log.level = ::Logger::WARN
|
23
23
|
log.formatter = proc do |severity, datetime, progname, msg|
|
24
24
|
"#{msg}\n"
|
25
25
|
end
|
26
26
|
end
|
27
|
-
self.
|
27
|
+
self.log = log
|
28
28
|
end
|
29
29
|
|
30
30
|
def listener_registered(listener, scanner)
|
31
|
-
|
31
|
+
log.info "Registered listener: <#{listener.class}> for: #{scanner}"
|
32
32
|
end
|
33
33
|
|
34
34
|
def scan_started(ip_prefix, range)
|
35
|
-
|
35
|
+
log.info "Scanning range: #{ip_prefix}.#{range.first} to #{ip_prefix}.#{range.last}"
|
36
36
|
end
|
37
37
|
|
38
38
|
def scan_finished(ip_prefix, range)
|
39
|
-
|
39
|
+
log.info "Scan finished."
|
40
40
|
end
|
41
41
|
|
42
42
|
def ip_scanned(ip, cmd, result)
|
43
|
-
|
43
|
+
log.debug " - Checked #{ip} with #{cmd}"
|
44
44
|
result.split("\n").each do |l|
|
45
|
-
|
45
|
+
log.debug " #{l}"
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def localhost_found(ip, mac)
|
50
|
-
|
50
|
+
log.debug " * Found localhost!"
|
51
51
|
end
|
52
52
|
|
53
53
|
def mac_found(ip, mac)
|
54
|
-
|
55
|
-
logger.debug " * Found #{mac} at #{ip}"
|
56
|
-
logger.debug
|
54
|
+
log.debug " * Found #{mac} at #{ip}"
|
57
55
|
end
|
58
56
|
|
59
57
|
def mac_not_found(ip)
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
log.debug " * No MAC found at #{ip}"
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def log_unknown_event(method_sym, *arguments)
|
64
|
+
# puts "method_sym = #{method_sym}"
|
65
|
+
# puts "arguments = #{arguments.inspect}"
|
66
|
+
# puts "log = #{log}"
|
67
|
+
# raise 'hell'
|
68
|
+
log.warn("#{method_sym}: #{arguments.inspect}")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Always log events, even if there is no explicit handler. Generate a
|
72
|
+
# method at runtime so we don't have to do method_missing every time.
|
73
|
+
def method_missing(method_sym, *arguments, &block)
|
74
|
+
arg_names = arguments.each_with_index.map { |arg, i| "arg#{i}" }
|
75
|
+
arg_list = arg_names.join(',')
|
76
|
+
instance_eval <<-RUBY
|
77
|
+
def #{method_sym}(#{arg_list})
|
78
|
+
log_unknown_event(:#{method_sym}, #{arg_list})
|
79
|
+
end
|
80
|
+
RUBY
|
81
|
+
# def method_sym(arg1, arg2, ...)
|
82
|
+
# log_unknown_event(:method_sym, arg1, arg2, ...)
|
83
|
+
# end
|
84
|
+
send(method_sym, *arguments)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Respond to anything.
|
88
|
+
def respond_to_missing?(method_sym, include_private = false)
|
89
|
+
true
|
63
90
|
end
|
64
91
|
end
|
65
92
|
end
|
@@ -7,20 +7,23 @@ module Presence
|
|
7
7
|
# list of MAC addresses on the network and detect when a new client connects
|
8
8
|
# or when a connected client disconnects.
|
9
9
|
class Tracker
|
10
|
+
|
10
11
|
def initialize
|
11
12
|
@mac_history = {}
|
12
13
|
@current_list = Presence::MACList.new
|
13
14
|
end
|
14
15
|
|
15
16
|
def listener_registered(l, scanner)
|
16
|
-
scanner
|
17
|
+
@scanner ||= scanner
|
18
|
+
@scanner.register_listener(@current_list) if l == self
|
17
19
|
end
|
18
20
|
|
19
21
|
def mac_found(ip, mac)
|
20
22
|
if @mac_history[mac].nil?
|
21
|
-
mac_connected
|
23
|
+
dispatch(:mac_connected, mac, ip)
|
22
24
|
elsif @mac_history[mac] != ip
|
23
|
-
|
25
|
+
old_ip = @mac_history[mac]
|
26
|
+
dispatch(:mac_changed, mac, old_ip, ip)
|
24
27
|
end
|
25
28
|
@mac_history[mac] = ip
|
26
29
|
end
|
@@ -29,25 +32,14 @@ module Presence
|
|
29
32
|
macs_left = @mac_history.keys - @current_list.macs_found.keys
|
30
33
|
macs_left.each do |mac|
|
31
34
|
old_ip = @mac_history[mac]
|
32
|
-
mac_disconnected
|
35
|
+
dispatch(:mac_disconnected, mac, old_ip)
|
33
36
|
@mac_history.delete(mac)
|
34
37
|
end
|
35
38
|
@current_list.macs_found.clear
|
36
39
|
end
|
37
40
|
|
38
|
-
def
|
39
|
-
|
40
|
-
# Do something interesting.
|
41
|
-
end
|
42
|
-
|
43
|
-
def mac_changed(mac, old_ip, new_ip)
|
44
|
-
puts " ** #{mac} changed ip from: #{old_ip} to #{new_ip}"
|
45
|
-
# Do something interesting.
|
46
|
-
end
|
47
|
-
|
48
|
-
def mac_disconnected(mac, old_ip)
|
49
|
-
puts " ** #{mac} disconnected from #{old_ip}"
|
50
|
-
# Do something interesting.
|
41
|
+
def dispatch(event, *args)
|
42
|
+
@scanner.dispatch(event, *args)
|
51
43
|
end
|
52
44
|
end
|
53
45
|
end
|
data/lib/presence/scanner.rb
CHANGED
@@ -82,12 +82,11 @@ module Presence
|
|
82
82
|
class << self
|
83
83
|
def check_env
|
84
84
|
commands = Commands.new
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
raise Presence::InvalidEnvironment.new("Install arping first: brew install arping")
|
85
|
+
required_commands = %w{ifconfig arping}
|
86
|
+
required_commands.each do |cmd|
|
87
|
+
if commands.run("which #{cmd}").size == 0
|
88
|
+
raise Presence::InvalidEnvironment.new("Unsupported platform: #{cmd} not found.")
|
89
|
+
end
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
data/lib/presence/version.rb
CHANGED
data/lib/presence.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Presence::HTTPNotifier do
|
4
|
+
let(:username) { nil }
|
5
|
+
let(:password) { nil }
|
6
|
+
let(:notifier) {
|
7
|
+
Presence::HTTPNotifier.new(
|
8
|
+
url: 'http://example.com/presence_events.json',
|
9
|
+
username: username,
|
10
|
+
password: password
|
11
|
+
)
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:scanner) { stub(Presence::Scanner) }
|
15
|
+
before { notifier.listener_registered(notifier, scanner) }
|
16
|
+
|
17
|
+
let(:http) { stub(Net::HTTP, :use_ssl= => nil, :verify_mode= => nil) }
|
18
|
+
let(:response) { stub(code: '200') }
|
19
|
+
before {
|
20
|
+
http.stub(:request).and_return(response)
|
21
|
+
Net::HTTP.stub(:new).with('example.com', 80).and_return(http)
|
22
|
+
}
|
23
|
+
|
24
|
+
context 'with a username and password' do
|
25
|
+
let(:username) { 'margot' }
|
26
|
+
let(:password) { 'poppie' }
|
27
|
+
|
28
|
+
it 'sends the username and password in the request' do
|
29
|
+
http.should_receive(:request) do |r|
|
30
|
+
r['authorization'].should == 'Basic bWFyZ290OnBvcHBpZQ=='
|
31
|
+
response
|
32
|
+
end
|
33
|
+
notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'dispatches an error notification if the request returns an error code' do
|
38
|
+
response.should_receive(:code).at_least(1).times.and_return('400')
|
39
|
+
response.should_receive(:body).and_return('Invalid request')
|
40
|
+
scanner.should_receive(:dispatch).with(:http_notification_failed, '400', 'Invalid request')
|
41
|
+
|
42
|
+
notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'dispatches an error notification if the request raises a network error' do
|
46
|
+
http.should_receive(:request).and_raise(SocketError.new('bad things occurred'))
|
47
|
+
scanner.should_receive(:dispatch).with(:http_notification_failed, 'SocketError', 'bad things occurred')
|
48
|
+
|
49
|
+
notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'sends a POST request on mac_connected' do
|
53
|
+
http.should_receive(:request) do |r|
|
54
|
+
r.method.should == 'POST'
|
55
|
+
r.body.should == 'mac=AA%3ABB%3ACC%3ADD%3AEE%3AFF&ip=10.0.1.49&event=mac_connected'
|
56
|
+
response
|
57
|
+
end
|
58
|
+
notifier.mac_connected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'sends a POST request on mac_disconnected' do
|
62
|
+
http.should_receive(:request) do |r|
|
63
|
+
r.method.should == 'POST'
|
64
|
+
r.body.should == 'mac=AA%3ABB%3ACC%3ADD%3AEE%3AFF&ip=10.0.1.49&event=mac_disconnected'
|
65
|
+
response
|
66
|
+
end
|
67
|
+
notifier.mac_disconnected('AA:BB:CC:DD:EE:FF', '10.0.1.49')
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Presence::Logger do
|
4
|
+
let(:level) { ::Logger::INFO }
|
5
|
+
let(:io) { StringIO.new }
|
6
|
+
let(:log) {
|
7
|
+
log = ::Logger.new(io)
|
8
|
+
log.level = level
|
9
|
+
log.formatter = proc do |severity, datetime, progname, msg|
|
10
|
+
"#{msg}\n"
|
11
|
+
end
|
12
|
+
log
|
13
|
+
}
|
14
|
+
let(:logger) { Presence::Logger.new(log) }
|
15
|
+
|
16
|
+
context 'with no ::Logger specified' do
|
17
|
+
let(:log) { nil }
|
18
|
+
|
19
|
+
it 'logs warnings to stdout by default' do
|
20
|
+
result = capture_stdout do |variable|
|
21
|
+
logger.log.warn('Run, baby, run!')
|
22
|
+
end
|
23
|
+
result.should == "Run, baby, run!\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'does not log info by default' do
|
27
|
+
result = capture_stdout do |variable|
|
28
|
+
logger.log.info('Run, baby, run!')
|
29
|
+
end
|
30
|
+
result.should == ''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with DEBUG logging' do
|
35
|
+
let(:level) { ::Logger::DEBUG }
|
36
|
+
|
37
|
+
it 'logs ip_scanned events' do
|
38
|
+
logger.ip_scanned('10.0.1.1', 'sudo arping', 'nada')
|
39
|
+
io.string.should == " - Checked 10.0.1.1 with sudo arping\n nada\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'logs localhost_found events' do
|
43
|
+
logger.localhost_found('10.0.1.1', 'AA:BB:CC:DD:EE:FF')
|
44
|
+
io.string.should == " * Found localhost!\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'logs mac_found events' do
|
48
|
+
logger.mac_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
|
49
|
+
io.string.should == " * Found aa:bb:cc:dd:ee:ff at 10.0.1.1\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'logs mac_not_found events' do
|
53
|
+
logger.mac_not_found('10.0.1.1')
|
54
|
+
io.string.should == " * No MAC found at 10.0.1.1\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'logs unknown events' do
|
58
|
+
logger.respond_to?(:miracle_occurred).should be_true
|
59
|
+
logger.miracle_occurred('256.256.256.256', 'GG:GG:GG:GG:GG:GG', 49)
|
60
|
+
io.string.should == "miracle_occurred: [\"256.256.256.256\", \"GG:GG:GG:GG:GG:GG\", 49]\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with INFO logging' do
|
66
|
+
let(:level) { ::Logger::INFO }
|
67
|
+
|
68
|
+
it 'logs listener_registered events' do
|
69
|
+
logger.listener_registered(logger, 'Scanner')
|
70
|
+
io.string.should == "Registered listener: <Presence::Logger> for: Scanner\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'logs scan_started events' do
|
74
|
+
logger.scan_started('10.0.1', (1..255))
|
75
|
+
io.string.should == "Scanning range: 10.0.1.1 to 10.0.1.255\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'logs scan_finished events' do
|
79
|
+
logger.scan_finished('10.0.1', (1..255))
|
80
|
+
io.string.should == "Scan finished.\n"
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'does not log ip_scanned events' do
|
84
|
+
logger.ip_scanned('10.0.1.1', 'sudo arping', 'nada')
|
85
|
+
io.string.should == ''
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'does not log localhost_found events' do
|
89
|
+
logger.localhost_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
|
90
|
+
io.string.should == ''
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'does not log mac_found events' do
|
94
|
+
logger.mac_found('10.0.1.1', 'aa:bb:cc:dd:ee:ff')
|
95
|
+
io.string.should == ''
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'does not log mac_not_found events' do
|
99
|
+
logger.mac_not_found('10.0.1.1')
|
100
|
+
io.string.should == ''
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -10,7 +10,7 @@ describe Presence::Scanner do
|
|
10
10
|
|
11
11
|
let(:commands) {
|
12
12
|
commands = stub(Presence::Commands)
|
13
|
-
Presence::Commands.
|
13
|
+
Presence::Commands.stub(:new).and_return(commands)
|
14
14
|
commands
|
15
15
|
}
|
16
16
|
let(:listener) {
|
@@ -28,6 +28,63 @@ describe Presence::Scanner do
|
|
28
28
|
commands.stub(:arping).with(ip).and_return([arping_cmd, mac])
|
29
29
|
}
|
30
30
|
|
31
|
+
describe '.check_env' do
|
32
|
+
before {
|
33
|
+
commands.stub(:run).with('which ifconfig').and_return('/sbin/ifconfig')
|
34
|
+
commands.stub(:run).with('which arping').and_return('/usr/local/sbin/arping')
|
35
|
+
}
|
36
|
+
|
37
|
+
it 'checks for ifconfig' do
|
38
|
+
commands.should_receive(:run).with('which ifconfig').and_return('/sbin/ifconfig')
|
39
|
+
Presence::Scanner.check_env
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'raises an exception if ifconfig is not found' do
|
43
|
+
commands.should_receive(:run).with('which ifconfig').and_return('')
|
44
|
+
expect {
|
45
|
+
Presence::Scanner.check_env
|
46
|
+
}.to raise_error(Presence::InvalidEnvironment, "Unsupported platform: ifconfig not found.")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'checks for arping' do
|
50
|
+
commands.should_receive(:run).with('which arping').and_return('/usr/local/sbin/arping')
|
51
|
+
Presence::Scanner.check_env
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises an exception if arping is not found' do
|
55
|
+
commands.should_receive(:run).with('which arping').and_return('')
|
56
|
+
expect {
|
57
|
+
Presence::Scanner.check_env
|
58
|
+
}.to raise_error(Presence::InvalidEnvironment, "Unsupported platform: arping not found.")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '.scan_loop' do
|
63
|
+
let(:scanner) { mock(Presence::Scanner) }
|
64
|
+
before { Presence::Scanner.should_receive(:new).and_return(scanner) }
|
65
|
+
|
66
|
+
it 'scans until interrupted' do
|
67
|
+
scanner.should_receive(:scan)
|
68
|
+
scanner.should_receive(:scan)
|
69
|
+
scanner.should_receive(:scan).and_raise(Interrupt.new)
|
70
|
+
Presence::Scanner.scan_loop
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'yields the scanner instance to a block' do
|
74
|
+
scanner.stub(:scan).and_raise(Interrupt.new)
|
75
|
+
scanner.should_receive(:register_listener)
|
76
|
+
Presence::Scanner.scan_loop do |s|
|
77
|
+
s.register_listener(Object.new)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#to_s' do
|
83
|
+
it 'overrides to_s' do
|
84
|
+
scanner.to_s.should == "<Presence::Scanner ip_prefix: '10.0.1' octet_range: (30..32)>"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
31
88
|
describe '#scan' do
|
32
89
|
it 'dispatches a scan_started event' do
|
33
90
|
listener.should_receive(:scan_started).with('10.0.1', octet_range)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Presence
|
2
|
+
module IOSpecHelpers
|
3
|
+
def suppress_output
|
4
|
+
@original_stdout, $stdout = $stdout, StringIO.new
|
5
|
+
@original_stderr, $stderr = $stderr, StringIO.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def reset_output
|
9
|
+
$stdout = @original_stdout
|
10
|
+
$stderr = @original_stderr
|
11
|
+
end
|
12
|
+
|
13
|
+
def capture_stdout
|
14
|
+
original_stdout, $stdout = $stdout, StringIO.new
|
15
|
+
yield
|
16
|
+
$stdout.string
|
17
|
+
ensure
|
18
|
+
$stdout = original_stdout
|
19
|
+
end
|
20
|
+
|
21
|
+
def capture_stderr
|
22
|
+
original_stderr, $stderr = $stderr, StringIO.new
|
23
|
+
yield
|
24
|
+
$stderr.string
|
25
|
+
ensure
|
26
|
+
$stderr = original_stderr
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec.configure do |config|
|
32
|
+
config.include Presence::IOSpecHelpers
|
33
|
+
end
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: presence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jason Wadsworth
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
prerelease: false
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/presence.rb
|
95
95
|
- lib/presence/commands.rb
|
96
96
|
- lib/presence/errors.rb
|
97
|
+
- lib/presence/listeners/http_notifier.rb
|
97
98
|
- lib/presence/listeners/logger.rb
|
98
99
|
- lib/presence/listeners/mac_list.rb
|
99
100
|
- lib/presence/listeners/mac_printer.rb
|
@@ -102,8 +103,12 @@ files:
|
|
102
103
|
- lib/presence/scanner.rb
|
103
104
|
- lib/presence/version.rb
|
104
105
|
- presence.gemspec
|
106
|
+
- spec/presence/http_notifier_spec.rb
|
107
|
+
- spec/presence/logger_spec.rb
|
105
108
|
- spec/presence/scanner_spec.rb
|
109
|
+
- spec/presence/tracker_spec.rb
|
106
110
|
- spec/spec_helper.rb
|
111
|
+
- spec/support/io_spec_helpers.rb
|
107
112
|
homepage: https://github.com/subakva/presence
|
108
113
|
licenses: []
|
109
114
|
post_install_message:
|
@@ -129,5 +134,9 @@ signing_key:
|
|
129
134
|
specification_version: 3
|
130
135
|
summary: Plays theme music when d8:d1:cb:b3:af:c4 arrives.
|
131
136
|
test_files:
|
137
|
+
- spec/presence/http_notifier_spec.rb
|
138
|
+
- spec/presence/logger_spec.rb
|
132
139
|
- spec/presence/scanner_spec.rb
|
140
|
+
- spec/presence/tracker_spec.rb
|
133
141
|
- spec/spec_helper.rb
|
142
|
+
- spec/support/io_spec_helpers.rb
|