and-son 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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