hidden-hippo 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +47 -0
- data/.rspec +2 -0
- data/.travis.yml +16 -0
- data/Gemfile +3 -0
- data/HACKING.md +78 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +5 -0
- data/Vagrantfile +24 -0
- data/bin/hh +4 -0
- data/ci/install-tshark.sh +21 -0
- data/config/gui-dev.ru +6 -0
- data/config/mongoid.yml +20 -0
- data/gui/public/favicon.png +0 -0
- data/gui/public/hidden-hippo.css +18 -0
- data/gui/public/user-placeholder.png +0 -0
- data/gui/views/dossier.rhtml +12 -0
- data/gui/views/index.rhtml +25 -0
- data/gui/views/layout.rhtml +31 -0
- data/gui/views/possibilities.rhtml +10 -0
- data/hidden-hippo.gemspec +31 -0
- data/hippo-small.png +0 -0
- data/hippo.png +0 -0
- data/lib/hidden_hippo/cli/app.rb +23 -0
- data/lib/hidden_hippo/cli/database.rb +47 -0
- data/lib/hidden_hippo/cli/gui.rb +51 -0
- data/lib/hidden_hippo/daemon.rb +90 -0
- data/lib/hidden_hippo/dossier.rb +23 -0
- data/lib/hidden_hippo/extractors/dhcp_hostname_extractor.rb +16 -0
- data/lib/hidden_hippo/extractors/dns_history_extractor.rb +25 -0
- data/lib/hidden_hippo/extractors/dns_llmnr_extractor.rb +18 -0
- data/lib/hidden_hippo/extractors/http_request_url_extractor.rb +15 -0
- data/lib/hidden_hippo/extractors/mdns_hostname_extractor.rb +18 -0
- data/lib/hidden_hippo/gui.rb +21 -0
- data/lib/hidden_hippo/packets/dhcp.rb +13 -0
- data/lib/hidden_hippo/packets/dns.rb +23 -0
- data/lib/hidden_hippo/packets/http.rb +13 -0
- data/lib/hidden_hippo/packets/packet.rb +73 -0
- data/lib/hidden_hippo/paths.rb +15 -0
- data/lib/hidden_hippo/possibilities.rb +63 -0
- data/lib/hidden_hippo/reader.rb +36 -0
- data/lib/hidden_hippo/scanner.rb +51 -0
- data/lib/hidden_hippo/update.rb +3 -0
- data/lib/hidden_hippo/updator.rb +49 -0
- data/lib/hidden_hippo/version.rb +3 -0
- data/lib/hidden_hippo.rb +23 -0
- data/spec/db_daemon_spec.rb +7 -0
- data/spec/dns_scanner_spec.rb +41 -0
- data/spec/dossier_spec.rb +72 -0
- data/spec/extractors/dhcp_hostname_extractor_spec.rb +43 -0
- data/spec/extractors/dns_history_extractor_spec.rb +52 -0
- data/spec/extractors/dns_llmnr_extractor_spec.rb +45 -0
- data/spec/extractors/http_request_url_extractor_spec.rb +23 -0
- data/spec/extractors/mdns_hostname_extractor_spec.rb +45 -0
- data/spec/fixtures/dns_elise.pcap +0 -0
- data/spec/fixtures/dns_reddit_eth.pcap +0 -0
- data/spec/fixtures/tcp_noise.pcap +0 -0
- data/spec/gui_daemon_spec.rb +7 -0
- data/spec/hidden_hippo_spec.rb +32 -0
- data/spec/packet_spec.rb +88 -0
- data/spec/possibilities_spec.rb +113 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/cli_controller_examples.rb +136 -0
- data/spec/updator_spec.rb +37 -0
- metadata +274 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'hidden_hippo/packets/dns'
|
3
|
+
require 'hidden_hippo/extractors/dns_history_extractor'
|
4
|
+
|
5
|
+
describe HiddenHippo::Extractors::DnsHistoryExtractor do
|
6
|
+
let(:queue) {Queue.new}
|
7
|
+
let(:extractor) {HiddenHippo::Extractors::DnsHistoryExtractor.new queue}
|
8
|
+
|
9
|
+
describe '#call' do
|
10
|
+
it 'should find the query_name/hostname in response' do
|
11
|
+
packet = HiddenHippo::Packets::Dns.new
|
12
|
+
packet.udp_dest_port = 53
|
13
|
+
packet.response = true
|
14
|
+
packet.eth_mac_src = 'some mac'
|
15
|
+
packet.eth_mac_dest = 'some other mac'
|
16
|
+
packet.dns_qry_name = 'dns resolution'
|
17
|
+
|
18
|
+
extractor.call packet
|
19
|
+
|
20
|
+
out = queue.pop true
|
21
|
+
expect(out).not_to be_nil
|
22
|
+
expect(out.mac_address).to eq 'some other mac'
|
23
|
+
expect(out.fields).to eq({history: 'dns resolution'})
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should find the query_name/hostname in query' do
|
27
|
+
packet = HiddenHippo::Packets::Dns.new
|
28
|
+
packet.udp_dest_port = 53
|
29
|
+
packet.response = false
|
30
|
+
packet.eth_mac_src = 'some mac'
|
31
|
+
packet.eth_mac_dest = 'some other mac'
|
32
|
+
packet.dns_qry_name = 'dns resolution'
|
33
|
+
|
34
|
+
extractor.call packet
|
35
|
+
|
36
|
+
out = queue.pop true
|
37
|
+
expect(out).not_to be_nil
|
38
|
+
expect(out.mac_address).to eq 'some mac'
|
39
|
+
expect(out.fields).to eq({history: 'dns resolution'})
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should ignore packets not on port 53' do
|
43
|
+
packet = HiddenHippo::Packets::Dns.new
|
44
|
+
packet.udp_dest_port = 42
|
45
|
+
packet.response = true
|
46
|
+
|
47
|
+
extractor.call packet
|
48
|
+
|
49
|
+
expect(queue.size).to eq 0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'hidden_hippo/packets/dns'
|
3
|
+
require 'hidden_hippo/extractors/dns_llmnr_extractor'
|
4
|
+
|
5
|
+
describe HiddenHippo::Extractors::DnsLlmnrExtractor do
|
6
|
+
let(:queue) {Queue.new}
|
7
|
+
let(:extractor) {HiddenHippo::Extractors::DnsLlmnrExtractor.new queue}
|
8
|
+
|
9
|
+
describe '#call' do
|
10
|
+
it 'should find the query_name/hostname in response' do
|
11
|
+
packet = HiddenHippo::Packets::Dns.new
|
12
|
+
packet.udp_dest_port = 5355
|
13
|
+
packet.response = false
|
14
|
+
packet.eth_mac_src = 'some mac'
|
15
|
+
packet.dns_qry_name = 'the host name'
|
16
|
+
|
17
|
+
extractor.call packet
|
18
|
+
|
19
|
+
out = queue.pop true
|
20
|
+
expect(out).not_to be_nil
|
21
|
+
expect(out.mac_address).to eq 'some mac'
|
22
|
+
expect(out.fields).to eq({hostname: 'the host name'})
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should ignore packets not on port 5355' do
|
26
|
+
packet = HiddenHippo::Packets::Dns.new
|
27
|
+
packet.udp_dest_port = 42
|
28
|
+
packet.response = true
|
29
|
+
|
30
|
+
extractor.call packet
|
31
|
+
|
32
|
+
expect(queue.size).to eq 0
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should ignore non request' do
|
36
|
+
packet = HiddenHippo::Packets::Dns.new
|
37
|
+
packet.udp_dest_port = 5353
|
38
|
+
packet.response = true
|
39
|
+
|
40
|
+
extractor.call packet
|
41
|
+
|
42
|
+
expect(queue.size).to eq 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'hidden_hippo/packets/http'
|
3
|
+
require 'hidden_hippo/extractors/http_request_url_extractor'
|
4
|
+
|
5
|
+
describe HiddenHippo::Extractors::HttpRequestUrlExtractor do
|
6
|
+
let(:queue) {Queue.new}
|
7
|
+
let(:extractor) {HiddenHippo::Extractors::HttpRequestUrlExtractor.new queue}
|
8
|
+
|
9
|
+
describe '#call' do
|
10
|
+
it 'should have an url' do
|
11
|
+
packet = HiddenHippo::Packets::Http.new
|
12
|
+
packet.eth_mac_src = 'http some mac'
|
13
|
+
packet.full_uri = 'blob.com/totolatulipe?$=0.com'
|
14
|
+
|
15
|
+
extractor.call packet
|
16
|
+
|
17
|
+
out = queue.pop true
|
18
|
+
expect(out.mac_address).to eq 'http some mac'
|
19
|
+
expect(out.fields).to eq({history: 'blob.com/totolatulipe?$=0.com'})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'hidden_hippo/packets/dns'
|
3
|
+
require 'hidden_hippo/extractors/mdns_hostname_extractor'
|
4
|
+
|
5
|
+
describe HiddenHippo::Extractors::MdnsHostnameExtractor do
|
6
|
+
let(:queue) {Queue.new}
|
7
|
+
let(:extractor) {HiddenHippo::Extractors::MdnsHostnameExtractor.new queue}
|
8
|
+
|
9
|
+
describe '#call' do
|
10
|
+
it 'should find the hostname in a mdns ptr response' do
|
11
|
+
packet = HiddenHippo::Packets::Dns.new
|
12
|
+
packet.udp_dest_port = 5353
|
13
|
+
packet.response = true
|
14
|
+
packet.eth_mac_src = 'some mac'
|
15
|
+
packet.ptr = 'the host name'
|
16
|
+
|
17
|
+
extractor.call packet
|
18
|
+
|
19
|
+
out = queue.pop true
|
20
|
+
expect(out).not_to be_nil
|
21
|
+
expect(out.mac_address).to eq 'some mac'
|
22
|
+
expect(out.fields).to eq({hostname: 'the host name'})
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should ignore packets not on port 5353' do
|
26
|
+
packet = HiddenHippo::Packets::Dns.new
|
27
|
+
packet.udp_dest_port = 42
|
28
|
+
packet.response = true
|
29
|
+
|
30
|
+
extractor.call packet
|
31
|
+
|
32
|
+
expect(queue.size).to eq 0
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should ignore non responses' do
|
36
|
+
packet = HiddenHippo::Packets::Dns.new
|
37
|
+
packet.udp_dest_port = 5353
|
38
|
+
packet.response = false
|
39
|
+
|
40
|
+
extractor.call packet
|
41
|
+
|
42
|
+
expect(queue.size).to eq 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'hidden_hippo'
|
2
|
+
require 'mongoid'
|
3
|
+
|
4
|
+
describe HiddenHippo do
|
5
|
+
it 'should have a version' do
|
6
|
+
expect(HiddenHippo::VERSION).not_to be_nil
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#pid_exists?' do
|
10
|
+
it 'should return true for an existing pid' do
|
11
|
+
expect(HiddenHippo.pid_exists? Process.pid).to be_truthy
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should return false for a non existing pid' do
|
15
|
+
expect(HiddenHippo.pid_exists? 99999).to be_falsey
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#gem_root' do
|
20
|
+
it 'should point to the root of the gem' do
|
21
|
+
expect(HiddenHippo.gem_root).to eq Pathname.new(__FILE__) + '../..'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#configure_db!' do
|
26
|
+
it 'should configure mongoid' do
|
27
|
+
HiddenHippo.configure_db!
|
28
|
+
|
29
|
+
expect(Mongoid.configured?).to be_truthy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/packet_spec.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'hidden_hippo/packets/packet'
|
2
|
+
|
3
|
+
describe HiddenHippo::Packets::Packet do
|
4
|
+
|
5
|
+
describe '#field' do
|
6
|
+
it 'should create accessors' do
|
7
|
+
packet_class = Class.new(HiddenHippo::Packets::Packet) do
|
8
|
+
field :foobar
|
9
|
+
end
|
10
|
+
|
11
|
+
instance = packet_class.new
|
12
|
+
|
13
|
+
expect(instance).to respond_to :foobar, :foobar=
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should add to the fields list' do
|
17
|
+
packet_class = Class.new(HiddenHippo::Packets::Packet) do
|
18
|
+
field :foobar
|
19
|
+
end
|
20
|
+
|
21
|
+
expect(packet_class.fields.map &:name).to include :foobar
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#parse' do
|
26
|
+
it 'should parse using the tshark fields' do
|
27
|
+
klass = Class.new HiddenHippo::Packets::Packet do
|
28
|
+
field :foobar, tshark: 'proto.foobar'
|
29
|
+
end
|
30
|
+
|
31
|
+
instance = klass.parse 'proto.foobar' => 'butthole'
|
32
|
+
|
33
|
+
expect(instance.foobar).to eq 'butthole'
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should convert when the converter is set' do
|
37
|
+
klass = Class.new HiddenHippo::Packets::Packet do
|
38
|
+
field :answer, tshark: 'magic.number', conv: ->(a) {a.to_i}
|
39
|
+
end
|
40
|
+
|
41
|
+
instance = klass.parse 'magic.number' => '42'
|
42
|
+
|
43
|
+
expect(instance.answer).to eq 42
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should convert with symbols' do
|
47
|
+
klass = Class.new HiddenHippo::Packets::Packet do
|
48
|
+
field :answer, tshark: 'magic.number', conv: :to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
instance = klass.parse 'magic.number' => '42'
|
52
|
+
|
53
|
+
expect(instance.answer).to eq 42
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should ignore unknow fields' do
|
57
|
+
klass = Class.new HiddenHippo::Packets::Packet
|
58
|
+
|
59
|
+
expect{klass.parse 'not.there' => 'foobar'}.not_to raise_error
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#filter' do
|
64
|
+
it 'should return the filter set' do
|
65
|
+
klass = Class.new HiddenHippo::Packets::Packet do
|
66
|
+
filter 'foobarbaz'
|
67
|
+
end
|
68
|
+
|
69
|
+
expect(klass.filter).to eq 'foobarbaz'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#tshark_fields' do
|
74
|
+
it 'should return the tshark fields for all the fields' do
|
75
|
+
klass = Class.new HiddenHippo::Packets::Packet do
|
76
|
+
field :thing, tshark: 'find.me'
|
77
|
+
end
|
78
|
+
|
79
|
+
expect(klass.tshark_fields).to include 'find.me'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should have default mac address fields' do
|
83
|
+
klass = Class.new HiddenHippo::Packets::Packet
|
84
|
+
|
85
|
+
expect(klass.tshark_fields).to include 'eth.src', 'eth.dst', 'wlan.sa', 'wlan.da'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'hidden_hippo'
|
2
|
+
require 'hidden_hippo/possibilities'
|
3
|
+
|
4
|
+
describe HiddenHippo::Possibilities do
|
5
|
+
let(:possibilities) {HiddenHippo::Possibilities.new}
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
it 'should set the base counts' do
|
9
|
+
possibilities = HiddenHippo::Possibilities.new 'foo' => 3
|
10
|
+
|
11
|
+
expect(possibilities['foo']).to eq 3
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should ignore base counts that are not strings' do
|
15
|
+
possibilities = HiddenHippo::Possibilities.new 'foo' => 'potato'
|
16
|
+
|
17
|
+
expect(possibilities['foo']).to eq 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#<<' do
|
22
|
+
it 'should add a possible value' do
|
23
|
+
possibilities << 'foo'
|
24
|
+
possibilities << 'biz'
|
25
|
+
possibilities << 'baz'
|
26
|
+
|
27
|
+
expect(possibilities).to contain_exactly 'foo', 'biz', 'baz'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should increment the support count of an existing value' do
|
31
|
+
possibilities << 'foo'
|
32
|
+
possibilities << 'foo'
|
33
|
+
|
34
|
+
expect(possibilities['foo']).to eq 2
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should convert values to string' do
|
38
|
+
possibilities << 42
|
39
|
+
|
40
|
+
expect(possibilities).to contain_exactly '42'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should replace dots with underscores' do
|
44
|
+
possibilities << 'dat.thing'
|
45
|
+
|
46
|
+
expect(possibilities['dat.thing']).to eq 0
|
47
|
+
expect(possibilities['dat_thing']).to eq 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should replace dollar signs with underscores' do
|
51
|
+
possibilities << 'dat$thing'
|
52
|
+
|
53
|
+
expect(possibilities['dat$thing']).to eq 0
|
54
|
+
expect(possibilities['dat_thing']).to eq 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#[]' do
|
59
|
+
it 'should return the support count' do
|
60
|
+
5.times do
|
61
|
+
possibilities << 'foo'
|
62
|
+
end
|
63
|
+
|
64
|
+
expect(possibilities['foo']).to eq 5
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should return 0 when no support count' do
|
68
|
+
expect(possibilities['not there']).to eq 0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#each' do
|
73
|
+
it 'should enumerate by support count' do
|
74
|
+
possibilities << 'fi'
|
75
|
+
possibilities << 'fo'
|
76
|
+
possibilities << 'fo'
|
77
|
+
possibilities << 'fum'
|
78
|
+
possibilities << 'fum'
|
79
|
+
possibilities << 'fum'
|
80
|
+
|
81
|
+
expect{|b| possibilities.each &b}.to yield_successive_args 'fum', 'fo', 'fi'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should return an enumerator without a block' do
|
85
|
+
possibilities << 'fi'
|
86
|
+
possibilities << 'fo'
|
87
|
+
possibilities << 'fum'
|
88
|
+
|
89
|
+
expect(possibilities.each).to be_kind_of Enumerator
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#each_with_support' do
|
94
|
+
it 'should enumerate by and with support count' do
|
95
|
+
possibilities << 'fi'
|
96
|
+
possibilities << 'fo'
|
97
|
+
possibilities << 'fo'
|
98
|
+
possibilities << 'fum'
|
99
|
+
possibilities << 'fum'
|
100
|
+
possibilities << 'fum'
|
101
|
+
|
102
|
+
expect{|b| possibilities.each_with_support &b}.to yield_successive_args ['fum', 3], ['fo', 2], ['fi', 1]
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should return an enumerator without a block' do
|
106
|
+
possibilities << 'fi'
|
107
|
+
possibilities << 'fo'
|
108
|
+
possibilities << 'fum'
|
109
|
+
|
110
|
+
expect(possibilities.each_with_support).to be_kind_of Enumerator
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
require 'hidden_hippo'
|
3
|
+
require 'shoulda-matchers'
|
4
|
+
require 'rspec/retry'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include Shoulda::Matchers::ActiveModel
|
8
|
+
|
9
|
+
stdout = $stdout
|
10
|
+
stderr = $stderr
|
11
|
+
|
12
|
+
config.before :each, noisy: true do
|
13
|
+
$stdout = StringIO.new
|
14
|
+
$stderr = StringIO.new
|
15
|
+
end
|
16
|
+
|
17
|
+
config.after :each, noisy: true do
|
18
|
+
$stdout = stdout
|
19
|
+
$stderr = stderr
|
20
|
+
end
|
21
|
+
|
22
|
+
config.before :all, db: true do
|
23
|
+
HiddenHippo.configure_db! :test
|
24
|
+
end
|
25
|
+
|
26
|
+
config.expect_with :rspec do |expectations|
|
27
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
28
|
+
end
|
29
|
+
|
30
|
+
config.mock_with :rspec do |mocks|
|
31
|
+
mocks.verify_partial_doubles = true
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'hidden_hippo'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
# Shared examples for the daemon controller commands
|
6
|
+
# it expects to have `name` defined. For example:
|
7
|
+
#
|
8
|
+
# describe 'hh thing' do
|
9
|
+
# let(:name) {'thing'}
|
10
|
+
# it_behaves_like 'cli daemon controller'
|
11
|
+
# end
|
12
|
+
shared_examples 'cli daemon controller' do
|
13
|
+
let(:home) { Pathname.new(Dir.mktmpdir) }
|
14
|
+
let(:pid_file) { home + 'pid' + "#{name}.pid" }
|
15
|
+
let(:log_file) { home + 'log' + "#{name}.log" }
|
16
|
+
|
17
|
+
def start
|
18
|
+
HiddenHippo::Cli::App.start [name, 'start']
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
HiddenHippo::Cli::App.start [name, 'stop']
|
23
|
+
end
|
24
|
+
|
25
|
+
def status
|
26
|
+
HiddenHippo::Cli::App.start [name, 'status']
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
ENV['HIDDEN_HIPPO_HOME'] = home.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
if pid_file.exist?
|
35
|
+
begin
|
36
|
+
pid = pid_file.read.to_i
|
37
|
+
Process.detach pid # keep the zombies at bay
|
38
|
+
Process.kill 9, pid
|
39
|
+
rescue
|
40
|
+
# do nothing
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
home.rmtree
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'start' do
|
48
|
+
it 'should start the daemon' do
|
49
|
+
start
|
50
|
+
pid = pid_file.read.to_i
|
51
|
+
|
52
|
+
expect(HiddenHippo.pid_exists? pid).to be_truthy
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should create a pid file' do
|
56
|
+
start
|
57
|
+
|
58
|
+
expect(pid_file).to exist
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should log to file', retry: 3 do
|
62
|
+
start
|
63
|
+
sleep 0.5
|
64
|
+
|
65
|
+
expect(log_file).to exist
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'replace stale pid file' do
|
69
|
+
pid_file.dirname.mkpath
|
70
|
+
File.write pid_file, '12345'
|
71
|
+
|
72
|
+
start
|
73
|
+
|
74
|
+
expect(pid_file.read.to_i).not_to eq 12345
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should complain if daemon is already running' do
|
78
|
+
start
|
79
|
+
|
80
|
+
expect{start}.to raise_error SystemExit do |error|
|
81
|
+
expect(error.status).not_to eq 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'stop' do
|
87
|
+
it 'should kill the process', retry: 3 do
|
88
|
+
start
|
89
|
+
pid = pid_file.read.to_i
|
90
|
+
Process.detach pid # make sure we don't get a zombie
|
91
|
+
|
92
|
+
stop
|
93
|
+
sleep 0.5
|
94
|
+
|
95
|
+
expect(HiddenHippo.pid_exists? pid).to be_falsey
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should delete the pid file' do
|
99
|
+
start
|
100
|
+
stop
|
101
|
+
|
102
|
+
expect(pid_file).not_to exist
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should complain if the pid file is missing' do
|
106
|
+
expect{stop}.to raise_error SystemExit do |error|
|
107
|
+
expect(error.status).not_to eq 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'status' do
|
113
|
+
it 'should return 0 if running' do
|
114
|
+
start
|
115
|
+
|
116
|
+
expect{status}.to raise_error SystemExit do |error|
|
117
|
+
expect(error.status).to eq 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should return 1 if not running' do
|
122
|
+
expect{status}.to raise_error SystemExit do |error|
|
123
|
+
expect(error.status).to eq 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should return 2 if not running but pid file is present' do
|
128
|
+
pid_file.dirname.mkpath
|
129
|
+
File.write pid_file, '99999'
|
130
|
+
|
131
|
+
expect{status}.to raise_error SystemExit do |error|
|
132
|
+
expect(error.status).to eq 2
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'hidden_hippo/dossier'
|
2
|
+
require 'hidden_hippo/update'
|
3
|
+
require 'hidden_hippo/updator'
|
4
|
+
|
5
|
+
describe HiddenHippo::Updator, :db do
|
6
|
+
let(:queue) {Queue.new}
|
7
|
+
let(:updator) {HiddenHippo::Updator.new queue}
|
8
|
+
|
9
|
+
before do
|
10
|
+
HiddenHippo::Dossier.delete_all
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
updator.stop
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add the fields to the database from the queue' do
|
18
|
+
HiddenHippo::Dossier.create mac_address: 'find me'
|
19
|
+
queue << HiddenHippo::Update.new('find me', {name: 'John Doe'})
|
20
|
+
|
21
|
+
updator.start
|
22
|
+
sleep 0.5
|
23
|
+
|
24
|
+
dossier = HiddenHippo::Dossier.find 'find me'
|
25
|
+
expect(dossier.name['John Doe']).to eq 1
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create the dossier if it is missing' do
|
29
|
+
queue << HiddenHippo::Update.new('not there', {hostname: 'Bobby-PC'})
|
30
|
+
|
31
|
+
updator.start
|
32
|
+
sleep 0.5
|
33
|
+
|
34
|
+
dossier = HiddenHippo::Dossier.find 'not there'
|
35
|
+
expect(dossier.hostname['Bobby-PC']).to eq 1
|
36
|
+
end
|
37
|
+
end
|