whois 4.0.6 → 6.0.3

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +12 -0
  3. data/.github/dependabot.yml +17 -0
  4. data/.github/workflows/release.yml +19 -0
  5. data/.github/workflows/tests.yml +29 -0
  6. data/.gitignore +11 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +27 -0
  9. data/.rubocop_opinionated.yml +115 -0
  10. data/.rubocop_todo.yml +89 -0
  11. data/.simplecov +6 -0
  12. data/.tool-versions +1 -0
  13. data/CHANGELOG.md +147 -44
  14. data/CONTRIBUTING.md +18 -6
  15. data/Gemfile +8 -0
  16. data/LICENSE.txt +1 -1
  17. data/README.md +4 -4
  18. data/Rakefile +28 -0
  19. data/SECURITY.md +24 -0
  20. data/bin/console +1 -0
  21. data/bin/whoisrb +6 -5
  22. data/data/ipv4.json +1 -3
  23. data/data/tld.json +125 -1049
  24. data/lib/whois/client.rb +5 -7
  25. data/lib/whois/errors.rb +4 -6
  26. data/lib/whois/record/part.rb +5 -6
  27. data/lib/whois/record.rb +5 -8
  28. data/lib/whois/server/adapters/afilias.rb +4 -5
  29. data/lib/whois/server/adapters/arin.rb +7 -8
  30. data/lib/whois/server/adapters/arpa.rb +19 -24
  31. data/lib/whois/server/adapters/base.rb +29 -46
  32. data/lib/whois/server/adapters/formatted.rb +4 -6
  33. data/lib/whois/server/adapters/none.rb +4 -6
  34. data/lib/whois/server/adapters/not_implemented.rb +4 -6
  35. data/lib/whois/server/adapters/standard.rb +4 -6
  36. data/lib/whois/server/adapters/verisign.rb +4 -5
  37. data/lib/whois/server/adapters/web.rb +4 -6
  38. data/lib/whois/server/socket_handler.rb +11 -12
  39. data/lib/whois/server.rb +73 -64
  40. data/lib/whois/version.rb +4 -2
  41. data/lib/whois.rb +32 -33
  42. data/spec/fixtures/referrals/afilias.bz.txt +23 -0
  43. data/spec/fixtures/referrals/arin_referral_apnic.txt +78 -0
  44. data/spec/fixtures/referrals/arin_referral_missing.txt +52 -0
  45. data/spec/fixtures/referrals/arin_referral_ripe.txt +50 -0
  46. data/spec/fixtures/referrals/arin_referral_rwhois.txt +63 -0
  47. data/spec/fixtures/referrals/arin_referral_servernap.txt +63 -0
  48. data/spec/fixtures/referrals/arin_referral_whois.txt +56 -0
  49. data/spec/fixtures/referrals/crsnic.com.txt +60 -0
  50. data/spec/fixtures/referrals/crsnic.com_referral.txt +56 -0
  51. data/spec/fixtures/referrals/crsnic.com_referral_missing.txt +50 -0
  52. data/spec/integration/whois_spec.rb +73 -0
  53. data/spec/spec_helper.rb +19 -0
  54. data/spec/support/helpers/connectivity_helper.rb +15 -0
  55. data/spec/support/helpers/spec_helper.rb +31 -0
  56. data/spec/whois/client_spec.rb +143 -0
  57. data/spec/whois/record/part_spec.rb +38 -0
  58. data/spec/whois/record_spec.rb +168 -0
  59. data/spec/whois/server/adapters/afilias_spec.rb +49 -0
  60. data/spec/whois/server/adapters/arin_spec.rb +83 -0
  61. data/spec/whois/server/adapters/arpa_spec.rb +29 -0
  62. data/spec/whois/server/adapters/base_spec.rb +155 -0
  63. data/spec/whois/server/adapters/formatted_spec.rb +53 -0
  64. data/spec/whois/server/adapters/none_spec.rb +23 -0
  65. data/spec/whois/server/adapters/not_implemented_spec.rb +24 -0
  66. data/spec/whois/server/adapters/standard_spec.rb +42 -0
  67. data/spec/whois/server/adapters/verisign_spec.rb +60 -0
  68. data/spec/whois/server/adapters/web_spec.rb +24 -0
  69. data/spec/whois/server/socket_handler_spec.rb +33 -0
  70. data/spec/whois/server_spec.rb +302 -0
  71. data/spec/whois/web_interface_error_spec.rb +23 -0
  72. data/spec/whois/whois_spec.rb +15 -0
  73. data/utils/compare-whois.rb +30 -0
  74. data/utils/deftld.rb +230 -0
  75. data/utils/defutils.rb +26 -0
  76. data/utils/fixupd.rb +60 -0
  77. data/utils/matrix.rb +68 -0
  78. data/utils/mkwhois.rb +31 -0
  79. data/whois.gemspec +19 -32
  80. metadata +58 -11
  81. data/4.0-Upgrade.md +0 -143
  82. data/bin/setup +0 -8
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Client do
6
+ describe "#initialize" do
7
+ it "accepts a zero parameters" do
8
+ expect { described_class.new }.not_to raise_error
9
+ end
10
+
11
+ it "accepts a settings parameter" do
12
+ expect { described_class.new({ foo: "bar" }) }.not_to raise_error
13
+ end
14
+
15
+
16
+ it "accepts a timeout setting with a value in seconds" do
17
+ client = described_class.new(timeout: 100)
18
+ expect(client.timeout).to eq(100)
19
+ end
20
+
21
+ it "accepts a timeout setting with a nil value" do
22
+ client = described_class.new(timeout: nil)
23
+ expect(client.timeout).to be_nil
24
+ end
25
+
26
+ it "accepts a block" do
27
+ described_class.new do |client|
28
+ expect(client).to be_instance_of(described_class)
29
+ end
30
+ end
31
+
32
+
33
+ it "defaults timeout setting to DEFAULT_TIMEOUT" do
34
+ client = described_class.new
35
+ expect(client.timeout).to eq(described_class::DEFAULT_TIMEOUT)
36
+ end
37
+
38
+ it "sets settings to given argument, except timeout" do
39
+ client = described_class.new(timeout: nil, foo: "bar")
40
+ expect(client.settings).to eq({ foo: "bar" })
41
+ end
42
+ end
43
+
44
+ describe "#lookup" do
45
+ it "converts the argument to string" do
46
+ query = ["example", ".", "test"]
47
+ query.instance_eval do
48
+ def to_s
49
+ join
50
+ end
51
+ end
52
+
53
+ server = Whois::Server::Adapters::Base.new(:tld, "test", "whois.test")
54
+ expect(server).to receive(:lookup).with("example.test")
55
+ expect(Whois::Server).to receive(:guess).with("example.test").and_return(server)
56
+
57
+ described_class.new.lookup(query)
58
+ end
59
+
60
+ it "converts the argument to downcase" do
61
+ server = Whois::Server::Adapters::Base.new(:tld, "test", "whois.test")
62
+ expect(server).to receive(:lookup).with("example.test")
63
+ expect(Whois::Server).to receive(:guess).with("example.test").and_return(server)
64
+
65
+ described_class.new.lookup("Example.TEST")
66
+ end
67
+
68
+ it "detects email" do
69
+ expect {
70
+ described_class.new.lookup("weppos@weppos.net")
71
+ }.to raise_error(Whois::ServerNotSupported)
72
+ end
73
+
74
+ it "works with domain with no whois" do
75
+ Whois::Server.define(:tld, "nowhois", nil, adapter: Whois::Server::Adapters::None)
76
+
77
+ expect {
78
+ described_class.new.lookup("domain.nowhois")
79
+ }.to raise_error(Whois::NoInterfaceError, /no whois server/)
80
+ end
81
+
82
+ it "works with domain with web whois" do
83
+ Whois::Server.define(:tld, "webwhois", nil, adapter: Whois::Server::Adapters::Web, url: "http://www.example.com/")
84
+
85
+ expect {
86
+ described_class.new.lookup("domain.webwhois")
87
+ }.to raise_error(Whois::WebInterfaceError, /www\.example\.com/)
88
+ end
89
+
90
+ it "raises if timeout is exceeded" do
91
+ adapter = Class.new(Whois::Server::Adapters::Base) do
92
+ def lookup(*)
93
+ sleep(2)
94
+ end
95
+ end
96
+ expect(Whois::Server).to receive(:guess).and_return(adapter.new(:tld, "test", "whois.test"))
97
+
98
+ client = described_class.new(timeout: 1)
99
+ expect {
100
+ client.lookup("example.test")
101
+ }.to raise_error(Timeout::Error)
102
+ end
103
+
104
+ it "does not raise if timeout is not exceeded" do
105
+ adapter = Class.new(Whois::Server::Adapters::Base) do
106
+ def lookup(*)
107
+ sleep(1)
108
+ end
109
+ end
110
+ expect(Whois::Server).to receive(:guess).and_return(adapter.new(:tld, "test", "whois.test"))
111
+
112
+ client = described_class.new(timeout: 5)
113
+ expect {
114
+ client.lookup("example.test")
115
+ }.not_to raise_error
116
+ end
117
+
118
+ it "supports unlimited timeout" do
119
+ adapter = Class.new(Whois::Server::Adapters::Base) do
120
+ def lookup(*)
121
+ sleep(1)
122
+ end
123
+ end
124
+ expect(Whois::Server).to receive(:guess).and_return(adapter.new(:tld, "test", "whois.test"))
125
+
126
+ client = described_class.new.tap { |c| c.timeout = nil }
127
+ expect {
128
+ client.lookup("example.test")
129
+ }.not_to raise_error
130
+ end
131
+ end
132
+
133
+ # FIXME: use RSpec metadata
134
+ need_connectivity do
135
+ describe "#query" do
136
+ it "sends a query for given domain" do
137
+ record = described_class.new.lookup("weppos.it")
138
+ expect(record.match?(/Domain:\s+weppos\.it/)).to be(true)
139
+ expect(record.match?(/Created:/)).to be(true)
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Record::Part do
6
+ describe "#initialize" do
7
+ it "accepts an empty value" do
8
+ expect {
9
+ instance = described_class.new
10
+ expect(instance.body).to be_nil
11
+ }.not_to raise_error
12
+ end
13
+
14
+ it "accepts an empty hash" do
15
+ expect {
16
+ instance = described_class.new({})
17
+ expect(instance.body).to be_nil
18
+ }.not_to raise_error
19
+ end
20
+
21
+ it "initializes a new instance from given hash" do
22
+ instance = described_class.new(body: "This is a WHOIS record.", host: "whois.example.test")
23
+
24
+ expect(instance.body).to eq("This is a WHOIS record.")
25
+ expect(instance.host).to eq("whois.example.test")
26
+ end
27
+
28
+ it "initializes a new instance from given block" do
29
+ instance = described_class.new do |c|
30
+ c.body = "This is a WHOIS record."
31
+ c.host = "whois.example.test"
32
+ end
33
+
34
+ expect(instance.body).to eq("This is a WHOIS record.")
35
+ expect(instance.host).to eq("whois.example.test")
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Record do
6
+ subject { described_class.new(server, parts) }
7
+
8
+ let(:server) {
9
+ Whois::Server.factory(:tld, ".foo", "whois.example.test")
10
+ }
11
+ let(:parts) {
12
+ [
13
+ Whois::Record::Part.new(body: "This is a record from foo.", host: "foo.example.test"),
14
+ Whois::Record::Part.new(body: "This is a record from bar.", host: "bar.example.test"),
15
+ ]
16
+ }
17
+ let(:content) {
18
+ parts.map(&:body).join("\n")
19
+ }
20
+
21
+
22
+ describe "#initialize" do
23
+ it "requires a server and parts" do
24
+ expect { described_class.new }.to raise_error(ArgumentError)
25
+ expect { described_class.new(server) }.to raise_error(ArgumentError)
26
+ expect { described_class.new(server, parts) }.not_to raise_error
27
+ end
28
+
29
+ it "sets server and parts from arguments" do
30
+ instance = described_class.new(server, parts)
31
+ expect(instance.server).to be(server)
32
+ expect(instance.parts).to be(parts)
33
+
34
+ instance = described_class.new(nil, nil)
35
+ expect(instance.server).to be_nil
36
+ expect(instance.parts).to be_nil
37
+ end
38
+ end
39
+
40
+
41
+ describe "#to_s" do
42
+ it "delegates to #content" do
43
+ expect(described_class.new(nil, [parts[0]]).to_s).to eq(parts[0].body)
44
+ expect(described_class.new(nil, parts).to_s).to eq(parts.map(&:body).join("\n"))
45
+ expect(described_class.new(nil, []).to_s).to eq("")
46
+ end
47
+ end
48
+
49
+ describe "#inspect" do
50
+ it "inspects the record content" do
51
+ expect(described_class.new(nil, [parts[0]]).inspect).to eq(parts[0].body.inspect)
52
+ end
53
+
54
+ it "joins multiple parts" do
55
+ expect(described_class.new(nil, parts).inspect).to eq(parts.map(&:body).join("\n").inspect)
56
+ end
57
+
58
+ it "joins empty parts" do
59
+ expect(described_class.new(nil, []).inspect).to eq("".inspect)
60
+ end
61
+ end
62
+
63
+ describe "#==" do
64
+ it "returns true when other is the same instance" do
65
+ one = two = described_class.new(server, parts)
66
+
67
+ expect(one == two).to be_truthy
68
+ expect(one).to eql(two)
69
+ end
70
+
71
+ it "returns true when other has same class and has the same parts" do
72
+ one = described_class.new(server, parts)
73
+ two = described_class.new(server, parts)
74
+
75
+ expect(one == two).to be_truthy
76
+ expect(one).to eql(two)
77
+ end
78
+
79
+ it "returns true when other has descendant class and has the same parts" do
80
+ subklass = Class.new(described_class)
81
+ one = described_class.new(server, parts)
82
+ two = subklass.new(server, parts)
83
+
84
+ expect(one == two).to be_truthy
85
+ expect(one).to eql(two)
86
+ end
87
+
88
+ it "returns true when other has same class and has equal parts" do
89
+ one = described_class.new(server, parts)
90
+ two = described_class.new(server, parts.dup)
91
+
92
+ expect(one == two).to be_truthy
93
+ expect(one).to eql(two)
94
+ end
95
+
96
+ it "returns true when other has same class, different server and the same parts" do
97
+ one = described_class.new(server, parts)
98
+ two = described_class.new(nil, parts)
99
+
100
+ expect(one == two).to be_truthy
101
+ expect(one).to eql(two)
102
+ end
103
+
104
+ it "returns false when other has different class and has the same parts" do
105
+ one = described_class.new(server, parts)
106
+ two = Struct.new(:server, :parts).new(server, parts)
107
+
108
+ expect(one == two).to be_falsey
109
+ expect(one).not_to eql(two)
110
+ end
111
+
112
+ it "returns false when other has different parts" do
113
+ one = described_class.new(server, parts)
114
+ two = described_class.new(server, [])
115
+
116
+ expect(one == two).to be_falsey
117
+ expect(one).not_to eql(two)
118
+ end
119
+
120
+ it "returns false when other is string and has the same content" do
121
+ one = described_class.new(server, parts)
122
+ two = described_class.new(server, parts).to_s
123
+
124
+ expect(one == two).to be_falsey
125
+ expect(one).not_to eql(two)
126
+ end
127
+
128
+ it "returns false when other is string and has different content" do
129
+ one = described_class.new(server, parts)
130
+ two = "different"
131
+
132
+ expect(one == two).to be_falsey
133
+ expect(one).not_to eql(two)
134
+ end
135
+ end
136
+
137
+
138
+ describe "#match" do
139
+ it "delegates to content" do
140
+ expect(subject.match(/record/)).to be_a(MatchData)
141
+ expect(subject.match(/record/)[0]).to eq("record")
142
+
143
+ expect(subject.match(/nomatch/)).to be_nil
144
+ end
145
+ end
146
+
147
+ describe "#match?" do
148
+ it "calls match and checks for match" do
149
+ expect(subject.match?(/record/)).to be(true)
150
+ expect(subject.match?(/nomatch/)).to be(false)
151
+ end
152
+ end
153
+
154
+
155
+ describe "#content" do
156
+ it "returns the part body" do
157
+ expect(described_class.new(nil, [parts[0]]).content).to eq(parts[0].body)
158
+ end
159
+
160
+ it "joins multiple parts" do
161
+ expect(described_class.new(nil, parts).content).to eq(parts.map(&:body).join("\n"))
162
+ end
163
+
164
+ it "returns an empty string when no parts" do
165
+ expect(described_class.new(nil, []).content).to eq("")
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Server::Adapters::Afilias do
6
+ let(:definition) { [:tld, ".test", "whois.afilias-grs.info", {}] }
7
+ let(:server) { described_class.new(*definition) }
8
+
9
+
10
+ describe "#lookup" do
11
+ context "without referral" do
12
+ it "returns the WHOIS record" do
13
+ response = "No match for example.test."
14
+ expected = response
15
+ expect(server.query_handler).to receive(:call).with("example.test", "whois.afilias-grs.info", 43).and_return(response)
16
+
17
+ record = server.lookup("example.test")
18
+ expect(record.to_s).to eq(expected)
19
+ expect(record.parts.size).to eq(1)
20
+ expect(record.parts).to eq([Whois::Record::Part.new(body: response, host: "whois.afilias-grs.info")])
21
+ end
22
+ end
23
+
24
+ context "with referral" do
25
+ it "follows all referrals" do
26
+ referral = File.read(fixture("referrals/afilias.bz.txt"))
27
+ response = "Match for example.test."
28
+ expected = "#{referral}\n#{response}"
29
+ expect(server.query_handler).to receive(:call).with("example.test", "whois.afilias-grs.info", 43).and_return(referral)
30
+ expect(server.query_handler).to receive(:call).with("example.test", "whois.belizenic.bz", 43).and_return(response)
31
+
32
+ record = server.lookup("example.test")
33
+ expect(record.to_s).to eq(expected)
34
+ expect(record.parts.size).to eq(2)
35
+ expect(record.parts).to eq([Whois::Record::Part.new(body: referral, host: "whois.afilias-grs.info"), Whois::Record::Part.new(body: response, host: "whois.belizenic.bz")])
36
+ end
37
+
38
+ it "ignores referral if options[:referral] is false" do
39
+ referral = File.read(fixture("referrals/afilias.bz.txt"))
40
+ server.options[:referral] = false
41
+ expect(server.query_handler).to receive(:call).with("example.test", "whois.afilias-grs.info", 43).and_return(referral)
42
+ expect(server.query_handler).not_to receive(:call).with("example.test", "whois.belizenic.bz", 43)
43
+
44
+ record = server.lookup("example.test")
45
+ expect(record.parts.size).to eq(1)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Server::Adapters::Arin do
6
+ let(:definition) { [:ipv4, "0.0.0.0/1", "whois.arin.net"] }
7
+ let(:server) { described_class.new(*definition) }
8
+
9
+ describe "#lookup" do
10
+ context "without referral" do
11
+ it "returns the WHOIS record" do
12
+ response = "Whois Response"
13
+ expected = response
14
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(response)
15
+ record = server.lookup("0.0.0.0")
16
+ expect(record.to_s).to eq(expected)
17
+ expect(record.parts.size).to eq(1)
18
+ expect(record.parts).to eq([Whois::Record::Part.new(body: response, host: "whois.arin.net")])
19
+ end
20
+ end
21
+
22
+ context "with referral" do
23
+ it "follows whois:// referrals" do
24
+ referral = File.read(fixture("referrals/arin_referral_whois.txt"))
25
+ response = "Whois Response"
26
+ expected = "#{referral}\n#{response}"
27
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(referral)
28
+ expect(server.query_handler).to receive(:call).with("0.0.0.0", "whois.ripe.net", 43).and_return(response)
29
+
30
+ record = server.lookup("0.0.0.0")
31
+ expect(record.to_s).to eq(expected)
32
+ expect(record.parts.size).to eq(2)
33
+ expect(record.parts).to eq([Whois::Record::Part.new(body: referral, host: "whois.arin.net"),
34
+ Whois::Record::Part.new(body: response, host: "whois.ripe.net"),])
35
+ end
36
+
37
+ it "follows rwhois:// referrals" do
38
+ referral = File.read(fixture("referrals/arin_referral_rwhois.txt"))
39
+ response = "Whois Response"
40
+ expected = "#{referral}\n#{response}"
41
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(referral)
42
+ expect(server.query_handler).to receive(:call).with("0.0.0.0", "rwhois.servernap.net", 4321).and_return(response)
43
+
44
+ record = server.lookup("0.0.0.0")
45
+ expect(record.to_s).to eq(expected)
46
+ expect(record.parts.size).to eq(2)
47
+ expect(record.parts).to eq([Whois::Record::Part.new(body: referral, host: "whois.arin.net"),
48
+ Whois::Record::Part.new(body: response, host: "rwhois.servernap.net"),])
49
+ end
50
+
51
+ it "ignores referral if options[:referral] is false" do
52
+ referral = File.read(fixture("referrals/arin_referral_whois.txt"))
53
+ server.options[:referral] = false
54
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(referral)
55
+ expect(server.query_handler).not_to receive(:call).with("0.0.0.0", "whois.ripe.net", 43)
56
+
57
+ record = server.lookup("0.0.0.0")
58
+ expect(record.parts.size).to eq(1)
59
+ end
60
+
61
+ it "ignores referral (gracefully) if missing" do
62
+ referral = File.read(fixture("referrals/arin_referral_missing.txt"))
63
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(referral)
64
+ expect(server.query_handler).not_to receive(:call)
65
+
66
+ record = server.lookup("0.0.0.0")
67
+ expect(record.parts.size).to eq(1)
68
+ end
69
+
70
+ it "folows referrals without ports" do
71
+ referral = File.read(fixture("referrals/arin_referral_apnic.txt"))
72
+ response = "Whois Response"
73
+ expect(server.query_handler).to receive(:call).with("n + 0.0.0.0", "whois.arin.net", 43).and_return(referral)
74
+ expect(server.query_handler).to receive(:call).with("0.0.0.0", "whois.apnic.net", 43).and_return(response)
75
+
76
+ record = server.lookup("0.0.0.0")
77
+ expect(record.parts.size).to eq(2)
78
+ expect(record.parts).to eq([Whois::Record::Part.new(body: referral, host: "whois.arin.net"),
79
+ Whois::Record::Part.new(body: response, host: "whois.apnic.net"),])
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "whois/server/adapters/arin"
5
+
6
+ describe Whois::Server::Adapters::Arpa do
7
+ let(:definition) { [:tld, ".in-addr.arpa", nil, {}] }
8
+
9
+ describe "#lookup" do
10
+ it "returns the WHOIS record" do
11
+ server = described_class.new(*definition)
12
+ expect(Whois::Server::Adapters::Arin.query_handler).to receive(:call)
13
+ .with("n + 229.128.in-addr.arpa", "whois.arin.net", 43)
14
+ .and_return(response = "Whois Response")
15
+
16
+ record = server.lookup("229.128.in-addr.arpa")
17
+ expect(record.to_s).to eq(response)
18
+ expect(record.parts).to eq([Whois::Record::Part.new(body: response, host: "whois.arin.net")])
19
+ end
20
+
21
+ it "discards newlines" do
22
+ server = described_class.new(*definition)
23
+
24
+ expect do
25
+ server.lookup("229.128.in-addr.arpa\nextra")
26
+ end.to raise_error(Whois::ServerError, "Invalid .in-addr.arpa address")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Whois::Server::Adapters::Base do
6
+ let(:definition) { [:tld, ".test", "whois.test", { foo: "bar" }] }
7
+
8
+
9
+ describe "#initialize" do
10
+ it "requires type, allocation, and host parameters" do
11
+ expect { described_class.new(:tld) }.to raise_error(ArgumentError)
12
+ expect { described_class.new(:tld, ".test") }.to raise_error(ArgumentError)
13
+ expect { described_class.new(:tld, ".test", "whois.test") }.not_to raise_error
14
+ end
15
+
16
+ it "accepts an options parameter" do
17
+ expect { described_class.new(:tld, ".test", "whois.test", { foo: "bar" }) }.not_to raise_error
18
+ end
19
+
20
+ it "sets instance variables from arguments" do
21
+ instance = described_class.new(:tld, ".test", "whois.test", { foo: "bar" })
22
+ expect(instance.type).to eq(:tld)
23
+ expect(instance.allocation).to eq(".test")
24
+ expect(instance.host).to eq("whois.test")
25
+ expect(instance.options).to eq({ foo: "bar" })
26
+ end
27
+
28
+ it "defaults options to an empty hash" do
29
+ instance = described_class.new(:tld, ".test", "whois.test")
30
+ expect(instance.options).to eq({})
31
+ end
32
+ end
33
+
34
+ describe "#==" do
35
+ it "returns true when other is the same instance" do
36
+ one = two = described_class.new(*definition)
37
+
38
+ expect(one == two).to be_truthy
39
+ expect(one).to eql(two)
40
+ end
41
+
42
+ it "returns true when other has same class and has the same attributes" do
43
+ one = described_class.new(*definition)
44
+ two = described_class.new(*definition)
45
+
46
+ expect(one == two).to be_truthy
47
+ expect(one).to eql(two)
48
+ end
49
+
50
+ it "returns true when other has descendant class and has the same attributes" do
51
+ subklass = Class.new(described_class)
52
+ one = described_class.new(*definition)
53
+ two = subklass.new(*definition)
54
+
55
+ expect(one == two).to be_truthy
56
+ expect(one).to eql(two)
57
+ end
58
+
59
+ it "returns false when other has different class and has the same attributes" do
60
+ one = described_class.new(*definition)
61
+ two = Struct.new(:type, :allocation, :host, :options).new(*definition)
62
+
63
+ expect(one == two).to be_falsey
64
+ expect(one).not_to eql(two)
65
+ end
66
+
67
+ it "returns false when other has different attributes" do
68
+ one = described_class.new(:tld, ".test", "whois.test")
69
+ two = described_class.new(:tld, ".cool", "whois.test")
70
+
71
+ expect(one == two).to be_falsey
72
+ expect(one).not_to eql(two)
73
+ end
74
+
75
+ it "returns false when other has different options" do
76
+ one = described_class.new(:tld, ".test", "whois.test")
77
+ two = described_class.new(:tld, ".test", "whois.test", { foo: "bar" })
78
+
79
+ expect(one == two).to be_falsey
80
+ expect(one).not_to eql(two)
81
+ end
82
+ end
83
+
84
+
85
+ describe "#configure" do
86
+ it "merges settings with current options" do
87
+ a = described_class.new(:tld, ".test", "whois.test", { hello: "world" })
88
+ a.configure(foo: "bar")
89
+ expect(a.options).to eq({ hello: "world", foo: "bar" })
90
+ end
91
+
92
+ it "gives higher priority to settings argument" do
93
+ a = described_class.new(:tld, ".test", "whois.test", { foo: "bar" })
94
+ expect(a.options).to eq({ foo: "bar" })
95
+ a.configure(foo: "baz")
96
+ expect(a.options).to eq({ foo: "baz" })
97
+ end
98
+
99
+ it "overrides @host if :host option exists" do
100
+ a = described_class.new(:tld, ".test", "whois.test", { hello: "world" })
101
+ a.configure(foo: "bar", host: "whois.example.com")
102
+ expect(a.options).to eq({ hello: "world", foo: "bar", host: "whois.example.com" })
103
+ expect(a.host).to eq("whois.example.com")
104
+ end
105
+ end
106
+
107
+
108
+ describe "#lookup" do
109
+ it "raises NotImplementedError" do
110
+ expect {
111
+ described_class.new(*definition).lookup("example.test")
112
+ }.to raise_error(NotImplementedError)
113
+ end
114
+ end
115
+
116
+ describe "#request" do
117
+ it "is an abstract method" do
118
+ expect {
119
+ described_class.new(*definition).request("example.test")
120
+ }.to raise_error(NotImplementedError)
121
+ end
122
+ end
123
+
124
+ describe "#query_the_socket" do
125
+ context "without :bind_host or :bind_port options" do
126
+ let(:server) { described_class.new(:tld, ".test", "whois.test", {}) }
127
+
128
+ it "does not bind the WHOIS query" do
129
+ expect(described_class.query_handler).to receive(:call).with("example.test", "whois.test", 43)
130
+
131
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
132
+ end
133
+ end
134
+
135
+ context "with :bind_host and :bind_port options" do
136
+ let(:server) { described_class.new(:tld, ".test", "whois.test", { bind_host: "192.168.1.1", bind_port: 3000 }) }
137
+
138
+ it "binds the WHOIS query to given host and port" do
139
+ expect(described_class.query_handler).to receive(:call).with("example.test", "whois.test", 43, "192.168.1.1", 3000)
140
+
141
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
142
+ end
143
+ end
144
+
145
+ context "with :bind_port and without :bind_host options" do
146
+ let(:server) { described_class.new(:tld, ".test", "whois.test", { bind_port: 3000 }) }
147
+
148
+ it "binds the WHOIS query to given port and defaults host" do
149
+ expect(described_class.query_handler).to receive(:call).with("example.test", "whois.test", 43, described_class::DEFAULT_BIND_HOST, 3000)
150
+
151
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
152
+ end
153
+ end
154
+ end
155
+ end