addressfinder 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bac347ed1fa4ee45f7ff1bdc3f5fdc5bee74206fa73b1fe4d33be727f21c1b41
4
- data.tar.gz: 44e72444624d652a166089b6c630fb739d47f77155dfaed2e8a27b88afa7bf59
3
+ metadata.gz: 8d84bdab006a12ff6f18d90d33986cf03172e1d8fedc52ffca604795631b8420
4
+ data.tar.gz: 933d6673ee1271440c17801ac410047a44761d6e1539de3f7c211cec9ee16bd7
5
5
  SHA512:
6
- metadata.gz: 180b47e4aa74a5b09c312cc6be655bca62f9f4293f68b7c2505370dbdf2f14c2a48bf71d6523fbe1cf991bcf078745f62ba9d9f9b4e7cebdabd9b38900e111ee
7
- data.tar.gz: 7396a52596c09359dbd3cb2facaafe6d4af4b4887be6d0c12b9de8770441ca45055bace9b4665af649793c0f482f39125b59df0e377f75c61e6380578ab258e1
6
+ metadata.gz: 27b217ad366baf5b6e46d02ab14410a30133d7adfefb06292a92daedc271266ed7139d83be5d14cdee4a3e1128ee18d6604049cd41405f243496bfc24dc13cf6
7
+ data.tar.gz: 26861692d4d8936ae1f5a581390afb2d04cc1f9a870b43488e6f0e76d4bb33caacdbe92e28ee13e8b92960d1dc5bb410d0a01ffdba6fe83c4917214afbbbdf57
@@ -0,0 +1,31 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ "master" ]
6
+ pull_request:
7
+ branches: [ "master" ]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ ruby-version: ['2.6', '2.7', '3.0', '3.1']
19
+
20
+ steps:
21
+ - uses: actions/checkout@v3
22
+ - name: Set up Ruby
23
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
24
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
25
+ # uses: ruby/setup-ruby@v1
26
+ uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa # v1.115.3
27
+ with:
28
+ ruby-version: ${{ matrix.ruby-version }}
29
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
30
+ - name: Run tests
31
+ run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # AddressFinder 1.10.0 (August 2023) #
2
+
3
+ * Add support for Email Verification
4
+ * Add support for Phone Verification
5
+ * Add support for Bulk Email Verification
6
+ * Add support for Bulk Phone Verification
7
+
8
+ # AddressFinder 1.9.1 (October 2022) #
9
+
10
+ * Add missing kwarg `**` for ruby 3
11
+
1
12
  # AddressFinder 1.9.0 (July 2022) #
2
13
 
3
14
  * Add support for Ruby 3.x
data/README.md CHANGED
@@ -157,6 +157,28 @@ rescue AddressFinder::RequestRejectedError => e
157
157
  end
158
158
  ```
159
159
 
160
+ #### Email Verification
161
+ ```ruby
162
+ begin
163
+ result = AddressFinder.email_verification(email: 'john.doe')
164
+ $stdout.puts "This email address is verified: #{result.is_verified}"
165
+ rescue AddressFinder::RequestRejectedError => e
166
+ response = JSON.parse(e.body)
167
+ $stdout.puts response['message']
168
+ end
169
+ ```
170
+
171
+ #### Phone Verification
172
+ ```ruby
173
+ begin
174
+ result = AddressFinder.phone_verification(phone_number: '1800 152 363', default_country_code: 'AU')
175
+ $stdout.puts "This phone number is verified: #{result.is_verified}"
176
+ rescue AddressFinder::RequestRejectedError => e
177
+ response = JSON.parse(e.body)
178
+ $stdout.puts response['message']
179
+ end
180
+ ```
181
+
160
182
  ## Advanced Usage
161
183
 
162
184
  #### Bulk Operations
@@ -164,7 +186,7 @@ end
164
186
  If you have a series of API requests, you can use the
165
187
  bulk method to re-use the HTTP connection.
166
188
 
167
- **Note:** The bulk method is currently only available for Address Verification (`#verification`).
189
+ **Note:** The bulk method is currently only available for Address Verification, Email Verification and Phone Verification (`#verification`, `#email_verification`, `#phone_verifiction`).
168
190
 
169
191
  ```ruby
170
192
  AddressFinder.bulk do |af|
@@ -36,6 +36,14 @@ module AddressFinder
36
36
  end
37
37
  end
38
38
 
39
+ def email_verification(args={})
40
+ AddressFinder::V1::Email::Verification.new(**args.merge(http: http)).perform.result
41
+ end
42
+
43
+ def phone_verification(args={})
44
+ AddressFinder::V1::Phone::Verification.new(**args.merge(http: http)).perform.result
45
+ end
46
+
39
47
  private
40
48
 
41
49
  attr_reader :http, :verification_version, :default_country
@@ -0,0 +1,71 @@
1
+ require 'ostruct'
2
+
3
+ module AddressFinder
4
+ module V1
5
+ class Base
6
+ attr_reader :result
7
+
8
+ def initialize(params:, path:, http:)
9
+ @params = params
10
+ @params[:domain] ||= config.domain if config.domain
11
+ @params[:key] ||= config.api_key
12
+ @params[:secret] ||= config.api_secret
13
+ @params[:format] ||= 'json'
14
+
15
+ @path = path
16
+ @http = http
17
+ end
18
+
19
+ def perform
20
+ build_request
21
+ execute_request
22
+ build_result
23
+
24
+ self
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :request_uri, :params, :http, :path
30
+ attr_accessor :response_body, :response_status
31
+ attr_writer :result
32
+
33
+ def build_request
34
+ @request_uri = "#{path}?#{encoded_params}"
35
+ end
36
+
37
+ def encoded_params
38
+ Util.encode_and_join_params(params)
39
+ end
40
+
41
+ def execute_request
42
+ request = Net::HTTP::Get.new(request_uri)
43
+
44
+ response = http.request(request)
45
+
46
+ self.response_body = response.body
47
+ self.response_status = response.code
48
+ end
49
+
50
+ def build_result
51
+ case response_status
52
+ when '200'
53
+ self.result = Result.new(response_hash)
54
+ else
55
+ raise AddressFinder::RequestRejectedError.new(response_status, response_body)
56
+ end
57
+ end
58
+
59
+ def response_hash
60
+ @_response_hash ||= MultiJson.load(response_body)
61
+ end
62
+
63
+ def config
64
+ @_config ||= AddressFinder.configuration
65
+ end
66
+
67
+ class Result < OpenStruct
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,16 @@
1
+ require 'addressfinder/v1/base'
2
+
3
+ module AddressFinder
4
+ module V1
5
+ module Email
6
+ class Verification < AddressFinder::V1::Base
7
+ attr_reader :result
8
+
9
+ def initialize(email:, http:, **args)
10
+ params = {email: email}.merge(args)
11
+ super(params: params, path: "/api/email/v1/verification", http: http)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'addressfinder/v1/base'
2
+
3
+ module AddressFinder
4
+ module V1
5
+ module Phone
6
+ class Verification < AddressFinder::V1::Base
7
+ attr_reader :result
8
+
9
+ def initialize(phone_number:, default_country_code:, http:, **args)
10
+ params = {phone_number: phone_number, default_country_code: default_country_code}.merge(args)
11
+ super(params: params, path: "/api/phone/v1/verification", http: http)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module AddressFinder
2
- VERSION = '1.9.0'
2
+ VERSION = '1.10.0'
3
3
  end
data/lib/addressfinder.rb CHANGED
@@ -9,6 +9,8 @@ require 'addressfinder/address_info'
9
9
  require 'addressfinder/address_search'
10
10
  require 'addressfinder/address_autocomplete'
11
11
  require 'addressfinder/bulk'
12
+ require 'addressfinder/v1/email/verification'
13
+ require 'addressfinder/v1/phone/verification'
12
14
  require 'addressfinder/errors'
13
15
  require 'addressfinder/util'
14
16
  require 'addressfinder/http'
@@ -30,14 +32,14 @@ module AddressFinder
30
32
  end
31
33
 
32
34
  def cleanse(args={}) # We are keeping this method for backward compatibility
33
- AddressFinder::Verification.new(args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
35
+ AddressFinder::Verification.new(**args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
34
36
  end
35
37
 
36
38
  def verification(args={})
37
39
  if (args[:country] || configuration.default_country) == 'au' && configuration.verification_version&.downcase == "v2"
38
- AddressFinder::V2::Au::Verification.new(args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
40
+ AddressFinder::V2::Au::Verification.new(**args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
39
41
  else
40
- AddressFinder::Verification.new(args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
42
+ AddressFinder::Verification.new(**args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
41
43
  end
42
44
  end
43
45
 
@@ -61,6 +63,14 @@ module AddressFinder
61
63
  AddressFinder::AddressInfo.new(params: args, http: AddressFinder::HTTP.new(configuration)).perform.result
62
64
  end
63
65
 
66
+ def email_verification(args={})
67
+ AddressFinder::V1::Email::Verification.new(**args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
68
+ end
69
+
70
+ def phone_verification(args={})
71
+ AddressFinder::V1::Phone::Verification.new(**args.merge(http: AddressFinder::HTTP.new(configuration))).perform.result
72
+ end
73
+
64
74
  def bulk(&block)
65
75
  AddressFinder::Bulk.new(http: AddressFinder::HTTP.new(configuration), verification_version: configuration.verification_version, default_country: configuration.default_country, &block).perform
66
76
  end
@@ -111,5 +111,97 @@ RSpec.describe AddressFinder::Bulk do
111
111
  AddressFinder::Bulk.new(http: http, verification_version: "v2", default_country: 'nz', &block).perform
112
112
  end
113
113
  end
114
+
115
+ context "email verification with 3 requests in the provided block" do
116
+ let(:response){ double(:response, body: %Q({"success": true}), code: "200") }
117
+ let(:block){
118
+ Proc.new do |proxy|
119
+ proxy.email_verification(email: "john.doe@addressfinder.com")
120
+ proxy.email_verification(email: "jane.doe@addressfinder.com")
121
+ proxy.email_verification(email: "tom.doe@addressfinder.com")
122
+ end
123
+ }
124
+
125
+ it "uses 1 http connection" do
126
+ expect(net_http).to receive(:do_start).once.and_call_original
127
+ expect(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
128
+ expect(net_http).to receive(:do_finish).once.and_call_original
129
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
130
+ end
131
+
132
+ it "calls the correct class with v1 verification and nz default" do
133
+ allow(net_http).to receive(:do_start).once.and_call_original
134
+ allow(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
135
+ allow(net_http).to receive(:do_finish).once.and_call_original
136
+ expect(AddressFinder::V1::Email::Verification).to receive(:new).exactly(3).times.and_call_original
137
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
138
+ end
139
+
140
+ it "calls the correct class without a verification version or default country" do
141
+ allow(net_http).to receive(:do_start).once.and_call_original
142
+ allow(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
143
+ allow(net_http).to receive(:do_finish).once.and_call_original
144
+ expect(AddressFinder::V1::Email::Verification).to receive(:new).exactly(3).times.and_call_original
145
+ AddressFinder::Bulk.new(http: http, verification_version: nil, default_country: nil, &block).perform
146
+ end
147
+
148
+ it "re-establishes the http connection and continues where we left off when a Net::OpenTimeout, Net::ReadTimeout or SocketError is raised" do
149
+ expect(http).to receive(:re_establish_connection).exactly(3).times.and_call_original
150
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
151
+ expect(net_http).to receive(:transport_request).once.and_return(response) # john.doe@addressfinder.com (success)
152
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::OpenTimeout) # jane.doe@addressfinder.com (error)
153
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::ReadTimeout) # Retry jane.doe@addressfinder.com (error)
154
+ expect(net_http).to receive(:transport_request).once.and_raise(SocketError) # Retry jane.doe@addressfinder.com (error)
155
+ expect(net_http).to receive(:transport_request).exactly(2).and_return(response) # Retry jane.doe@addressfinder.com (success) & tom.doe@addressfinder.com (success)
156
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
157
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
158
+ end
159
+ end
160
+
161
+ context "phone verification with 3 requests in the provided block" do
162
+ let(:response){ double(:response, body: %Q({"success": true}), code: "200") }
163
+ let(:block){
164
+ Proc.new do |proxy|
165
+ proxy.phone_verification(phone_number: "+64274673830", default_country_code: "AU")
166
+ proxy.phone_verification(phone_number: "1800 152 363", default_country_code: "AU")
167
+ proxy.phone_verification(phone_number: "0274673830", default_country_code: "NZ")
168
+ end
169
+ }
170
+
171
+ it "uses 1 http connection" do
172
+ expect(net_http).to receive(:do_start).once.and_call_original
173
+ expect(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
174
+ expect(net_http).to receive(:do_finish).once.and_call_original
175
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
176
+ end
177
+
178
+ it "calls the correct class with v1 verification and nz default" do
179
+ allow(net_http).to receive(:do_start).once.and_call_original
180
+ allow(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
181
+ allow(net_http).to receive(:do_finish).once.and_call_original
182
+ expect(AddressFinder::V1::Phone::Verification).to receive(:new).exactly(3).times.and_call_original
183
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
184
+ end
185
+
186
+ it "calls the correct class without a verification version or default country" do
187
+ allow(net_http).to receive(:do_start).once.and_call_original
188
+ allow(net_http).to receive(:transport_request).exactly(3).times.and_return(response)
189
+ allow(net_http).to receive(:do_finish).once.and_call_original
190
+ expect(AddressFinder::V1::Phone::Verification).to receive(:new).exactly(3).times.and_call_original
191
+ AddressFinder::Bulk.new(http: http, verification_version: nil, default_country: nil, &block).perform
192
+ end
193
+
194
+ it "re-establishes the http connection and continues where we left off when a Net::OpenTimeout, Net::ReadTimeout or SocketError is raised" do
195
+ expect(http).to receive(:re_establish_connection).exactly(3).times.and_call_original
196
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
197
+ expect(net_http).to receive(:transport_request).once.and_return(response) # +64274673830 (success)
198
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::OpenTimeout) # 1800 152 363 (error)
199
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::ReadTimeout) # Retry 1800 152 363 (error)
200
+ expect(net_http).to receive(:transport_request).once.and_raise(SocketError) # Retry 1800 152 363 (error)
201
+ expect(net_http).to receive(:transport_request).exactly(2).and_return(response) # Retry 1800 152 363 (success) & 0274673830 (success)
202
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
203
+ AddressFinder::Bulk.new(http: http, verification_version: 'v1', default_country: 'nz', &block).perform
204
+ end
205
+ end
114
206
  end
115
207
  end
@@ -0,0 +1,148 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe AddressFinder::V1::Email::Verification do
4
+ before do
5
+ AddressFinder.configure do |af|
6
+ af.api_key = "XXX"
7
+ af.api_secret = "YYY"
8
+ af.timeout = 5
9
+ af.retries = 3
10
+ end
11
+ end
12
+
13
+ let(:verification_module){ AddressFinder::V1::Email::Verification.new(**args) }
14
+ let(:http){ AddressFinder::HTTP.new(AddressFinder.configuration) }
15
+ let(:net_http){ http.send(:net_http) }
16
+
17
+ describe "#execute_request" do
18
+ let(:args){ {email: "john.doe@addressfinder.com", http: http} }
19
+
20
+ before do
21
+ WebMock.allow_net_connect!(net_http_connect_on_start: true)
22
+ allow(http).to receive(:sleep)
23
+ allow(verification_module).to receive(:request_uri).and_return("/test/path")
24
+ expect(http).to_not receive(:re_establish_connection)
25
+ end
26
+
27
+ after do
28
+ WebMock.disable_net_connect!
29
+ end
30
+
31
+ subject(:execute_request){ verification_module.send(:execute_request) }
32
+
33
+ it "retries an errored request another time before succeeding" do
34
+ expect(net_http).to receive(:do_start).twice.and_call_original
35
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::OpenTimeout)
36
+ expect(net_http).to receive(:transport_request).once.and_return(double(:response, body: "OK", code: "200"))
37
+ expect(net_http).to receive(:do_finish).twice.and_call_original
38
+ execute_request
39
+ end
40
+
41
+ it "re-raises a Net::OpenTimeout error after 3 retries" do
42
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
43
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(Net::OpenTimeout)
44
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
45
+ expect{execute_request}.to raise_error(Net::OpenTimeout)
46
+ end
47
+
48
+ it "re-raises a Net::ReadTimeout error after 3 retries" do
49
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
50
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(Net::ReadTimeout)
51
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
52
+ expect{execute_request}.to raise_error(Net::ReadTimeout)
53
+ end
54
+
55
+ it "re-raises a SocketError error after 3 retries" do
56
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
57
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(SocketError)
58
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
59
+ expect{execute_request}.to raise_error(SocketError)
60
+ end
61
+ end
62
+
63
+ describe "#build_request" do
64
+ subject(:request_uri){ verification_module.send(:build_request) }
65
+
66
+ context "with email argument" do
67
+ let(:args){ {email: "john.doe@addressfinder.com", http: http} }
68
+
69
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&key=XXX&secret=YYY&format=json") }
70
+ end
71
+
72
+ context "with email and format arguments" do
73
+ let(:args){ {email: "john.doe@addressfinder.com", format: "xml", http: http} }
74
+
75
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&format=xml&key=XXX&secret=YYY") }
76
+ end
77
+
78
+ context "with a reserved character in the email" do
79
+ let(:args){ {email: "john=doe@addressfinder.com", http: http} }
80
+
81
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john%3Ddoe%40addressfinder.com&key=XXX&secret=YYY&format=json") }
82
+ end
83
+
84
+ context "with a key override" do
85
+ let(:args){ {email: "john.doe@addressfinder.com", key: "AAA", http: http} }
86
+
87
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&key=AAA&secret=YYY&format=json") }
88
+ end
89
+
90
+ context "with a secret override" do
91
+ let(:args){ {email: "john.doe@addressfinder.com", secret: "BBB", http: http} }
92
+
93
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&secret=BBB&key=XXX&format=json") }
94
+ end
95
+
96
+ context "with a domain given" do
97
+ let(:args){ {email: "john.doe@addressfinder.com", domain: "testdomain.com", http: http} }
98
+
99
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&domain=testdomain.com&key=XXX&secret=YYY&format=json") }
100
+
101
+ context "given in the AF configuration" do
102
+ let(:args){ {email: "john.doe@addressfinder.com", http: http} }
103
+
104
+ it "should use the config domain if set" do
105
+ AddressFinder.configuration.domain = "anotherdomain.com"
106
+ expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&domain=anotherdomain.com&key=XXX&secret=YYY&format=json")
107
+ AddressFinder.configuration.domain = nil # set back to nil after
108
+ end
109
+ end
110
+ end
111
+
112
+ context "with a all arguments included in request" do
113
+ let(:args){ {email: "john.doe@addressfinder.com", domain: "mysite.com", key: "AAA", secret: "BBB", format: "json", http: http} }
114
+
115
+ it { expect(request_uri).to eq("/api/email/v1/verification?email=john.doe%40addressfinder.com&domain=mysite.com&key=AAA&secret=BBB&format=json") }
116
+ end
117
+ end
118
+
119
+ describe "#build_result" do
120
+ let(:args){ {email: "ignored", http: nil} }
121
+
122
+ before do
123
+ verification_module.send("response_body=", body)
124
+ verification_module.send("response_status=", status)
125
+ end
126
+
127
+ subject(:result){ verification_module.send(:build_result) }
128
+
129
+ context "with a successful verification" do
130
+ let(:body){ '{"email_account": "john.doe", "email_domain": "addressfinder.com", "is_verified": true, "success": true}' }
131
+ let(:status){ "200" }
132
+
133
+ it { expect(result.class).to eq(AddressFinder::V1::Email::Verification::Result) }
134
+ it { expect(result.is_verified).to eq(true) }
135
+ it { expect(result.email_account).to eq("john.doe") }
136
+ end
137
+
138
+ context "with an unsuccessful verification" do
139
+ let(:body){ '{"email_account": "jane.doe", "email_domain": "addressfinder.com", "is_verified": false, "not_verified_reason": "The email account does not exist", "success": true}' }
140
+ let(:status){ "200" }
141
+
142
+ it { expect(result.class).to eq(AddressFinder::V1::Email::Verification::Result) }
143
+ it { expect(result.is_verified).to eq(false) }
144
+ it { expect(result.email_account).to eq("jane.doe") }
145
+ it { expect(result.not_verified_reason).to eq("The email account does not exist") }
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,144 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe AddressFinder::V1::Phone::Verification do
4
+ before do
5
+ AddressFinder.configure do |af|
6
+ af.api_key = "XXX"
7
+ af.api_secret = "YYY"
8
+ af.timeout = 5
9
+ af.retries = 3
10
+ end
11
+ end
12
+
13
+ let(:verification_module){ AddressFinder::V1::Phone::Verification.new(**args) }
14
+ let(:http){ AddressFinder::HTTP.new(AddressFinder.configuration) }
15
+ let(:net_http){ http.send(:net_http) }
16
+
17
+ describe "#execute_request" do
18
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", http: http} }
19
+
20
+ before do
21
+ WebMock.allow_net_connect!(net_http_connect_on_start: true)
22
+ allow(http).to receive(:sleep)
23
+ allow(verification_module).to receive(:request_uri).and_return("/test/path")
24
+ expect(http).to_not receive(:re_establish_connection)
25
+ end
26
+
27
+ after do
28
+ WebMock.disable_net_connect!
29
+ end
30
+
31
+ subject(:execute_request){ verification_module.send(:execute_request) }
32
+
33
+ it "retries an errored request another time before succeeding" do
34
+ expect(net_http).to receive(:do_start).twice.and_call_original
35
+ expect(net_http).to receive(:transport_request).once.and_raise(Net::OpenTimeout)
36
+ expect(net_http).to receive(:transport_request).once.and_return(double(:response, body: "OK", code: "200"))
37
+ expect(net_http).to receive(:do_finish).twice.and_call_original
38
+ execute_request
39
+ end
40
+
41
+ it "re-raises a Net::OpenTimeout error after 3 retries" do
42
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
43
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(Net::OpenTimeout)
44
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
45
+ expect{execute_request}.to raise_error(Net::OpenTimeout)
46
+ end
47
+
48
+ it "re-raises a Net::ReadTimeout error after 3 retries" do
49
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
50
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(Net::ReadTimeout)
51
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
52
+ expect{execute_request}.to raise_error(Net::ReadTimeout)
53
+ end
54
+
55
+ it "re-raises a SocketError error after 3 retries" do
56
+ expect(net_http).to receive(:do_start).exactly(4).times.and_call_original
57
+ expect(net_http).to receive(:transport_request).exactly(4).times.and_raise(SocketError)
58
+ expect(net_http).to receive(:do_finish).exactly(4).times.and_call_original
59
+ expect{execute_request}.to raise_error(SocketError)
60
+ end
61
+ end
62
+
63
+ describe "#build_request" do
64
+ subject(:request_uri){ verification_module.send(:build_request) }
65
+
66
+ context "with phone number and default country code arguments" do
67
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", http: http} }
68
+
69
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=AU&key=XXX&secret=YYY&format=json") }
70
+ end
71
+
72
+ context "with a reserved character in the phone number" do
73
+ let(:args){ {phone_number: "1800= 152 363", default_country_code: "AU", http: http} }
74
+
75
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800%3D+152+363&default_country_code=AU&key=XXX&secret=YYY&format=json") }
76
+ end
77
+
78
+ context "with a key override" do
79
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", key: "AAA", http: http} }
80
+
81
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=AU&key=AAA&secret=YYY&format=json") }
82
+ end
83
+
84
+ context "with a secret override" do
85
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", secret: "BBB", http: http} }
86
+
87
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=AU&secret=BBB&key=XXX&format=json") }
88
+ end
89
+
90
+ context "with a domain given" do
91
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", domain: "testdomain.com", http: http} }
92
+
93
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=AU&domain=testdomain.com&key=XXX&secret=YYY&format=json") }
94
+
95
+ context "given in the AF configuration" do
96
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU", http: http} }
97
+
98
+ it "should use the config domain if set" do
99
+ AddressFinder.configuration.domain = "anotherdomain.com"
100
+ expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=AU&domain=anotherdomain.com&key=XXX&secret=YYY&format=json")
101
+ AddressFinder.configuration.domain = nil # set back to nil after
102
+ end
103
+ end
104
+ end
105
+
106
+ context "with a all arguments included in request" do
107
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "NZ", allowed_country_codes: "AU,NZ", mobile_only: true, timeout: "10", domain: "mysite.com", key: "AAA", secret: "BBB", format: "xml", http: http} }
108
+
109
+ it { expect(request_uri).to eq("/api/phone/v1/verification?phone_number=1800+152+363&default_country_code=NZ&allowed_country_codes=AU%2CNZ&mobile_only=true&timeout=10&domain=mysite.com&key=AAA&secret=BBB&format=xml") }
110
+ end
111
+ end
112
+
113
+ describe "#build_result" do
114
+ let(:args){ {phone_number: "ignored", default_country_code: "ignored", http: nil} }
115
+
116
+ before do
117
+ verification_module.send("response_body=", body)
118
+ verification_module.send("response_status=", status)
119
+ end
120
+
121
+ subject(:result){ verification_module.send(:build_result) }
122
+
123
+ context "with a successful verification" do
124
+ let(:body){ '{"raw_international": "+611800152353", "line_type": "toll_free", "line_status": "disconnected", "is_verified": true, "success": true}' }
125
+ let(:status){ "200" }
126
+
127
+ it { expect(result.class).to eq(AddressFinder::V1::Phone::Verification::Result) }
128
+ it { expect(result.is_verified).to eq(true) }
129
+ it { expect(result.raw_international).to eq("+611800152353") }
130
+ it { expect(result.line_type).to eq("toll_free") }
131
+ it { expect(result.line_status).to eq("disconnected") }
132
+ end
133
+
134
+ context "with an unsuccessful verification" do
135
+ let(:body){ '{"is_verified": false, "not_verified_reason": "Phone number format is incorrect", "not_verified_code": "INVALID_FORMAT", "success": true}' }
136
+ let(:status){ "200" }
137
+
138
+ it { expect(result.class).to eq(AddressFinder::V1::Phone::Verification::Result) }
139
+ it { expect(result.is_verified).to eq(false) }
140
+ it { expect(result.not_verified_code).to eq("INVALID_FORMAT") }
141
+ it { expect(result.not_verified_reason).to eq("Phone number format is incorrect") }
142
+ end
143
+ end
144
+ end
@@ -116,7 +116,7 @@ RSpec.describe AddressFinder::V2::Au::Verification do
116
116
 
117
117
  it 'should use the config domain if set' do
118
118
  AddressFinder.configuration.domain = 'anotherdomain.com'
119
- # expect(request_uri).to eq('/api/au/address/v2/verification?q=123&domain=anotherdomain.com&key=XXX&secret=YYY&format=json')
119
+ expect(request_uri).to eq('/api/au/address/v2/verification?q=123&domain=anotherdomain.com&key=XXX&secret=YYY&format=json')
120
120
  AddressFinder.configuration.domain = nil # set back to nil after
121
121
  end
122
122
  end
@@ -29,6 +29,11 @@ RSpec.describe AddressFinder do
29
29
  expect(AddressFinder::Verification).to receive_message_chain(:new, :perform, :result)
30
30
  subject
31
31
  end
32
+
33
+ it "safely passes arguments through" do
34
+ stub_request(:get, Addressable::Template.new("https://api.addressfinder.io/api/nz/address/verification{?args*}")).to_return(:status => 200, :body => "{}", :headers => {})
35
+ subject
36
+ end
32
37
  end
33
38
 
34
39
  context "with country set to au" do
@@ -37,6 +42,11 @@ RSpec.describe AddressFinder do
37
42
  expect(AddressFinder::V2::Au::Verification).to receive_message_chain(:new, :perform, :result)
38
43
  subject
39
44
  end
45
+
46
+ it "safely passes arguments through" do
47
+ stub_request(:get, Addressable::Template.new("https://api.addressfinder.io/api/au/address/v2/verification{?args*}")).to_return(:status => 200, :body => "{}", :headers => {})
48
+ subject
49
+ end
40
50
  end
41
51
  end
42
52
 
@@ -61,4 +71,24 @@ RSpec.describe AddressFinder do
61
71
  end
62
72
  end
63
73
  end
74
+
75
+ context "#email_verification" do
76
+ subject(:verification) { AddressFinder.email_verification(args) }
77
+ let(:args){ {email: "john.doe@addressfinder.com"} }
78
+
79
+ it "calls the email verification class" do
80
+ expect(AddressFinder::V1::Email::Verification).to receive_message_chain(:new, :perform, :result)
81
+ subject
82
+ end
83
+ end
84
+
85
+ context "#phone_verification" do
86
+ subject(:verification) { AddressFinder.phone_verification(args) }
87
+ let(:args){ {phone_number: "1800 152 363", default_country_code: "AU"} }
88
+
89
+ it "calls the phone verification class" do
90
+ expect(AddressFinder::V1::Phone::Verification).to receive_message_chain(:new, :perform, :result)
91
+ subject
92
+ end
93
+ end
64
94
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: addressfinder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nigel Ramsay
@@ -9,10 +9,10 @@ authors:
9
9
  - Sean Arnold
10
10
  - Alexandre Barret
11
11
  - Cassandre Guinut
12
- autorequire:
12
+ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2022-07-21 00:00:00.000000000 Z
15
+ date: 2023-08-30 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: multi_json
@@ -109,6 +109,7 @@ executables: []
109
109
  extensions: []
110
110
  extra_rdoc_files: []
111
111
  files:
112
+ - ".github/workflows/ruby.yml"
112
113
  - ".gitignore"
113
114
  - ".travis.yml"
114
115
  - CHANGELOG.md
@@ -131,6 +132,9 @@ files:
131
132
  - lib/addressfinder/location_info.rb
132
133
  - lib/addressfinder/location_search.rb
133
134
  - lib/addressfinder/util.rb
135
+ - lib/addressfinder/v1/base.rb
136
+ - lib/addressfinder/v1/email/verification.rb
137
+ - lib/addressfinder/v1/phone/verification.rb
134
138
  - lib/addressfinder/v2/au/verification.rb
135
139
  - lib/addressfinder/verification.rb
136
140
  - lib/addressfinder/version.rb
@@ -141,6 +145,8 @@ files:
141
145
  - spec/lib/addressfinder/location_info_spec.rb
142
146
  - spec/lib/addressfinder/location_search_spec.rb
143
147
  - spec/lib/addressfinder/util_spec.rb
148
+ - spec/lib/addressfinder/v1/email/verification_spec.rb
149
+ - spec/lib/addressfinder/v1/phone/verification_spec.rb
144
150
  - spec/lib/addressfinder/v2/au/verification_spec.rb
145
151
  - spec/lib/addressfinder/verification_spec.rb
146
152
  - spec/lib/addressfinder_spec.rb
@@ -149,7 +155,7 @@ homepage: https://github.com/AddressFinder/addressfinder-ruby
149
155
  licenses:
150
156
  - MIT
151
157
  metadata: {}
152
- post_install_message:
158
+ post_install_message:
153
159
  rdoc_options: []
154
160
  require_paths:
155
161
  - lib
@@ -164,8 +170,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
170
  - !ruby/object:Gem::Version
165
171
  version: '0'
166
172
  requirements: []
167
- rubygems_version: 3.1.6
168
- signing_key:
173
+ rubygems_version: 3.1.4
174
+ signing_key:
169
175
  specification_version: 4
170
176
  summary: Provides easy access to AddressFinder APIs
171
177
  test_files:
@@ -176,6 +182,8 @@ test_files:
176
182
  - spec/lib/addressfinder/location_info_spec.rb
177
183
  - spec/lib/addressfinder/location_search_spec.rb
178
184
  - spec/lib/addressfinder/util_spec.rb
185
+ - spec/lib/addressfinder/v1/email/verification_spec.rb
186
+ - spec/lib/addressfinder/v1/phone/verification_spec.rb
179
187
  - spec/lib/addressfinder/v2/au/verification_spec.rb
180
188
  - spec/lib/addressfinder/verification_spec.rb
181
189
  - spec/lib/addressfinder_spec.rb