ghost 0.3.0 → 1.0.0.pre
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/LICENSE +1 -1
- data/bin/ghost +2 -130
- data/lib/ghost.rb +3 -16
- data/lib/ghost/cli.rb +60 -0
- data/lib/ghost/cli/task.rb +71 -0
- data/lib/ghost/cli/task/add.rb +25 -0
- data/lib/ghost/cli/task/delete.rb +30 -0
- data/lib/ghost/cli/task/empty.rb +18 -0
- data/lib/ghost/cli/task/export.rb +19 -0
- data/lib/ghost/cli/task/help.rb +41 -0
- data/lib/ghost/cli/task/import.rb +25 -0
- data/lib/ghost/cli/task/list.rb +40 -0
- data/lib/ghost/host.rb +34 -0
- data/lib/ghost/store.rb +12 -0
- data/lib/ghost/store/dscl_store.rb +71 -0
- data/lib/ghost/store/hosts_file_store.rb +123 -0
- data/lib/ghost/tokenized_file.rb +65 -0
- data/lib/ghost/version.rb +3 -0
- data/spec/ghost/cli/task/add_spec.rb +80 -0
- data/spec/ghost/cli/task/delete_spec.rb +20 -0
- data/spec/ghost/cli/task/empty_spec.rb +19 -0
- data/spec/ghost/cli/task/export_spec.rb +16 -0
- data/spec/ghost/cli/task/help_spec.rb +36 -0
- data/spec/ghost/cli/task/import_spec.rb +56 -0
- data/spec/ghost/cli/task/list_spec.rb +50 -0
- data/spec/ghost/cli_spec.rb +22 -0
- data/spec/ghost/host_spec.rb +36 -0
- data/spec/ghost/store/dscl_store_spec.rb +153 -0
- data/spec/ghost/store/hosts_file_store_spec.rb +316 -0
- data/spec/ghost/store_spec.rb +2 -0
- data/spec/ghost/tokenized_file_spec.rb +131 -0
- data/spec/spec_helper.rb +4 -2
- data/spec/support/cli.rb +29 -0
- data/spec/support/resolv.rb +15 -0
- metadata +91 -27
- data/Rakefile +0 -28
- data/TODO +0 -0
- data/bin/ghost-ssh +0 -132
- data/lib/ghost/linux-host.rb +0 -158
- data/lib/ghost/mac-host.rb +0 -116
- data/lib/ghost/ssh_config.rb +0 -110
- data/spec/etc_hosts_spec.rb +0 -190
- data/spec/ghost_spec.rb +0 -151
- data/spec/spec.opts +0 -1
- data/spec/ssh_config_spec.rb +0 -80
- data/spec/ssh_config_template +0 -11
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
describe Ghost::Cli, :type => :cli do
|
5
|
+
describe "empty" do
|
6
|
+
before do
|
7
|
+
store.add(Ghost::Host.new("xyz", "127.0.0.1"))
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'empties the list of hosts' do
|
11
|
+
ghost("empty")
|
12
|
+
store.all.should be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'outputs a summary of the operation' do
|
16
|
+
ghost("empty").should == "[Emptying] Done.\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
describe Ghost::Cli, :type => :cli do
|
5
|
+
describe "export" do
|
6
|
+
it "outputs all hosts one-per-line in hosts file format" do
|
7
|
+
store.add Ghost::Host.new("gist.github.com", "10.0.0.1")
|
8
|
+
store.add Ghost::Host.new("google.com", "192.168.1.10")
|
9
|
+
|
10
|
+
ghost("export").should == <<-EOE.unindent
|
11
|
+
10.0.0.1 gist.github.com
|
12
|
+
192.168.1.10 google.com
|
13
|
+
EOE
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
describe Ghost::Cli, :type => :cli do
|
5
|
+
describe "help" do
|
6
|
+
let(:overview) do
|
7
|
+
<<-EOF.unindent
|
8
|
+
USAGE: ghost <task> [<args>]
|
9
|
+
|
10
|
+
The ghost tasks are:
|
11
|
+
add Add a host
|
12
|
+
delete Remove a ghost-managed host
|
13
|
+
empty Clear all ghost-managed hosts
|
14
|
+
export Export all hosts in /etc/hosts format
|
15
|
+
import Import hosts in /etc/hosts format
|
16
|
+
list Show all (or a filtered) list of hosts
|
17
|
+
|
18
|
+
See 'ghost help <task>' for more information on a specific task.
|
19
|
+
EOF
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'displays help overview when called with no args' do
|
23
|
+
ghost("").should == overview
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'displays help overview when help task is called with no arguments' do
|
27
|
+
ghost("help").should == overview
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when no help text for a given topic is available" do
|
31
|
+
it "prints out a message" do
|
32
|
+
ghost("help missing").should == "No help for task 'missing'\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
describe Ghost::Cli, :type => :cli do
|
5
|
+
describe "import" do
|
6
|
+
context "with current export format" do
|
7
|
+
let(:import) do
|
8
|
+
<<-EOI.unindent
|
9
|
+
1.2.3.4 foo.com
|
10
|
+
2.3.4.5 bar.com
|
11
|
+
EOI
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:foo_com) { Ghost::Host.new('foo.com', '1.2.3.4') }
|
15
|
+
let(:bar_com) { Ghost::Host.new('bar.com', '2.3.4.5') }
|
16
|
+
|
17
|
+
context 'with no file name'
|
18
|
+
context 'with STDIN pseudo file name (-)'
|
19
|
+
|
20
|
+
context 'with a file name' do
|
21
|
+
it 'adds each entry' do
|
22
|
+
file = Tempfile.new('import')
|
23
|
+
file.write(import)
|
24
|
+
file.close
|
25
|
+
|
26
|
+
ghost("import #{file.path}")
|
27
|
+
|
28
|
+
store.all.should include(foo_com)
|
29
|
+
store.all.should include(bar_com)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with multiple file names'
|
34
|
+
|
35
|
+
context 'when an entry is already present' do
|
36
|
+
context 'without the -f flag' do
|
37
|
+
it 'skips the existing entries'
|
38
|
+
it 'prints a warning about skipped entries'
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with the -f flag' do
|
42
|
+
it 'overwrites the existing entries'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with multiple hosts per line' do
|
47
|
+
let(:import) do
|
48
|
+
<<-EOI.unindent
|
49
|
+
1.2.3.4 foo.com
|
50
|
+
2.3.4.5 bar.com subdomain.bar.com
|
51
|
+
EOI
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
describe Ghost::Cli, :type => :cli do
|
5
|
+
describe "list" do
|
6
|
+
before do
|
7
|
+
store.add Ghost::Host.new("gist.github.com", "10.0.0.1")
|
8
|
+
store.add Ghost::Host.new("google.com", "192.168.1.10")
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with no filtering parameter" do
|
12
|
+
it "outputs all hostnames" do
|
13
|
+
ghost("list").should == <<-EOF.unindent
|
14
|
+
Listing 2 host(s):
|
15
|
+
gist.github.com -> 10.0.0.1
|
16
|
+
google.com -> 192.168.1.10
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a filtering parameter" do
|
22
|
+
before do
|
23
|
+
store.empty
|
24
|
+
store.add Ghost::Host.new("google.com", "10.0.0.1")
|
25
|
+
store.add Ghost::Host.new("google.co.uk", "192.168.1.10")
|
26
|
+
store.add Ghost::Host.new("gmail.com")
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'that is a regex' do
|
30
|
+
it "outputs entries whose hostname or IP match the filter" do
|
31
|
+
ghost("list /\.com$/").should == <<-EOF.unindent
|
32
|
+
Listing 2 host(s):
|
33
|
+
google.com -> 10.0.0.1
|
34
|
+
gmail.com -> 127.0.0.1
|
35
|
+
EOF
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'that is a string' do
|
40
|
+
it "outputs entries whose hostname or IP match the filter" do
|
41
|
+
ghost("list google").should == <<-EOF.unindent
|
42
|
+
Listing 2 host(s):
|
43
|
+
google.com -> 10.0.0.1
|
44
|
+
google.co.uk -> 192.168.1.10
|
45
|
+
EOF
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper.rb")
|
2
|
+
require 'ghost/cli'
|
3
|
+
|
4
|
+
# TODO: test exit statuses
|
5
|
+
describe Ghost::Cli, :type => :cli do
|
6
|
+
context 'writable operations with out proper permissions' do
|
7
|
+
it 'outputs a message telling user to escalate permissions' do
|
8
|
+
store.stub(:add).and_raise(Errno::EACCES)
|
9
|
+
|
10
|
+
ghost("add domain.com").should == "Insufficient privileges. Try using `sudo` or running as root.\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "environment configuration" # via GHOST_OPTS (see OptionParser#environment)
|
15
|
+
|
16
|
+
describe "--version" do
|
17
|
+
it "outputs the gem name and version" do
|
18
|
+
ghost("--version").should == "ghost #{Ghost::VERSION}\n"
|
19
|
+
ghost("-v").should == "ghost #{Ghost::VERSION}\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper.rb")
|
2
|
+
require 'ghost/host'
|
3
|
+
|
4
|
+
describe Ghost::Host do
|
5
|
+
describe 'attributes' do
|
6
|
+
subject { Ghost::Host.new('google.com', '74.125.225.102') }
|
7
|
+
|
8
|
+
its(:name) { should == 'google.com' }
|
9
|
+
its(:to_s) { should == 'google.com' }
|
10
|
+
its(:host) { should == 'google.com' }
|
11
|
+
its(:hostname) { should == 'google.com' }
|
12
|
+
its(:ip) { should == '74.125.225.102'}
|
13
|
+
its(:ip_address) { should == '74.125.225.102'}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'has a default IP of 127.0.0.1' do
|
17
|
+
Ghost::Host.new('xyz.com').ip.should == '127.0.0.1'
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'equality' do
|
21
|
+
it 'is equal to a host with the same hostname and IP' do
|
22
|
+
Ghost::Host.new('google.com', '123.123.123.123').should ==
|
23
|
+
Ghost::Host.new('google.com', '123.123.123.123')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'is not equal to a host with a different host name' do
|
27
|
+
Ghost::Host.new('google.com', '123.123.123.123').should_not ==
|
28
|
+
Ghost::Host.new('gmail.com', '123.123.123.123')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'is not equal to a host with a different IP' do
|
32
|
+
Ghost::Host.new('google.com', '123.123.123.123').should_not ==
|
33
|
+
Ghost::Host.new('google.com', '222.222.222.222')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper.rb")
|
2
|
+
require 'ghost/store/dscl_store'
|
3
|
+
|
4
|
+
# TODO: Raise exception error when `dscl` doesn't have sufficient privileges
|
5
|
+
describe Ghost::Store::DsclStore do
|
6
|
+
let(:store) { Ghost::Store::DsclStore.new }
|
7
|
+
let(:cmd) { Ghost::Store::DsclStore::Dscl }
|
8
|
+
|
9
|
+
before do
|
10
|
+
cmd.stub(:list => [])
|
11
|
+
cmd.stub(:read => nil)
|
12
|
+
cmd.stub(:create => true)
|
13
|
+
cmd.stub(:delete => true)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:dscl_foo_com) do
|
17
|
+
<<-EOF.unindent
|
18
|
+
AppleMetaNodeLocation: /Local/Default
|
19
|
+
GeneratedUID: 7FE20A09-21B5-42C5-9E8C-E64999BD20E2
|
20
|
+
IPAddress: 123.123.123.123
|
21
|
+
RecordName: foo.com
|
22
|
+
RecordType: dsRecTypeStandard:Hosts
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:dscl_bar_com) do
|
27
|
+
<<-EOF.unindent
|
28
|
+
AppleMetaNodeLocation: /Local/Default
|
29
|
+
GeneratedUID: 15286594-C5F1-4508-BAB0-98B96D424657
|
30
|
+
IPAddress: 127.0.0.1
|
31
|
+
RecordName: bar.com
|
32
|
+
RecordType: dsRecTypeStandard:Hosts
|
33
|
+
EOF
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#all" do
|
37
|
+
it 'returns an empty array when no hosts are in the store' do
|
38
|
+
store.all.should == []
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns an array of Ghost::Host entries for each host in the store' do
|
42
|
+
cmd.stub(:list).and_return([dscl_foo_com, dscl_bar_com])
|
43
|
+
store.all.should == [
|
44
|
+
Ghost::Host.new('foo.com', '123.123.123.123'),
|
45
|
+
Ghost::Host.new('bar.com', '127.0.0.1')
|
46
|
+
]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#find" do
|
51
|
+
it 'finds hosts matching a regex' do
|
52
|
+
cmd.stub(:list).and_return([dscl_foo_com, dscl_bar_com])
|
53
|
+
store.find(/.*/).should == store.all
|
54
|
+
store.find(/f/).should == [Ghost::Host.new('foo.com', '123.123.123.123')]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#add" do
|
59
|
+
let(:host) { Ghost::Host.new('foo.com', '123.123.123.123') }
|
60
|
+
|
61
|
+
it 'returns true' do
|
62
|
+
store.add(host).should be_true
|
63
|
+
end
|
64
|
+
|
65
|
+
# In order to make this run off OS X and without root, have to use an
|
66
|
+
# expectation... I think?
|
67
|
+
it 'adds the host' do
|
68
|
+
cmd.should_receive(:create).with('localhost', 'foo.com', '123.123.123.123')
|
69
|
+
store.add(host)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#delete" do
|
74
|
+
before do
|
75
|
+
store.stub(:all).and_return [
|
76
|
+
Ghost::Host.new('foo.com', '127.0.0.1'),
|
77
|
+
Ghost::Host.new('fo.com', '127.0.0.1'),
|
78
|
+
Ghost::Host.new('fooo.com', '127.0.0.2')
|
79
|
+
]
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'using a Ghost::Host to identify host' do
|
83
|
+
context 'and the IP does not match an entry' do
|
84
|
+
let(:host) { Ghost::Host.new("foo.com", "127.0.0.2") }
|
85
|
+
|
86
|
+
it 'returns empty array' do
|
87
|
+
store.delete(host).should == []
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'has no effect' do
|
91
|
+
store.delete(host)
|
92
|
+
cmd.should_not_receive(:delete)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'and the IP matches an entry' do
|
97
|
+
let(:host) { Ghost::Host.new("foo.com", "127.0.0.1") }
|
98
|
+
|
99
|
+
it 'returns array of deleted hosts' do
|
100
|
+
store.delete(host).should == [host]
|
101
|
+
end
|
102
|
+
|
103
|
+
# In order to make this run off OS X and without root, have to use an
|
104
|
+
# expectation... I think?
|
105
|
+
it 'deletes the host' do
|
106
|
+
cmd.should_receive(:delete).with('localhost', 'foo.com')
|
107
|
+
store.delete(host)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'using a regex to identify hosts' do
|
113
|
+
let(:host) { /fo*\.com/ }
|
114
|
+
|
115
|
+
it 'returns array of removed hosts' do
|
116
|
+
store.delete(host).should == [
|
117
|
+
Ghost::Host.new('fo.com', '127.0.0.1'),
|
118
|
+
Ghost::Host.new('foo.com', '127.0.0.1'),
|
119
|
+
Ghost::Host.new('fooo.com', '127.0.0.2')
|
120
|
+
]
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'deletes the hosts' do
|
124
|
+
cmd.should_receive(:delete).with('localhost', 'fo.com')
|
125
|
+
cmd.should_receive(:delete).with('localhost', 'foo.com')
|
126
|
+
cmd.should_receive(:delete).with('localhost', 'fooo.com')
|
127
|
+
store.delete(host)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'using a string to identify host' do
|
132
|
+
let(:host) { "foo.com" }
|
133
|
+
|
134
|
+
it 'returns array of removed hosts' do
|
135
|
+
store.delete(host).should == [Ghost::Host.new('foo.com', '127.0.0.1')]
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'removes the host from the file' do
|
139
|
+
cmd.should_receive(:delete).with('localhost', 'foo.com')
|
140
|
+
store.delete(host)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#empty" do
|
146
|
+
it 'deletes all the entries' do
|
147
|
+
store.stub(:all => [Ghost::Host.new('foo'), Ghost::Host.new('bar')])
|
148
|
+
cmd.should_receive(:delete).with('localhost', 'foo')
|
149
|
+
cmd.should_receive(:delete).with('localhost', 'bar')
|
150
|
+
store.empty
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
|
2
|
+
require 'ghost/store/hosts_file_store'
|
3
|
+
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
describe Ghost::Store::HostsFileStore do
|
7
|
+
def write(content)
|
8
|
+
File.open(file_path, 'w') { |f| f.write(content) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def read
|
12
|
+
File.read(file_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def no_write
|
16
|
+
File.any_instance.stub(:reopen).with(anything, /[aw]/).and_raise("no writing!")
|
17
|
+
File.any_instance.stub(:puts).and_raise("no writing!")
|
18
|
+
File.any_instance.stub(:print).and_raise("no writing!")
|
19
|
+
File.any_instance.stub(:write).and_raise("no writing!")
|
20
|
+
File.any_instance.stub(:<<).and_raise("no writing!")
|
21
|
+
File.any_instance.stub(:flush).and_raise("no writing!")
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { store }
|
25
|
+
|
26
|
+
let(:file_path) { File.join(Dir.tmpdir, "etc_hosts.#{Process.pid}.#{rand(9999)}") }
|
27
|
+
let(:store) { described_class.new(file_path) }
|
28
|
+
let(:contents) do
|
29
|
+
<<-EOF.unindent
|
30
|
+
127.0.0.1 localhost localhost.localdomain
|
31
|
+
EOF
|
32
|
+
end
|
33
|
+
|
34
|
+
before { write(contents) }
|
35
|
+
|
36
|
+
it 'manages the default file of /etc/hosts when no file path is provided' do
|
37
|
+
described_class.new.path.should == "/etc/hosts"
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'manages the file at the provided path when given' do
|
41
|
+
described_class.new('xyz').path.should == 'xyz'
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#all" do
|
45
|
+
context 'with no ghost-managed hosts in the file' do
|
46
|
+
it 'returns no hosts' do
|
47
|
+
store.all.should == []
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with some ghost-managed hosts in the file' do
|
52
|
+
let(:contents) do
|
53
|
+
<<-EOF.gsub(/^\s+/,'')
|
54
|
+
127.0.0.1 localhost localhost.localdomain
|
55
|
+
# ghost start
|
56
|
+
1.2.3.4 bjeanes.com
|
57
|
+
2.3.4.5 my-app.com subdomain.my-app.com
|
58
|
+
# ghost end
|
59
|
+
EOF
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns an array with one Ghost::Host per ghost-managed host in the hosts file' do
|
63
|
+
store.all.should == [
|
64
|
+
Ghost::Host.new('bjeanes.com', '1.2.3.4'),
|
65
|
+
Ghost::Host.new('my-app.com', '2.3.4.5'),
|
66
|
+
Ghost::Host.new('subdomain.my-app.com', '2.3.4.5')
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "shouldn't write to the file" do
|
71
|
+
no_write
|
72
|
+
store.all
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#find" do
|
78
|
+
let(:contents) do
|
79
|
+
<<-EOF.gsub(/^\s+/,'')
|
80
|
+
# ghost start
|
81
|
+
1.2.3.4 bjeanes.com
|
82
|
+
2.3.4.5 my-app.com subdomain.my-app.com
|
83
|
+
# ghost end
|
84
|
+
EOF
|
85
|
+
end
|
86
|
+
|
87
|
+
it "finds hosts matching a regex" do
|
88
|
+
store.find(/.*/).should == store.all
|
89
|
+
store.find(/my-app\.com$/i).should == [
|
90
|
+
Ghost::Host.new('my-app.com', '2.3.4.5'),
|
91
|
+
Ghost::Host.new('subdomain.my-app.com', '2.3.4.5')
|
92
|
+
]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#add" do
|
97
|
+
let(:host) { Ghost::Host.new("google.com", "127.0.0.1") }
|
98
|
+
|
99
|
+
context 'with no ghost-managed hosts in the file' do
|
100
|
+
it 'returns true' do
|
101
|
+
store.add(host).should be_true
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'adds the new host between delimeters' do
|
105
|
+
store.add(host)
|
106
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
107
|
+
127.0.0.1 localhost localhost.localdomain
|
108
|
+
# ghost start
|
109
|
+
127.0.0.1 google.com
|
110
|
+
# ghost end
|
111
|
+
EOF
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with existing ghost-managed hosts in the file' do
|
116
|
+
let(:contents) do
|
117
|
+
<<-EOF.gsub(/^\s+/,'')
|
118
|
+
127.0.0.1 localhost localhost.localdomain
|
119
|
+
# ghost start
|
120
|
+
192.168.1.1 github.com
|
121
|
+
# ghost end
|
122
|
+
EOF
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'when adding to an existing IP' do
|
126
|
+
before { host.ip = '192.168.1.1' }
|
127
|
+
|
128
|
+
it 'adds to existing entry between tokens, listing host names in alphabetical order' do
|
129
|
+
store.add(host)
|
130
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
131
|
+
127.0.0.1 localhost localhost.localdomain
|
132
|
+
# ghost start
|
133
|
+
192.168.1.1 github.com google.com
|
134
|
+
# ghost end
|
135
|
+
EOF
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'returns true' do
|
139
|
+
store.add(host).should be_true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'when adding a new IP' do
|
144
|
+
it 'adds new entry between tokens, in numerical order' do
|
145
|
+
store.add(host)
|
146
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
147
|
+
127.0.0.1 localhost localhost.localdomain
|
148
|
+
# ghost start
|
149
|
+
127.0.0.1 google.com
|
150
|
+
192.168.1.1 github.com
|
151
|
+
# ghost end
|
152
|
+
EOF
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'returns true' do
|
156
|
+
store.add(host).should be_true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#delete" do
|
163
|
+
context 'with no ghost-managed hosts in the file' do
|
164
|
+
let(:host) { Ghost::Host.new("localhost", "127.0.0.1") }
|
165
|
+
|
166
|
+
it 'returns empty array' do
|
167
|
+
store.delete(host).should == []
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'has no effect' do
|
171
|
+
store.delete(host)
|
172
|
+
read.should == contents
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'with existing ghost-managed hosts in the file' do
|
177
|
+
let(:contents) do
|
178
|
+
<<-EOF.gsub(/^\s+/,'')
|
179
|
+
127.0.0.1 localhost localhost.localdomain
|
180
|
+
# ghost start
|
181
|
+
127.0.0.1 google.com
|
182
|
+
127.0.0.2 gooogle.com
|
183
|
+
192.168.1.1 github.com
|
184
|
+
# ghost end
|
185
|
+
EOF
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'when deleting one of the ghost entries' do
|
189
|
+
context 'using a Ghost::Host to identify host' do
|
190
|
+
context 'and the IP does not match an entry' do
|
191
|
+
let(:host) { Ghost::Host.new("google.com", "127.0.0.2") }
|
192
|
+
|
193
|
+
it 'returns empty array' do
|
194
|
+
store.delete(host).should == []
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'has no effect' do
|
198
|
+
store.delete(host)
|
199
|
+
read.should == contents
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'and the IP matches an entry' do
|
204
|
+
let(:host) { Ghost::Host.new("google.com", "127.0.0.1") }
|
205
|
+
|
206
|
+
it 'returns array of removed hosts' do
|
207
|
+
store.delete(host).should == [Ghost::Host.new('google.com', '127.0.0.1')]
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'removes the host from the file' do
|
211
|
+
store.delete(host)
|
212
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
213
|
+
127.0.0.1 localhost localhost.localdomain
|
214
|
+
# ghost start
|
215
|
+
127.0.0.2 gooogle.com
|
216
|
+
192.168.1.1 github.com
|
217
|
+
# ghost end
|
218
|
+
EOF
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'using a regex to identify hosts' do
|
224
|
+
let(:host) { /go*gle\.com/ }
|
225
|
+
|
226
|
+
it 'returns array of removed hosts' do
|
227
|
+
store.delete(host).should == [
|
228
|
+
Ghost::Host.new('google.com', '127.0.0.1'),
|
229
|
+
Ghost::Host.new('gooogle.com', '127.0.0.2')
|
230
|
+
]
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'removes the host from the file' do
|
234
|
+
store.delete(host)
|
235
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
236
|
+
127.0.0.1 localhost localhost.localdomain
|
237
|
+
# ghost start
|
238
|
+
192.168.1.1 github.com
|
239
|
+
# ghost end
|
240
|
+
EOF
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'using a string to identify host' do
|
245
|
+
let(:host) { "google.com" }
|
246
|
+
|
247
|
+
it 'returns array of removed hosts' do
|
248
|
+
store.delete(host).should == [Ghost::Host.new('google.com', '127.0.0.1')]
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'removes the host from the file' do
|
252
|
+
store.delete(host)
|
253
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
254
|
+
127.0.0.1 localhost localhost.localdomain
|
255
|
+
# ghost start
|
256
|
+
127.0.0.2 gooogle.com
|
257
|
+
192.168.1.1 github.com
|
258
|
+
# ghost end
|
259
|
+
EOF
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when trying to delete a non-ghost entry' do
|
265
|
+
let(:host) { Ghost::Host.new("localhost") }
|
266
|
+
|
267
|
+
it 'returns false' do
|
268
|
+
store.delete(host).should == []
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'has no effect' do
|
272
|
+
store.delete(host)
|
273
|
+
read.should == contents
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe "#empty" do
|
280
|
+
context 'with no ghost-managed hosts in the file' do
|
281
|
+
it 'returns false' do
|
282
|
+
store.empty.should be_false
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'has no effect' do
|
286
|
+
store.empty
|
287
|
+
read.should == contents
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'with existing ghost-managed hosts in the file' do
|
292
|
+
let(:contents) do
|
293
|
+
<<-EOF.gsub(/^\s+/,'')
|
294
|
+
127.0.0.1 localhost localhost.localdomain
|
295
|
+
# ghost start
|
296
|
+
127.0.0.1 google.com
|
297
|
+
192.168.1.1 github.com
|
298
|
+
# ghost end
|
299
|
+
EOF
|
300
|
+
end
|
301
|
+
|
302
|
+
context 'when deleting one of the ghost entries' do
|
303
|
+
it 'returns true' do
|
304
|
+
store.empty.should be_true
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'removes the host from the file' do
|
308
|
+
store.empty
|
309
|
+
read.should == <<-EOF.gsub(/^\s+/,'')
|
310
|
+
127.0.0.1 localhost localhost.localdomain
|
311
|
+
EOF
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|