LVS-JSONService 0.0.0 → 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.
- data/JSONService.gemspec +57 -0
- data/VERSION +1 -1
- data/lib/lvs/json_service/base.rb +194 -0
- data/lib/lvs/json_service/logger.rb +11 -0
- data/lib/lvs/json_service/request.rb +76 -0
- data/spec/fixtures/error_response.yml +21 -0
- data/spec/fixtures/response.yml +27 -0
- data/spec/lvs/json_service/base_spec.rb +7 -0
- data/spec/lvs/json_service/logger_spec.rb +35 -0
- data/spec/lvs/json_service/request_spec.rb +249 -0
- data/spec/spec.opts +4 -0
- metadata +18 -5
data/JSONService.gemspec
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{JSONService}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["LVS"]
|
9
|
+
s.date = %q{2009-06-18}
|
10
|
+
s.email = %q{info@lvs.co.uk}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"LICENSE",
|
13
|
+
"README.rdoc"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
"JSONService.gemspec",
|
17
|
+
"LICENSE",
|
18
|
+
"README.rdoc",
|
19
|
+
"Rakefile",
|
20
|
+
"VERSION",
|
21
|
+
"lib/json_service.rb",
|
22
|
+
"lib/lvs/json_service/base.rb",
|
23
|
+
"lib/lvs/json_service/logger.rb",
|
24
|
+
"lib/lvs/json_service/request.rb",
|
25
|
+
"spec/fixtures/error_response.yml",
|
26
|
+
"spec/fixtures/response.yml",
|
27
|
+
"spec/json_service_spec.rb",
|
28
|
+
"spec/lvs/json_service/base_spec.rb",
|
29
|
+
"spec/lvs/json_service/logger_spec.rb",
|
30
|
+
"spec/lvs/json_service/request_spec.rb",
|
31
|
+
"spec/spec.opts",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
s.has_rdoc = true
|
35
|
+
s.homepage = %q{http://github.com/lvs/JSONService}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.1}
|
39
|
+
s.summary = %q{TODO}
|
40
|
+
s.test_files = [
|
41
|
+
"spec/lvs/json_service/base_spec.rb",
|
42
|
+
"spec/lvs/json_service/logger_spec.rb",
|
43
|
+
"spec/lvs/json_service/request_spec.rb",
|
44
|
+
"spec/spec_helper.rb",
|
45
|
+
"spec/json_service_spec.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 2
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
else
|
54
|
+
end
|
55
|
+
else
|
56
|
+
end
|
57
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'activesupport'
|
2
|
+
require 'net/https'
|
3
|
+
require 'lvs/json_service/request'
|
4
|
+
|
5
|
+
module LVS
|
6
|
+
module JsonService
|
7
|
+
class Base
|
8
|
+
include ::LVS::JsonService::Request
|
9
|
+
|
10
|
+
@@services = []
|
11
|
+
@@cache = CACHE if defined?(CACHE)
|
12
|
+
@@service_prefix = ""
|
13
|
+
attr_accessor :fields
|
14
|
+
cattr_accessor :service_prefix
|
15
|
+
cattr_accessor :field_prefix
|
16
|
+
cattr_accessor :cache
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def self.site=(value)
|
21
|
+
# value is containing AGP_LOCATION already sometimes:
|
22
|
+
if SSL_DISABLED
|
23
|
+
value.gsub!(/^#{AGP_LOCATION}/, '') if AGP_LOCATION && value.match(/#{AGP_LOCATION}/)
|
24
|
+
agp = AGP_LOCATION.gsub(/\/$/, '')
|
25
|
+
else
|
26
|
+
value.gsub!(/^#{AGP_LOCATION}/, '')
|
27
|
+
value.gsub!(/^#{SSL_AGP_LOCATION}/, '') if SSL_AGP_LOCATION && value.match(/#{SSL_AGP_LOCATION}/)
|
28
|
+
agp = SSL_AGP_LOCATION.gsub(/\/$/, '')
|
29
|
+
end
|
30
|
+
value.gsub!(/^\//, '')
|
31
|
+
@@site = (agp + '/' + value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.debug(message)
|
35
|
+
Rails.logger.debug " \033[1;4;32mLVS::JsonService\033[0m #{message}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.define_cached_service(name, service, options)
|
39
|
+
(class<<self;self;end).send :define_method, name do |*args|
|
40
|
+
begin
|
41
|
+
args = args.first || {}
|
42
|
+
options[:cache_time] ||= 10
|
43
|
+
service_name = "call_#{name}"
|
44
|
+
mutex ||= Mutex::new
|
45
|
+
tried = false
|
46
|
+
mutex.lock if AppTools.is_memcached_threaded?
|
47
|
+
begin
|
48
|
+
jsn_data = { }
|
49
|
+
if ActionController::Base.perform_caching && @@cache
|
50
|
+
Rails.logger.info("JSON API CACHED CALL: #{service} - #{args.to_yaml}")
|
51
|
+
key = "json:call:" + Digest::MD5.hexdigest("#{service}:#{args.to_s}")
|
52
|
+
cached = @@cache.get(key)
|
53
|
+
if cached.nil?
|
54
|
+
result = self.send(service_name, args)
|
55
|
+
@@cache.set(key, result, options[:cache_time])
|
56
|
+
jsn_data = result
|
57
|
+
else
|
58
|
+
jsn_data = cached
|
59
|
+
end
|
60
|
+
else
|
61
|
+
Rails.logger.info("JSON API CALL: #{method} - #{args.to_yaml}")
|
62
|
+
jsn_data = self.send(service_name, args)
|
63
|
+
end
|
64
|
+
jsn_data
|
65
|
+
rescue MemCache::MemCacheError => err
|
66
|
+
raise err if tried
|
67
|
+
Rails.logger.info("JSON API CALL RETRY: #{err} - #{method} - #{args.to_yaml}")
|
68
|
+
tried = true
|
69
|
+
retry
|
70
|
+
end
|
71
|
+
ensure
|
72
|
+
mutex.unlock if AppTools.is_memcached_threaded?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.define_service(name, service, options = {})
|
78
|
+
service_name = name
|
79
|
+
|
80
|
+
service_path = service.split('.')
|
81
|
+
if service_path.size <= 2
|
82
|
+
internal_service = service
|
83
|
+
prefix = @@service_prefix
|
84
|
+
else
|
85
|
+
internal_service = service_path[-2..-1].join('.')
|
86
|
+
prefix = service_path[0..-3].join('.') + '.'
|
87
|
+
end
|
88
|
+
|
89
|
+
if options[:cached]
|
90
|
+
service_name = "call_#{name}"
|
91
|
+
self.define_cached_service(name, service, options)
|
92
|
+
end
|
93
|
+
|
94
|
+
(class<<self;self;end).send :define_method, service_name do |args|
|
95
|
+
method_params, flags = args
|
96
|
+
|
97
|
+
method_params ||= {}
|
98
|
+
options[:defaults] ||= {}
|
99
|
+
options[:defaults].each_pair do |key, value|
|
100
|
+
method_params[key] = value if method_params[key].blank?
|
101
|
+
end
|
102
|
+
options[:required] ||= {}
|
103
|
+
options[:required].each do |key|
|
104
|
+
raise LVS::JsonService::Error.new("Required field #{key} wasn't supplied", internal_service, '0', method_params) if method_params[key].blank?
|
105
|
+
end
|
106
|
+
result = self.run_remote_request(@@site + prefix + internal_service, method_params, options)
|
107
|
+
if flags && flags[:raw]
|
108
|
+
result
|
109
|
+
else
|
110
|
+
self.parse_result(result)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@@services << name
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.fake_service(name, json)
|
118
|
+
(class<<self;self;end).send :define_method, name do |*args|
|
119
|
+
self.parse_result(JSON.parse(json))
|
120
|
+
end
|
121
|
+
@@services << name
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.services
|
125
|
+
@@services
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.parse_result(response)
|
129
|
+
if response.is_a?(Array)
|
130
|
+
response.map { |x| self.new(x) }
|
131
|
+
else
|
132
|
+
self.new(response)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def initialize(values = {})
|
137
|
+
values.each_pair do |key, value|
|
138
|
+
key = key.underscore
|
139
|
+
self.class.send(:define_method, key, proc {self.instance_variable_get("@#{key}")})
|
140
|
+
self.class.send(:define_method, "#{key}=", proc {|value| self.instance_variable_set("@#{key}", value)})
|
141
|
+
|
142
|
+
# If the key starts with has_ create alias to has_ method removing has
|
143
|
+
# and putting ? at the end
|
144
|
+
if key =~ /^has_/
|
145
|
+
temp_key = "#{key.gsub(/^has_/, '')}?"
|
146
|
+
self.class.send(:define_method, temp_key, proc {self.instance_variable_get("@#{key}")})
|
147
|
+
self.class.send(:define_method, "#{temp_key}=", proc {|value| self.instance_variable_set("@#{key}", value)})
|
148
|
+
end
|
149
|
+
|
150
|
+
if value.is_a?(Hash)
|
151
|
+
self.instance_variable_set("@#{key}", self.class.new(value))
|
152
|
+
elsif value.is_a?(Array)
|
153
|
+
self.instance_variable_set("@#{key}", value.collect {|v| if v.is_a?(Hash) or v.is_a?(Array) then self.class.new(v) else v end })
|
154
|
+
else
|
155
|
+
if key =~ /date$/
|
156
|
+
value = Time.at(value/1000)
|
157
|
+
elsif key =~ /^has_/
|
158
|
+
self.instance_variable_set("@#{key}", value)
|
159
|
+
!(value == 0 || value.blank?)
|
160
|
+
elsif key =~ /\?$/
|
161
|
+
key = "has_#{key.chop}"
|
162
|
+
!(value == 0 || value.blank?)
|
163
|
+
end
|
164
|
+
|
165
|
+
self.instance_variable_set("@#{key}", value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def method_missing(*args)
|
171
|
+
self.class.debug("Method #{args[0]} called on #{self.class} but is non-existant, returned default FALSE")
|
172
|
+
super
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Error < StandardError
|
177
|
+
attr_reader :message, :code, :service, :args, :json_response
|
178
|
+
|
179
|
+
def initialize(message, code, service, args, response=nil)
|
180
|
+
@message = message
|
181
|
+
@code = code
|
182
|
+
@service = service
|
183
|
+
@args = args
|
184
|
+
@json_response = response
|
185
|
+
|
186
|
+
super "#{message}\n#{service} (#{args.inspect})"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class NotFoundError < Error; end
|
191
|
+
class TimeoutError < Error; end
|
192
|
+
class BackendUnavailableError < Error; end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'lvs/json_service/logger'
|
3
|
+
|
4
|
+
module LVS
|
5
|
+
module JsonService
|
6
|
+
module Request
|
7
|
+
def self.http_request_with_timeout(service, args, options)
|
8
|
+
|
9
|
+
uri = URI.parse(service)
|
10
|
+
|
11
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
12
|
+
|
13
|
+
if options[:encrypted] && !SSL_DISABLED
|
14
|
+
http.use_ssl = true
|
15
|
+
if options[:auth_cert]
|
16
|
+
http.cert = OpenSSL::X509::Certificate.new(File.read(options[:auth_cert]))
|
17
|
+
http.key = OpenSSL::PKey::RSA.new(File.read(options[:auth_key]), options[:auth_key_password])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
http.open_timeout = options[:timeout] || 1
|
22
|
+
http.read_timeout = options[:timeout] || 1
|
23
|
+
|
24
|
+
req = Net::HTTP::Post.new(uri.path)
|
25
|
+
req.form_data = { "object_request" => args.to_json }
|
26
|
+
|
27
|
+
retries = options[:retries] || 0
|
28
|
+
|
29
|
+
begin
|
30
|
+
retries -= 1
|
31
|
+
response = http.start { |connection| connection.request(req) }
|
32
|
+
|
33
|
+
rescue Timeout::Error
|
34
|
+
if retries >= 0
|
35
|
+
LVS::JsonService::Logger.debug(
|
36
|
+
"Retrying #{service} due to TimeoutError"
|
37
|
+
)
|
38
|
+
retry
|
39
|
+
end
|
40
|
+
raise LVS::JsonService::TimeoutError.new("Backend failed to respond in time", 500, service, args)
|
41
|
+
|
42
|
+
rescue Errno::ECONNREFUSED
|
43
|
+
if retries >= 0
|
44
|
+
LVS::JsonService::Logger.debug(
|
45
|
+
"Retrying #{service} due to Errno::ECONNREFUSED"
|
46
|
+
)
|
47
|
+
sleep(1)
|
48
|
+
retry
|
49
|
+
end
|
50
|
+
raise LVS::JsonService::BackendUnavailableError.new("Backend unavailable", 500, service, args)
|
51
|
+
end
|
52
|
+
|
53
|
+
if response.is_a?(Net::HTTPNotFound)
|
54
|
+
raise LVS::JsonService::NotFoundError.new("404 Found for the service", 404, service, args)
|
55
|
+
end
|
56
|
+
|
57
|
+
response
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.run_remote_request(service, args, options = {})
|
61
|
+
LVS::JsonService::Logger.debug "run_remote_request('#{service}', #{args.to_json}"
|
62
|
+
response = http_request_with_timeout(service, args, options)
|
63
|
+
if response.body.size < 1024
|
64
|
+
LVS::JsonService::Logger.debug "Response: #{response.body.gsub(/\n/, '')}"
|
65
|
+
else
|
66
|
+
LVS::JsonService::Logger.debug "Response Snippet: #{response.body.gsub(/\n/, '')[0..1024]}"
|
67
|
+
end
|
68
|
+
result = JSON.parse(response.body)
|
69
|
+
if result.is_a?(Hash) && result.has_key?("PCode")
|
70
|
+
raise LVS::JsonService::Error.new(result["message"], result["PCode"], service, args, result)
|
71
|
+
end
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
--- !ruby/object:Net::HTTPOK
|
2
|
+
body: |
|
3
|
+
{
|
4
|
+
"PCode" : 1,
|
5
|
+
"message": "something bad happened"
|
6
|
+
}
|
7
|
+
body_exist: true
|
8
|
+
code: "200"
|
9
|
+
header:
|
10
|
+
date:
|
11
|
+
- Wed, 17 Jun 2009 13:17:54 GMT
|
12
|
+
content-type:
|
13
|
+
- text/plain;charset=UTF-8
|
14
|
+
server:
|
15
|
+
- Apache-Coyote/1.1
|
16
|
+
transfer-encoding:
|
17
|
+
- chunked
|
18
|
+
http_version: "1.1"
|
19
|
+
message: OK
|
20
|
+
read: true
|
21
|
+
socket:
|
@@ -0,0 +1,27 @@
|
|
1
|
+
--- !ruby/object:Net::HTTPOK
|
2
|
+
body: |-
|
3
|
+
[
|
4
|
+
{
|
5
|
+
"description": "Handball (ABP)",
|
6
|
+
"id": 1100
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"description": "Casino Roulette",
|
10
|
+
"id": 978400
|
11
|
+
}
|
12
|
+
]
|
13
|
+
body_exist: true
|
14
|
+
code: "200"
|
15
|
+
header:
|
16
|
+
date:
|
17
|
+
- Wed, 17 Jun 2009 13:17:54 GMT
|
18
|
+
content-type:
|
19
|
+
- text/plain;charset=UTF-8
|
20
|
+
server:
|
21
|
+
- Apache-Coyote/1.1
|
22
|
+
transfer-encoding:
|
23
|
+
- chunked
|
24
|
+
http_version: "1.1"
|
25
|
+
message: OK
|
26
|
+
read: true
|
27
|
+
socket:
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe LVS::JsonService::Logger do
|
4
|
+
before :each do
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "debug" do
|
8
|
+
describe "with RAILS_DEFAULT_LOGGER set" do
|
9
|
+
before :each do
|
10
|
+
@mock_logger = mock()
|
11
|
+
LVS::JsonService::Logger.const_set(:RAILS_DEFAULT_LOGGER, @mock_logger)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should pass the message to RAILS_DEFAULT_LOGGER" do
|
15
|
+
message = "Some debug message"
|
16
|
+
@mock_logger.should_receive(:debug).with(message)
|
17
|
+
LVS::JsonService::Logger.debug(message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "without RAILS_ROOT set" do
|
22
|
+
before :each do
|
23
|
+
LVS::JsonService::Logger.module_eval do
|
24
|
+
remove_const(:RAILS_DEFAULT_LOGGER) if const_defined?(:RAILS_DEFAULT_LOGGER)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not raise an exception" do
|
29
|
+
lambda {
|
30
|
+
LVS::JsonService::Logger.debug("something")
|
31
|
+
}.should_not raise_error(Exception)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
# Explicitly requiring this now to ensure it is loaded before we try to
|
4
|
+
# unmarshall response from the yaml fixture file.
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
describe LVS::JsonService::Request do
|
8
|
+
before :each do
|
9
|
+
@domain = "example.com"
|
10
|
+
@path = "/some/path"
|
11
|
+
@port = 80
|
12
|
+
@url = "http://#{@domain}#{@path}"
|
13
|
+
|
14
|
+
@args = {:some => "thing"}
|
15
|
+
@options= {:timeout => 100}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".http_request_with_timeout" do
|
19
|
+
before :each do
|
20
|
+
@mock_post = mock(:post, :null_object => true)
|
21
|
+
Net::HTTP::Post.stub!(:new).and_return(@mock_post)
|
22
|
+
|
23
|
+
@mock_http = MockNetHttp.new
|
24
|
+
@connection = @mock_http.connection
|
25
|
+
Net::HTTP.stub!(:new).and_return(@mock_http)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should set Net::HTTP#open_timeout" do
|
29
|
+
@mock_http.should_receive(:open_timeout=).with(@options[:timeout])
|
30
|
+
do_request
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set Net::HTTP#read_timeout" do
|
34
|
+
@mock_http.should_receive(:read_timeout=).with(@options[:timeout])
|
35
|
+
do_request
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should default to a timeout of 1 if not set" do
|
39
|
+
@options = {:timeout => nil}
|
40
|
+
@mock_http.should_receive(:read_timeout=).with(1)
|
41
|
+
do_request
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should pass through the domain and port to Net::HTTP" do
|
45
|
+
Net::HTTP.should_receive(:new).with(@domain, @port).and_return(@mock_http)
|
46
|
+
do_request
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should create a Net::HTTP::Post object" do
|
50
|
+
Net::HTTP::Post.should_receive(:new).with(@path).and_return(@mock_post)
|
51
|
+
do_request
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should assign the JSON parameters to a Net::HTTP::Post object" do
|
55
|
+
@mock_post.should_receive(:form_data=).with({ "object_request" => @args.to_json })
|
56
|
+
do_request
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should send one request to Net::HTTP#start" do
|
60
|
+
@connection.should_receive(:request).once.with(@mock_post)
|
61
|
+
do_request
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return the response from the service" do
|
65
|
+
response = "some response"
|
66
|
+
@connection.should_receive(:request).and_return(response)
|
67
|
+
do_request.should == response
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "with 2 retries of Timeout::Error" do
|
71
|
+
|
72
|
+
before :each do
|
73
|
+
@options = {:retries => 2}
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "with subsequent success" do
|
77
|
+
|
78
|
+
it "should post the request 2 times" do
|
79
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_raise(Timeout::Error.new(nil))
|
80
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered
|
81
|
+
do_request
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return the response from the service" do
|
85
|
+
response = "some response"
|
86
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_raise(Timeout::Error.new(nil))
|
87
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_return(response)
|
88
|
+
do_request.should == response
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should log the retry attempt" do
|
94
|
+
@connection.stub!(:request).and_raise(Timeout::Error.new(nil))
|
95
|
+
LVS::JsonService::Logger.should_receive(:debug).at_least(1).times.
|
96
|
+
with("Retrying #{@url} due to TimeoutError")
|
97
|
+
do_request_catching_errors
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "with subseqent failure" do
|
101
|
+
|
102
|
+
before :each do
|
103
|
+
@connection.stub!(:request).and_raise(Timeout::Error.new(nil))
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should post the request 3 times (original + 2 retries)" do
|
107
|
+
@connection.should_receive(:request).with(@mock_post).exactly(3).times.and_raise(Timeout::Error.new(nil))
|
108
|
+
do_request_catching_errors
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should raise an LVS::JsonService::TimeoutError exception" do
|
112
|
+
lambda {
|
113
|
+
do_request
|
114
|
+
}.should raise_error(LVS::JsonService::TimeoutError)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "with 2 retries of Errno::ECONNREFUSED" do
|
121
|
+
|
122
|
+
before :each do
|
123
|
+
@options = {:retries => 2}
|
124
|
+
LVS::JsonService::Request.stub!(:sleep)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should sleep for 1 second before each timeout" do
|
128
|
+
@connection.stub!(:request).and_raise(Errno::ECONNREFUSED)
|
129
|
+
LVS::JsonService::Request.should_receive(:sleep).with(1)
|
130
|
+
do_request_catching_errors
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "with subsequent success" do
|
134
|
+
|
135
|
+
it "should post the request 2 times" do
|
136
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_raise(Errno::ECONNREFUSED)
|
137
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered
|
138
|
+
do_request
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should return the response from the service" do
|
142
|
+
response = "some response"
|
143
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_raise(Errno::ECONNREFUSED)
|
144
|
+
@connection.should_receive(:request).with(@mock_post).exactly(1).times.ordered.and_return(response)
|
145
|
+
do_request.should == response
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "with subsequent failure" do
|
150
|
+
|
151
|
+
before :each do
|
152
|
+
@connection.stub!(:request).and_raise(Errno::ECONNREFUSED)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should post the request 3 times (original + 2 retries)" do
|
156
|
+
@connection.should_receive(:request).with(@mock_post).exactly(3).times.and_raise(Errno::ECONNREFUSED)
|
157
|
+
do_request_catching_errors
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should raise an LVS::JsonService::BackendUnavailableError exception" do
|
161
|
+
lambda {
|
162
|
+
do_request
|
163
|
+
}.should raise_error(LVS::JsonService::BackendUnavailableError)
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should log the retry attempt" do
|
169
|
+
@connection.stub!(:request).and_raise(Errno::ECONNREFUSED)
|
170
|
+
LVS::JsonService::Logger.should_receive(:debug).at_least(1).times.
|
171
|
+
with("Retrying #{@url} due to Errno::ECONNREFUSED")
|
172
|
+
do_request_catching_errors
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should raise LVS::JsonService::NotFoundError if Net::HTTPNotFound is raised" do
|
177
|
+
@connection.stub!(:request).and_return(Net::HTTPNotFound.new(404, 1.1, "Not Found"))
|
178
|
+
lambda {
|
179
|
+
do_request
|
180
|
+
}.should raise_error(LVS::JsonService::NotFoundError)
|
181
|
+
end
|
182
|
+
|
183
|
+
def do_request
|
184
|
+
LVS::JsonService::Request.http_request_with_timeout(@url, @args, @options)
|
185
|
+
end
|
186
|
+
|
187
|
+
def do_request_catching_errors
|
188
|
+
do_request
|
189
|
+
rescue LVS::JsonService::Error
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe ".run_remote_request" do
|
195
|
+
before :each do
|
196
|
+
@response = load_fixture('response.yml')
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should call http_request_with_timeout with service, args and options" do
|
200
|
+
LVS::JsonService::Request.should_receive(:http_request_with_timeout).
|
201
|
+
with(@url, @args, @options).
|
202
|
+
and_return(@response)
|
203
|
+
LVS::JsonService::Request.run_remote_request(@url, @args, @options)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should return the parsed JSON result" do
|
207
|
+
expected_result = [
|
208
|
+
{"id"=>1100, "description"=>"Handball (ABP)"},
|
209
|
+
{"id"=>978400, "description"=>"Casino Roulette"}
|
210
|
+
]
|
211
|
+
LVS::JsonService::Request.stub!(:http_request_with_timeout).and_return(@response)
|
212
|
+
LVS::JsonService::Request.run_remote_request(@url, @args, @options).should == expected_result
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should raise an error if the response contains PCode" do
|
216
|
+
error_response = load_fixture('error_response.yml')
|
217
|
+
LVS::JsonService::Request.stub!(:http_request_with_timeout).
|
218
|
+
and_return(error_response)
|
219
|
+
|
220
|
+
lambda {
|
221
|
+
LVS::JsonService::Request.run_remote_request(@url, @args, @options)
|
222
|
+
}.should raise_error(LVS::JsonService::Error)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
def load_fixture (file)
|
229
|
+
response_file = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', file)
|
230
|
+
YAML.load_file(response_file)
|
231
|
+
end
|
232
|
+
|
233
|
+
class MockNetHttp
|
234
|
+
|
235
|
+
attr_accessor :connection
|
236
|
+
|
237
|
+
def initialize(*args)
|
238
|
+
@connection = mock(:connection)
|
239
|
+
end
|
240
|
+
|
241
|
+
def start
|
242
|
+
yield @connection
|
243
|
+
end
|
244
|
+
|
245
|
+
def method_missing(*args)
|
246
|
+
return self
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
data/spec/spec.opts
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: LVS-JSONService
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LVS
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-18 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,14 +23,24 @@ extra_rdoc_files:
|
|
23
23
|
- LICENSE
|
24
24
|
- README.rdoc
|
25
25
|
files:
|
26
|
+
- JSONService.gemspec
|
26
27
|
- LICENSE
|
27
28
|
- README.rdoc
|
28
29
|
- Rakefile
|
29
30
|
- VERSION
|
30
31
|
- lib/json_service.rb
|
32
|
+
- lib/lvs/json_service/base.rb
|
33
|
+
- lib/lvs/json_service/logger.rb
|
34
|
+
- lib/lvs/json_service/request.rb
|
35
|
+
- spec/fixtures/error_response.yml
|
36
|
+
- spec/fixtures/response.yml
|
31
37
|
- spec/json_service_spec.rb
|
38
|
+
- spec/lvs/json_service/base_spec.rb
|
39
|
+
- spec/lvs/json_service/logger_spec.rb
|
40
|
+
- spec/lvs/json_service/request_spec.rb
|
41
|
+
- spec/spec.opts
|
32
42
|
- spec/spec_helper.rb
|
33
|
-
has_rdoc:
|
43
|
+
has_rdoc: true
|
34
44
|
homepage: http://github.com/lvs/JSONService
|
35
45
|
post_install_message:
|
36
46
|
rdoc_options:
|
@@ -54,8 +64,11 @@ requirements: []
|
|
54
64
|
rubyforge_project:
|
55
65
|
rubygems_version: 1.2.0
|
56
66
|
signing_key:
|
57
|
-
specification_version:
|
67
|
+
specification_version: 2
|
58
68
|
summary: TODO
|
59
69
|
test_files:
|
60
|
-
- spec/
|
70
|
+
- spec/lvs/json_service/base_spec.rb
|
71
|
+
- spec/lvs/json_service/logger_spec.rb
|
72
|
+
- spec/lvs/json_service/request_spec.rb
|
61
73
|
- spec/spec_helper.rb
|
74
|
+
- spec/json_service_spec.rb
|