and-son 0.7.0 → 0.8.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.
@@ -11,14 +11,17 @@ module AndSon
11
11
  DEFAULT_TIMEOUT = 60 # seconds
12
12
 
13
13
  attr_reader :host, :port
14
+ attr_reader :before_call_procs, :after_call_procs
14
15
  attr_accessor :timeout_value, :params_value, :logger_value
15
16
 
16
17
  def initialize(host, port)
17
18
  @host = host
18
19
  @port = port
19
- @params_value = {}
20
+ @params_value = {}
20
21
  @timeout_value = (ENV['ANDSON_TIMEOUT'] || DEFAULT_TIMEOUT).to_f
21
- @logger_value = NullLogger.new
22
+ @logger_value = NullLogger.new
23
+ @before_call_procs = []
24
+ @after_call_procs = []
22
25
  end
23
26
 
24
27
  # chain runner methods by returning itself
@@ -29,10 +32,14 @@ module AndSon
29
32
  if !params.kind_of?(Hash)
30
33
  raise ArgumentError, "expected params to be a Hash instead of a #{params.class}"
31
34
  end
35
+ call_params = self.params_value.merge(params)
36
+
37
+ self.before_call_procs.each{ |p| p.call(name, call_params, self) }
32
38
  client_response = nil
33
39
  benchmark = Benchmark.measure do
34
- client_response = self.call!(name, params)
40
+ client_response = call!(name, call_params)
35
41
  end
42
+ self.after_call_procs.each{ |p| p.call(name, call_params, self) }
36
43
 
37
44
  summary_line = SummaryLine.new({
38
45
  'time' => RoundedTime.new(benchmark.real),
@@ -50,19 +57,6 @@ module AndSon
50
57
  end
51
58
  end
52
59
 
53
- def call!(name, params)
54
- call_params = self.params_value.merge(params)
55
- AndSon::Connection.new(host, port).open do |connection|
56
- connection.write(Sanford::Protocol::Request.new(name, call_params).to_hash)
57
- connection.close_write
58
- if !connection.peek(timeout_value).empty?
59
- AndSon::Response.parse(connection.read(timeout_value))
60
- else
61
- raise AndSon::ConnectionClosedError.new
62
- end
63
- end
64
- end
65
-
66
60
  def hash
67
61
  [ self.host,
68
62
  self.port,
@@ -77,6 +71,20 @@ module AndSon
77
71
  end
78
72
  alias :eql? :==
79
73
 
74
+ private
75
+
76
+ def call!(name, params)
77
+ AndSon::Connection.new(host, port).open do |connection|
78
+ connection.write(Sanford::Protocol::Request.new(name, params).to_hash)
79
+ connection.close_write
80
+ if !connection.peek(timeout_value).empty?
81
+ AndSon::Response.parse(connection.read(timeout_value))
82
+ else
83
+ raise AndSon::ConnectionClosedError.new
84
+ end
85
+ end
86
+ end
87
+
80
88
  module InstanceMethods
81
89
 
82
90
  # define methods here to allow configuring call runner params. be sure to
@@ -99,6 +107,14 @@ module AndSon
99
107
  self.call_runner.tap{ |r| r.logger_value = passed_logger }
100
108
  end
101
109
 
110
+ def before_call(&block)
111
+ self.call_runner.tap{ |r| r.before_call_procs << block }
112
+ end
113
+
114
+ def after_call(&block)
115
+ self.call_runner.tap{ |r| r.after_call_procs << block }
116
+ end
117
+
102
118
  private
103
119
 
104
120
  def stringify_keys(hash)
@@ -56,20 +56,28 @@ module AndSon
56
56
  class TestClient
57
57
  include Client
58
58
 
59
- attr_accessor :timeout_value, :params_value, :logger_value
60
59
  attr_reader :calls, :responses
60
+ attr_reader :before_call_procs, :after_call_procs
61
+ attr_accessor :timeout_value, :params_value, :logger_value
61
62
 
62
63
  def initialize(host, port)
63
64
  super
64
- @params_value = {}
65
65
  @calls = []
66
66
  @responses = AndSon::StoredResponses.new
67
+
68
+ @params_value = {}
69
+ @before_call_procs = []
70
+ @after_call_procs = []
67
71
  end
68
72
 
69
73
  def call(name, params = nil)
70
74
  params ||= {}
75
+ callback_params = self.params_value.merge(params)
76
+
71
77
  response = self.responses.get(name, params)
78
+ self.before_call_procs.each{ |p| p.call(name, callback_params, self) }
72
79
  self.calls << Call.new(name, params, response.protocol_response)
80
+ self.after_call_procs.each{ |p| p.call(name, callback_params, self) }
73
81
  if block_given?
74
82
  yield response.protocol_response
75
83
  else
@@ -79,12 +87,12 @@ module AndSon
79
87
 
80
88
  def call_runner; self; end
81
89
 
82
- def add_response(*args, &block)
83
- self.responses.add(*args, &block)
90
+ def add_response(name, &block)
91
+ self.responses.add(name, &block)
84
92
  end
85
93
 
86
- def remove_response(*args)
87
- self.responses.remove(*args)
94
+ def remove_responses(name)
95
+ self.responses.remove(name)
88
96
  end
89
97
 
90
98
  def reset
@@ -5,47 +5,58 @@ module AndSon
5
5
 
6
6
  class StoredResponses
7
7
 
8
- RequestData = Struct.new(:name, :params)
9
-
10
8
  def initialize
11
- @hash = Hash.new{ default_response_proc }
9
+ @hash = Hash.new{ |h, k| h[k] = Stub.new }
12
10
  end
13
11
 
14
- def add(name, params = nil, &response_block)
15
- request_data = RequestData.new(name, params || {})
16
- @hash[request_data] = response_block
12
+ def add(name, &block)
13
+ @hash[name].tap{ |s| s.set_default_proc(&block) }
17
14
  end
18
15
 
19
- def get(name, params = nil)
20
- response_block = @hash[RequestData.new(name, params || {})]
21
- response = handle_response_block(response_block)
16
+ def get(name, params)
17
+ response = @hash[name].call(params)
22
18
  AndSon::Response.new(response)
23
19
  end
24
20
 
25
- def remove(name, params = nil)
26
- @hash.delete(RequestData.new(name, params || {}))
21
+ def remove(name)
22
+ @hash.delete(name)
27
23
  end
28
24
 
29
25
  def remove_all
30
26
  @hash.clear
31
27
  end
32
28
 
33
- private
29
+ class Stub
30
+ attr_reader :hash
34
31
 
35
- def handle_response_block(response_block)
36
- if response_block.arity == 0 || response_block.arity == -1
37
- default_response.tap{ |r| r.data = response_block.call }
38
- else
39
- default_response.tap{ |r| response_block.call(r) }
32
+ def initialize
33
+ @default_proc = proc{ |r| r.data = Hash.new }
34
+ @hash = {}
40
35
  end
41
- end
42
36
 
43
- def default_response
44
- Sanford::Protocol::Response.new(200, {})
45
- end
37
+ def set_default_proc(&block)
38
+ @default_proc = block if block
39
+ end
40
+
41
+ def with(params, &block)
42
+ @hash[params] = block
43
+ self
44
+ end
45
+
46
+ def call(params)
47
+ block = @hash[params] || @default_proc
48
+ if block.arity == 0 || block.arity == -1
49
+ default_response.tap{ |r| r.data = block.call }
50
+ else
51
+ default_response.tap{ |r| block.call(r) }
52
+ end
53
+ end
46
54
 
47
- def default_response_proc
48
- proc{ |r| r.data = Hash.new }
55
+ private
56
+
57
+ def default_response
58
+ Sanford::Protocol::Response.new(200, {})
59
+ end
49
60
  end
50
61
 
51
62
  end
@@ -1,3 +1,3 @@
1
1
  module AndSon
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  require 'socket'
2
2
 
3
- class FakeServer
3
+ class TestServer
4
4
 
5
5
  def initialize(port, options = nil)
6
6
  options ||= {}
@@ -16,7 +16,7 @@ class FakeServer
16
16
  end
17
17
 
18
18
  def run
19
- server = TCPServer.new("localhost", @port)
19
+ server = TCPServer.new('127.0.0.1', @port)
20
20
  socket = server.accept
21
21
 
22
22
  if @closing_server
@@ -48,9 +48,9 @@ class FakeServer
48
48
  returned = handler.call(request.params)
49
49
  end
50
50
 
51
- module Helper
51
+ module TestHelpers
52
52
 
53
- def run_fake_server(server, &block)
53
+ def run_test_server(server, &block)
54
54
  begin
55
55
  thread = Thread.new{ server.run }
56
56
  yield
@@ -65,12 +65,12 @@ class FakeServer
65
65
 
66
66
  def start_closing_server(port, &block)
67
67
  server = FakeServer.new(port, :closing_server => true)
68
- run_fake_server(server, &block)
68
+ run_test_server(server, &block)
69
69
  end
70
70
 
71
71
  def start_slow_server(port, &block)
72
72
  server = FakeServer.new(port, :slow => true)
73
- run_fake_server(server, &block)
73
+ run_test_server(server, &block)
74
74
  end
75
75
 
76
76
  end
@@ -0,0 +1,205 @@
1
+ require 'assert'
2
+ require 'and-son/client'
3
+
4
+ require 'test/support/test_server'
5
+
6
+ module AndSon::Client
7
+
8
+ class SystemTests < Assert::Context
9
+ desc "AndSon::Client"
10
+ setup do
11
+ @host = '127.0.0.1'
12
+ @port = 12000
13
+ end
14
+
15
+ end
16
+
17
+ class UsingTestServerSetupTests < SystemTests
18
+ include TestServer::TestHelpers
19
+
20
+ setup do
21
+ @test_server = TestServer.new(@port)
22
+ end
23
+
24
+ end
25
+
26
+ class SuccessfulRequestTests < UsingTestServerSetupTests
27
+ desc "when making a request to a service"
28
+ setup do
29
+ @service_name = Factory.string
30
+ @test_server.add_handler(@service_name) do |params|
31
+ [200, params['message']]
32
+ end
33
+ @client = AndSon.new(@host, @port)
34
+ end
35
+
36
+ should "return a 200 response" do
37
+ self.run_test_server(@test_server) do
38
+
39
+ params = { 'message' => Factory.string }
40
+ @client.call(@service_name, params) do |r|
41
+ assert_equal 200, r.code
42
+ assert_equal params['message'], r.data
43
+ assert_nil r.message
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ class BadRequestTests < UsingTestServerSetupTests
52
+ desc "when making a request to a service that returns a 400"
53
+ setup do
54
+ @service_name = Factory.string
55
+ @test_server.add_handler(@service_name) do |params|
56
+ [400, Factory.string]
57
+ end
58
+ @client = AndSon.new(@host, @port)
59
+ end
60
+
61
+ should "raise a bad request error" do
62
+ self.run_test_server(@test_server) do
63
+
64
+ assert_raises(AndSon::BadRequestError) do
65
+ @client.call(@service_name)
66
+ end
67
+
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ class NotFoundRequestTests < UsingTestServerSetupTests
74
+ desc "when making a request to a service that returns a 404"
75
+ setup do
76
+ @service_name = Factory.string
77
+ @test_server.add_handler(@service_name) do |params|
78
+ [404, Factory.string]
79
+ end
80
+ @client = AndSon.new(@host, @port)
81
+ end
82
+
83
+ should "raise a not found error" do
84
+ self.run_test_server(@test_server) do
85
+
86
+ assert_raises(AndSon::NotFoundError) do
87
+ @client.call(@service_name)
88
+ end
89
+
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ class ClientErrorRequestTests < UsingTestServerSetupTests
96
+ desc "when making a request to a service that returns a 4XX"
97
+ setup do
98
+ @service_name = Factory.string
99
+ @test_server.add_handler(@service_name) do |params|
100
+ code = Factory.integer(99) + 400
101
+ [code, Factory.string]
102
+ end
103
+ @client = AndSon.new(@host, @port)
104
+ end
105
+
106
+ should "raise a client error" do
107
+ self.run_test_server(@test_server) do
108
+
109
+ assert_raises(AndSon::ClientError) do
110
+ @client.call(@service_name)
111
+ end
112
+
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ class ServerErrorRequestTests < UsingTestServerSetupTests
119
+ desc "when making a request to a service that returns a 4XX"
120
+ setup do
121
+ @service_name = Factory.string
122
+ @test_server.add_handler(@service_name) do |params|
123
+ code = Factory.integer(99) + 500
124
+ [code, Factory.string]
125
+ end
126
+ @client = AndSon.new(@host, @port)
127
+ end
128
+
129
+ should "raise a server error" do
130
+ self.run_test_server(@test_server) do
131
+
132
+ assert_raises(AndSon::ServerError) do
133
+ @client.call(@service_name)
134
+ end
135
+
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+ class TimeoutRequestTests < UsingTestServerSetupTests
142
+ desc "when making a request to a service that takes to long to respond"
143
+ setup do
144
+ @service_name = Factory.string
145
+ @test_server.add_handler(@service_name) do |params|
146
+ sleep 0.2
147
+ [200, Factory.string]
148
+ end
149
+ @client = AndSon.new(@host, @port).timeout(0.1)
150
+ end
151
+
152
+ should "raise a timeout error" do
153
+ self.run_test_server(@test_server) do
154
+
155
+ assert_raises(Sanford::Protocol::TimeoutError) do
156
+ @client.call(@service_name)
157
+ end
158
+
159
+ end
160
+ end
161
+
162
+ end
163
+
164
+ class StoredResponseTests < SystemTests
165
+ desc "with stored responses"
166
+ setup do
167
+ ENV['ANDSON_TEST_MODE'] = 'yes'
168
+
169
+ @client = AndSon.new(@host, @port)
170
+
171
+ @service_name = Factory.string
172
+ @service_params = { Factory.string => Factory.string }
173
+ @response_data = Factory.string
174
+
175
+ @client.add_response(@service_name){ |r| r.code = 500 }
176
+ @client.add_response(@service_name).with(@service_params){ @response_data }
177
+ end
178
+ teardown do
179
+ ENV.delete('ANDSON_TEST_MODE')
180
+ end
181
+
182
+ should "return the configured response when the name and params match" do
183
+ @client.call(@service_name, @service_params) do |r|
184
+ assert_equal @response_data, r.data
185
+ end
186
+ end
187
+
188
+ should "return a configured response when only the name matches" do
189
+ @client.call(@service_name, { Factory.string => Factory.string }) do |r|
190
+ assert_equal 500, r.code
191
+ assert_not_equal @response_data, r.data
192
+ end
193
+ end
194
+
195
+ should "return a default response when the name and params don't match" do
196
+ @client.call(Factory.string, { Factory.string => Factory.string }) do |r|
197
+ assert_equal 200, r.code
198
+ assert_nil r.message
199
+ assert_equal({}, r.data)
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+ end
@@ -29,6 +29,7 @@ class AndSon::CallRunner
29
29
  subject{ @call_runner }
30
30
 
31
31
  should have_readers :host, :port
32
+ should have_readers :before_call_procs, :after_call_procs
32
33
  should have_accessors :params_value, :timeout_value, :logger_value
33
34
  should have_imeths :call_runner
34
35
 
@@ -37,10 +38,12 @@ class AndSon::CallRunner
37
38
  assert_equal @port, subject.port
38
39
  end
39
40
 
40
- should "default its params, timeout and logger" do
41
+ should "default its params, timeout, logger and callbacks" do
41
42
  assert_equal({}, subject.params_value)
42
43
  assert_equal 60, subject.timeout_value
43
44
  assert_instance_of NullLogger, subject.logger_value
45
+ assert_equal [], subject.before_call_procs
46
+ assert_equal [], subject.after_call_procs
44
47
  end
45
48
 
46
49
  should "return itself using `call_runner`" do
@@ -97,6 +100,7 @@ class AndSon::CallRunner
97
100
  class InstanceMethodsTests < InitTests
98
101
 
99
102
  should have_imeths :timeout, :params, :logger
103
+ should have_imeths :before_call, :after_call
100
104
 
101
105
  should "set its timeout value and return its call runner using `timeout`" do
102
106
  timeout_value = Factory.integer
@@ -136,6 +140,28 @@ class AndSon::CallRunner
136
140
  assert_same subject, result
137
141
  end
138
142
 
143
+ should "add a before call proc using `before_call`" do
144
+ callback = proc{ Factory.string }
145
+ result = subject.before_call(&callback)
146
+ assert_equal [callback], subject.before_call_procs
147
+
148
+ other_callback = proc{ Factory.string }
149
+ result = subject.before_call(&other_callback)
150
+ assert_equal 2, subject.before_call_procs.size
151
+ assert_equal other_callback, subject.before_call_procs.last
152
+ end
153
+
154
+ should "add an after call proc using `after_call`" do
155
+ callback = proc{ Factory.string }
156
+ result = subject.after_call(&callback)
157
+ assert_equal [callback], subject.after_call_procs
158
+
159
+ other_callback = proc{ Factory.string }
160
+ result = subject.after_call(&other_callback)
161
+ assert_equal 2, subject.after_call_procs.size
162
+ assert_equal other_callback, subject.after_call_procs.last
163
+ end
164
+
139
165
  end
140
166
 
141
167
  class CallSetupTests < InitTests
@@ -158,23 +184,35 @@ class AndSon::CallRunner
158
184
  class CallTests < CallSetupTests
159
185
  desc "call method"
160
186
  setup do
161
- @call_bang_name = nil
162
- @call_bang_params = nil
163
- @call_bang_called = false
164
- Assert.stub(@call_runner, :call!) do |name, params|
165
- @call_bang_name = name
166
- @call_bang_params = params
167
- @call_bang_called = true
168
- @response
169
- end
187
+ @fake_connection = FakeConnection.new
188
+ @fake_connection.peek_data = Factory.string(1)
189
+ @fake_connection.read_data = @protocol_response.to_hash
190
+ Assert.stub(AndSon::Connection, :new).with(@host, @port){ @fake_connection }
170
191
  end
171
192
 
172
- should "call `call!`" do
173
- assert_false @call_bang_called
193
+ should "open a connection, write a request and close the write stream" do
174
194
  subject.call(@name, @params)
175
- assert_equal @name, @call_bang_name
176
- assert_equal @params, @call_bang_params
177
- assert_true @call_bang_called
195
+
196
+ protocol_connection = @fake_connection.protocol_connection
197
+ exp = Sanford::Protocol::Request.new(@name, @params).to_hash
198
+ assert_equal exp, protocol_connection.write_data
199
+ assert_true protocol_connection.closed_write
200
+ end
201
+
202
+ should "build a response from reading the server response on the connection" do
203
+ response_data = subject.call(@name, @params)
204
+
205
+ protocol_connection = @fake_connection.protocol_connection
206
+ assert_equal @call_runner.timeout_value, protocol_connection.peek_timeout
207
+ assert_equal @call_runner.timeout_value, protocol_connection.read_timeout
208
+ assert_equal @response.data, response_data
209
+ end
210
+
211
+ should "raise a connection closed error if the server doesn't write a response" do
212
+ @fake_connection.peek_data = "" # simulate the server not writing a response
213
+ assert_raise(AndSon::ConnectionClosedError) do
214
+ subject.call(@name, @params)
215
+ end
178
216
  end
179
217
 
180
218
  should "return the response data when a block isn't provided" do
@@ -190,7 +228,71 @@ class AndSon::CallRunner
190
228
 
191
229
  should "default its params when they aren't provided" do
192
230
  subject.call(@name)
193
- assert_equal({}, @call_bang_params)
231
+
232
+ protocol_connection = @fake_connection.protocol_connection
233
+ exp = Sanford::Protocol::Request.new(@name, {}).to_hash
234
+ assert_equal exp, protocol_connection.write_data
235
+ end
236
+
237
+ should "merge the passed params with its params value" do
238
+ subject.params({ Factory.string => Factory.string })
239
+ merged_params = subject.params_value.merge(@params)
240
+ subject.call(@name, @params)
241
+
242
+ protocol_connection = @fake_connection.protocol_connection
243
+ exp = Sanford::Protocol::Request.new(@name, merged_params).to_hash
244
+ assert_equal exp, protocol_connection.write_data
245
+ end
246
+
247
+ should "run before call procs" do
248
+ yielded_name = nil
249
+ yielded_params = nil
250
+ yielded_runner = nil
251
+ subject.before_call do |name, params, call_runner|
252
+ yielded_name = name
253
+ yielded_params = params
254
+ yielded_runner = call_runner
255
+ end
256
+
257
+ subject.call(@name, @params)
258
+ assert_equal @name, yielded_name
259
+ assert_equal @params, yielded_params
260
+ assert_same subject, yielded_runner
261
+ end
262
+
263
+ should "run after call procs" do
264
+ yielded_name = nil
265
+ yielded_params = nil
266
+ yielded_runner = nil
267
+ subject.after_call do |name, params, call_runner|
268
+ yielded_name = name
269
+ yielded_params = params
270
+ yielded_runner = call_runner
271
+ end
272
+
273
+ subject.call(@name, @params)
274
+ assert_equal @name, yielded_name
275
+ assert_equal @params, yielded_params
276
+ assert_same subject, yielded_runner
277
+ end
278
+
279
+ should "run callbacks in the correct order" do
280
+ n = 0
281
+ before_call_num = nil
282
+ after_call_num = nil
283
+ call_num = nil
284
+ subject.before_call{ before_call_num = n += 1 }
285
+ subject.after_call{ after_call_num = n += 1 }
286
+ # the connection should be created between the callbacks
287
+ Assert.stub(AndSon::Connection, :new).with(@host, @port) do
288
+ call_num = n += 1
289
+ @fake_connection
290
+ end
291
+
292
+ subject.call(@name, @params)
293
+ assert_equal 1, before_call_num
294
+ assert_equal 2, call_num
295
+ assert_equal 3, after_call_num
194
296
  end
195
297
 
196
298
  should "log a summary line of the call" do
@@ -211,45 +313,6 @@ class AndSon::CallRunner
211
313
 
212
314
  end
213
315
 
214
- class CallBangTests < CallSetupTests
215
- desc "the call! method"
216
- setup do
217
- @call_runner.params({ Factory.string => Factory.string })
218
-
219
- @fake_connection = FakeConnection.new
220
- @fake_connection.peek_data = Factory.string(1)
221
- @fake_connection.read_data = @protocol_response.to_hash
222
- Assert.stub(AndSon::Connection, :new).with(@host, @port){ @fake_connection }
223
- end
224
-
225
- should "open a connection, write a request and close the write stream" do
226
- subject.call!(@name, @params)
227
-
228
- protocol_connection = @fake_connection.protocol_connection
229
- params = @call_runner.params_value.merge(@params)
230
- expected = Sanford::Protocol::Request.new(@name, params).to_hash
231
- assert_equal expected, protocol_connection.write_data
232
- assert_true protocol_connection.closed_write
233
- end
234
-
235
- should "build a response from reading the server response on the connection" do
236
- response = subject.call!(@name, @params)
237
-
238
- protocol_connection = @fake_connection.protocol_connection
239
- assert_equal @call_runner.timeout_value, protocol_connection.peek_timeout
240
- assert_equal @call_runner.timeout_value, protocol_connection.read_timeout
241
- assert_equal @response, response
242
- end
243
-
244
- should "raise a connection closed error if the server doesn't write a response" do
245
- @fake_connection.peek_data = "" # simulate the server not writing a response
246
- assert_raise(AndSon::ConnectionClosedError) do
247
- subject.call!(@name, @params)
248
- end
249
- end
250
-
251
- end
252
-
253
316
  class FakeConnection
254
317
  attr_reader :protocol_connection
255
318
 
@@ -6,14 +6,14 @@ module AndSon::Client
6
6
  class UnitTests < Assert::Context
7
7
  desc "AndSon::Client"
8
8
  setup do
9
- @current_timeout = ENV['ANDSON_TEST_MODE']
9
+ @current_test_mode = ENV['ANDSON_TEST_MODE']
10
10
  ENV['ANDSON_TEST_MODE'] = 'yes'
11
11
 
12
12
  @host = Factory.string
13
13
  @port = Factory.integer
14
14
  end
15
15
  teardown do
16
- ENV['ANDSON_TEST_MODE'] = @current_timeout
16
+ ENV['ANDSON_TEST_MODE'] = @current_test_mode
17
17
  end
18
18
  subject{ AndSon::Client }
19
19
 
@@ -127,22 +127,23 @@ module AndSon::Client
127
127
  @params = { Factory.string => Factory.string }
128
128
 
129
129
  @client = AndSon::TestClient.new(@host, @port)
130
- data = Factory.string
131
- @client.add_response(@name, @params){ data }
132
- @response = @client.responses.get(@name, @params)
133
130
  end
134
131
  subject{ @client }
135
132
 
136
- should have_accessors :timeout_value, :params_value, :logger_value
137
133
  should have_readers :calls, :responses
138
- should have_imeths :add_response, :remove_response, :reset
134
+ should have_readers :before_call_procs, :after_call_procs
135
+ should have_accessors :timeout_value, :params_value, :logger_value
136
+ should have_imeths :add_response, :remove_responses, :reset
139
137
 
140
- should "default its params value" do
141
- assert_equal({}, subject.params_value)
138
+ should "know its calls and stored responses" do
139
+ assert_equal [], subject.calls
140
+ assert_instance_of AndSon::StoredResponses, subject.responses
142
141
  end
143
142
 
144
- should "know its stored responses" do
145
- assert_instance_of AndSon::StoredResponses, subject.responses
143
+ should "default its params and callbacks" do
144
+ assert_equal({}, subject.params_value)
145
+ assert_equal [], subject.before_call_procs
146
+ assert_equal [], subject.after_call_procs
146
147
  end
147
148
 
148
149
  should "know its call runner" do
@@ -158,38 +159,106 @@ module AndSon::Client
158
159
  assert_instance_of AndSon::TestClient::Call, call
159
160
  assert_equal @name, call.request_name
160
161
  assert_equal @params, call.request_params
161
- assert_equal @response.protocol_response, call.response
162
+ assert_instance_of Sanford::Protocol::Response, call.response
162
163
  end
163
164
 
164
- should "return a stored response using `call`" do
165
- assert_equal @response.data, subject.call(@name, @params)
165
+ should "return a stored response's data using `call`" do
166
+ exp = subject.responses.get(@name, @params)
167
+ assert_equal exp.data, subject.call(@name, @params)
166
168
  end
167
169
 
168
170
  should "yield a stored response using `call` with a block" do
169
171
  yielded = nil
170
172
  subject.call(@name, @params){ |response| yielded = response }
171
- assert_equal @response.protocol_response, yielded
173
+ exp = subject.responses.get(@name, @params)
174
+ assert_equal exp.protocol_response, yielded
175
+ end
176
+
177
+ should "run before call procs" do
178
+ subject.params({ Factory.string => Factory.string })
179
+ yielded_name = nil
180
+ yielded_params = nil
181
+ yielded_runner = nil
182
+ subject.before_call do |name, params, call_runner|
183
+ yielded_name = name
184
+ yielded_params = params
185
+ yielded_runner = call_runner
186
+ end
187
+
188
+ subject.call(@name, @params)
189
+ assert_equal @name, yielded_name
190
+ exp = subject.params_value.merge(@params)
191
+ assert_equal exp, yielded_params
192
+ assert_same subject, yielded_runner
193
+ end
194
+
195
+ should "run after call procs" do
196
+ subject.params({ Factory.string => Factory.string })
197
+ yielded_name = nil
198
+ yielded_params = nil
199
+ yielded_runner = nil
200
+ subject.after_call do |name, params, call_runner|
201
+ yielded_name = name
202
+ yielded_params = params
203
+ yielded_runner = call_runner
204
+ end
205
+
206
+ subject.call(@name, @params)
207
+ assert_equal @name, yielded_name
208
+ exp = subject.params_value.merge(@params)
209
+ assert_equal exp, yielded_params
210
+ assert_same subject, yielded_runner
211
+ end
212
+
213
+ should "run callbacks in the correct order" do
214
+ n = 0
215
+ before_call_num = nil
216
+ after_call_num = nil
217
+ subject.before_call{ before_call_num = n += 1 }
218
+ subject.after_call{ after_call_num = n += 1 }
219
+
220
+ subject.call(@name, @params)
221
+ assert_equal 1, before_call_num
222
+ assert_equal 2, after_call_num
172
223
  end
173
224
 
174
225
  should "allow adding/removing stored responses" do
175
226
  data = Factory.string
176
- subject.add_response(@name, @params){ data }
227
+ subject.add_response(@name).with(@params){ data }
177
228
  response = subject.responses.get(@name, @params)
178
229
  assert_equal data, response.data
179
230
 
180
- subject.remove_response(@name, @params)
231
+ subject.remove_responses(@name)
232
+ response = subject.responses.get(@name, @params)
233
+ assert_not_equal data, response.data
234
+ end
235
+
236
+ should "return a stored response stub using `add_response`" do
237
+ stub = subject.add_response(@name)
238
+ assert_instance_of AndSon::StoredResponses::Stub, stub
239
+
240
+ data = Factory.string
241
+ stub.with(@params){ data }
181
242
  response = subject.responses.get(@name, @params)
243
+ assert_equal data, response.data
244
+
245
+ response = subject.responses.get(@name, {
246
+ Factory.string => Factory.string
247
+ })
182
248
  assert_not_equal data, response.data
183
249
  end
184
250
 
185
251
  should "clear its calls and remove all its configured responses using `reset`" do
186
252
  subject.call(@name, @params)
187
- assert_not_equal [], subject.calls
188
- assert_equal @response, subject.responses.get(@name, @params)
253
+ data = Factory.string
254
+ subject.add_response(@name).with(@params){ data }
255
+
256
+ assert_not_empty subject.calls
257
+ assert_equal data, subject.responses.get(@name, @params).data
189
258
 
190
259
  subject.reset
191
- assert_equal [], subject.calls
192
- assert_not_equal @response, subject.responses.get(@name, @params)
260
+ assert_empty subject.calls
261
+ assert_not_equal data, subject.responses.get(@name, @params).data
193
262
  end
194
263
 
195
264
  should "be comparable" do
@@ -17,42 +17,50 @@ class AndSon::StoredResponses
17
17
  should have_imeths :add, :get, :remove, :remove_all
18
18
 
19
19
  should "allow adding and getting responses with response data" do
20
- subject.add(@name, @params){ @response_data }
21
- protocol_response = subject.get(@name, @params).protocol_response
20
+ subject.add(@name){ @response_data }
21
+ protocol_response = subject.get(@name, {}).protocol_response
22
+
22
23
  assert_equal 200, protocol_response.code
23
24
  assert_nil protocol_response.status.message
24
25
  assert_equal @response_data, protocol_response.data
25
26
  end
26
27
 
27
- should "allow adding and gettings responses being yielded a response" do
28
- code = Factory.integer
28
+ should "allow adding and getting responses when yielded a response" do
29
+ code = Factory.integer
29
30
  message = Factory.string
30
- data = Factory.string
31
+ data = Factory.string
31
32
 
32
33
  yielded = nil
33
- subject.add(@name, @params) do |response|
34
+ subject.add(@name) do |response|
34
35
  yielded = response
35
- response.code = code
36
+ response.code = code
36
37
  response.message = message
37
- response.data = data
38
+ response.data = data
38
39
  end
39
- protocol_response = subject.get(@name, @params).protocol_response
40
+ protocol_response = subject.get(@name, {}).protocol_response
40
41
 
41
42
  assert_instance_of Sanford::Protocol::Response, yielded
42
- assert_equal code, protocol_response.code
43
+ assert_equal code, protocol_response.code
43
44
  assert_equal message, protocol_response.message
44
- assert_equal data, protocol_response.data
45
+ assert_equal data, protocol_response.data
45
46
  end
46
47
 
47
- should "allow adding and getting responses with no params" do
48
- subject.add(@name){ @response_data }
49
- protocol_response = subject.get(@name).protocol_response
50
- assert_equal @response_data, protocol_response.data
51
- end
48
+ should "return a stub when adding a response" do
49
+ stub = subject.add(@name)
50
+ assert_instance_of AndSon::StoredResponses::Stub, stub
52
51
 
53
- should "return a default response for a name/params that isn't configured" do
52
+ stub.with(@params){ @response_data }
54
53
  response = subject.get(@name, @params)
54
+ assert_equal @response_data, response.data
55
+
56
+ response = subject.get(@name, {})
57
+ assert_not_equal @response_data, response.data
58
+ end
59
+
60
+ should "return a default response for a service that isn't configured" do
61
+ response = subject.get(@name, {})
55
62
  protocol_response = response.protocol_response
63
+
56
64
  assert_equal 200, protocol_response.code
57
65
  assert_nil protocol_response.status.message
58
66
  assert_equal({}, protocol_response.data)
@@ -62,41 +70,81 @@ class AndSon::StoredResponses
62
70
  called = false
63
71
  subject.add(@name){ called = true }
64
72
  assert_false called
65
- subject.get(@name)
73
+ subject.get(@name, {})
66
74
  assert_true called
67
75
  end
68
76
 
69
- should "allow removing a response" do
70
- subject.add(@name, @params){ @response_data }
71
- protocol_response = subject.get(@name, @params).protocol_response
72
- assert_equal @response_data, protocol_response.data
73
-
74
- subject.remove(@name, @params)
75
- protocol_response = subject.get(@name, @params).protocol_response
76
- assert_not_equal @response_data, protocol_response.data
77
- end
78
-
79
- should "allow removing a response without params" do
77
+ should "allow removing a stub" do
80
78
  subject.add(@name){ @response_data }
81
- protocol_response = subject.get(@name).protocol_response
79
+ protocol_response = subject.get(@name, {}).protocol_response
82
80
  assert_equal @response_data, protocol_response.data
83
81
 
84
82
  subject.remove(@name)
85
- protocol_response = subject.get(@name).protocol_response
83
+ protocol_response = subject.get(@name, {}).protocol_response
86
84
  assert_not_equal @response_data, protocol_response.data
87
85
  end
88
86
 
89
87
  should "allow removing all responses" do
90
- subject.add(@name, @params){ @response_data }
91
88
  subject.add(@name){ @response_data }
89
+ other_name = Factory.string
90
+ subject.add(other_name){ @response_data }
92
91
 
93
92
  subject.remove_all
94
- protocol_response = subject.get(@name, @params).protocol_response
93
+ protocol_response = subject.get(@name, {}).protocol_response
95
94
  assert_not_equal @response_data, protocol_response.data
96
- protocol_response = subject.get(@name).protocol_response
95
+ protocol_response = subject.get(other_name, {}).protocol_response
97
96
  assert_not_equal @response_data, protocol_response.data
98
97
  end
99
98
 
100
99
  end
101
100
 
101
+ class StubTests < UnitTests
102
+ desc "Stub"
103
+ setup do
104
+ @stub = Stub.new
105
+ end
106
+ subject{ @stub }
107
+
108
+ should have_readers :hash
109
+ should have_imeths :set_default_proc, :with, :call
110
+
111
+ should "default its default response proc" do
112
+ response = subject.call(@params)
113
+ assert_equal({}, response.data)
114
+ end
115
+
116
+ should "allow settings its default proc" do
117
+ data = Factory.string
118
+ subject.set_default_proc{ |r| r.data = data }
119
+ response = subject.call(@params)
120
+ assert_equal data, response.data
121
+ end
122
+
123
+ should "allow setting responses for specific params" do
124
+ response = subject.call(@params)
125
+ assert_equal({}, response.data)
126
+
127
+ data = Factory.string
128
+ subject.with(@params){ |r| r.data = data }
129
+ response = subject.call(@params)
130
+ assert_equal data, response.data
131
+ end
132
+
133
+ should "yield a response when a response block expects an arg" do
134
+ yielded = nil
135
+ subject.with(@params){ |r| yielded = r }
136
+ exp = Sanford::Protocol::Response.new(200, {})
137
+ assert_equal exp, subject.call(@params)
138
+ assert_equal exp, yielded
139
+ end
140
+
141
+ should "set a response data when the response block doesn't expect an arg" do
142
+ data = Factory.string
143
+ subject.with(@params){ data }
144
+ exp = Sanford::Protocol::Response.new(200, data)
145
+ assert_equal exp, subject.call(@params)
146
+ end
147
+
148
+ end
149
+
102
150
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: and-son
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 63
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 7
8
+ - 8
9
9
  - 0
10
- version: 0.7.0
10
+ version: 0.8.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Collin Redding
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2014-09-29 00:00:00 Z
19
+ date: 2014-12-18 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  requirement: &id001 !ruby/object:Gem::Requirement
@@ -74,8 +74,8 @@ files:
74
74
  - lib/and-son/version.rb
75
75
  - test/helper.rb
76
76
  - test/support/factory.rb
77
- - test/support/fake_server.rb
78
- - test/system/making_requests_tests.rb
77
+ - test/support/test_server.rb
78
+ - test/system/client_tests.rb
79
79
  - test/unit/and-son_tests.rb
80
80
  - test/unit/call_runner_tests.rb
81
81
  - test/unit/client_tests.rb
@@ -117,8 +117,8 @@ summary: Simple Sanford client for Ruby.
117
117
  test_files:
118
118
  - test/helper.rb
119
119
  - test/support/factory.rb
120
- - test/support/fake_server.rb
121
- - test/system/making_requests_tests.rb
120
+ - test/support/test_server.rb
121
+ - test/system/client_tests.rb
122
122
  - test/unit/and-son_tests.rb
123
123
  - test/unit/call_runner_tests.rb
124
124
  - test/unit/client_tests.rb
@@ -1,194 +0,0 @@
1
- require 'assert'
2
- require 'and-son'
3
-
4
- require 'test/support/fake_server'
5
-
6
- class MakingRequestsTests < Assert::Context
7
- include FakeServer::Helper
8
-
9
- desc "making a request that"
10
- setup do
11
- @fake_server = FakeServer.new(12000)
12
- end
13
-
14
- class SuccessTests < MakingRequestsTests
15
- desc "returns a successful response"
16
- setup do
17
- @fake_server.add_handler('echo'){|params| [ 200, params['message'] ] }
18
- end
19
-
20
- should "get a 200 response with the parameter echoed back" do
21
- self.run_fake_server(@fake_server) do
22
-
23
- client = AndSon.new('localhost', 12000)
24
- client.call('echo', :message => 'test') do |response|
25
- assert_equal 200, response.status.code
26
- assert_equal nil, response.status.message
27
- assert_equal 'test', response.data
28
- end
29
-
30
- end
31
- end
32
-
33
- end
34
-
35
- class WithStoredResponsesTests < MakingRequestsTests
36
- desc "is stored with and-son and with testing ENV var set"
37
- setup do
38
- ENV['ANDSON_TEST_MODE'] = 'yes'
39
- end
40
- teardown do
41
- ENV.delete('ANDSON_TEST_MODE')
42
- end
43
-
44
- should "return the registered response" do
45
- client = AndSon.new('localhost', 12000)
46
- client.add_response('echo', 'message' => 'test'){ 'test' }
47
-
48
- client.call('echo', 'message' => 'test') do |response|
49
- assert_equal 200, response.code
50
- assert_equal nil, response.status.message
51
- assert_equal 'test', response.data
52
- end
53
- end
54
-
55
- end
56
-
57
- class AuthorizeTests < MakingRequestsTests
58
- setup do
59
- @fake_server.add_handler('authorize_it') do |params|
60
- if params['api_key'] == 12345
61
- [ 200, params['data'] ]
62
- else
63
- [ 401, params['data'] ]
64
- end
65
- end
66
- end
67
-
68
- should "get a 200 response when api_key is passed with the correct value" do
69
- self.run_fake_server(@fake_server) do
70
-
71
- client = AndSon.new('localhost', 12000).params({ 'api_key' => 12345 })
72
- client.call('authorize_it', { 'data' => 'holla' }) do |response|
73
- assert_equal 200, response.status.code
74
- assert_equal nil, response.status.message
75
- assert_equal 'holla', response.data
76
- end
77
-
78
- end
79
- end
80
-
81
- should "get a 401 response when api_key isn't passed" do
82
- self.run_fake_server(@fake_server) do
83
-
84
- client = AndSon.new('localhost', 12000)
85
- client.call('authorize_it', { 'data' => 'holla' }) do |response|
86
- assert_equal 401, response.status.code
87
- assert_equal nil, response.status.message
88
- assert_equal 'holla', response.data
89
- end
90
-
91
- end
92
- end
93
-
94
- end
95
-
96
- class Failure400Tests < MakingRequestsTests
97
- desc "when a request fails with a 400"
98
- setup do
99
- @fake_server.add_handler('400'){|params| [ 400, false ] }
100
- end
101
-
102
- should "raise a bad request error" do
103
- self.run_fake_server(@fake_server) do
104
-
105
- assert_raises(AndSon::BadRequestError) do
106
- client = AndSon.new('localhost', 12000)
107
- client.call('400')
108
- end
109
-
110
- end
111
- end
112
-
113
- end
114
-
115
- class Failure404Tests < MakingRequestsTests
116
- desc "when a request fails with a 404"
117
- setup do
118
- @fake_server.add_handler('404'){|params| [ 404, false ] }
119
- end
120
-
121
- should "raise a not found error" do
122
- self.run_fake_server(@fake_server) do
123
-
124
- assert_raises(AndSon::NotFoundError) do
125
- client = AndSon.new('localhost', 12000)
126
- client.call('404')
127
- end
128
-
129
- end
130
- end
131
-
132
- end
133
-
134
- class Failure4xxTests < MakingRequestsTests
135
- desc "when a request fails with a 4xx"
136
- setup do
137
- @fake_server.add_handler('4xx'){|params| [ 402, false ] }
138
- end
139
-
140
- should "raise a client error" do
141
- self.run_fake_server(@fake_server) do
142
-
143
- assert_raises(AndSon::ClientError) do
144
- client = AndSon.new('localhost', 12000)
145
- client.call('4xx')
146
- end
147
-
148
- end
149
- end
150
-
151
- end
152
-
153
- class Failure5xxTests < MakingRequestsTests
154
- desc "when a request fails with a 5xx"
155
- setup do
156
- @fake_server.add_handler('5xx'){|params| [ 500, false ] }
157
- end
158
-
159
- should "raise a server error" do
160
- self.run_fake_server(@fake_server) do
161
-
162
- assert_raises(AndSon::ServerError) do
163
- client = AndSon.new('localhost', 12000)
164
- client.call('5xx')
165
- end
166
-
167
- end
168
- end
169
-
170
- end
171
-
172
- class TimeoutErrorTests < MakingRequestsTests
173
- desc "when a request takes to long to respond"
174
- setup do
175
- @fake_server.add_handler('forever') do |params|
176
- sleep 0.2
177
- [ 200, true ]
178
- end
179
- end
180
-
181
- should "raise a timeout error" do
182
- self.run_fake_server(@fake_server) do
183
-
184
- assert_raises(Sanford::Protocol::TimeoutError) do
185
- client = AndSon.new('localhost', 12000)
186
- client.timeout(0.1).call('forever')
187
- end
188
-
189
- end
190
- end
191
-
192
- end
193
-
194
- end