hoodoo 1.10.0 → 1.11.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjU2MjRlMTgwYjU3ZDdhOTBhZjk4M2E5NGEwZjk5Mjg4MDM0YjMyMw==
4
+ Y2FmMmNkOGIxNmI3Yjc3Njk2ZGU4MmJlMzVkZDkyYWQ2ZGI2NGNiNQ==
5
5
  data.tar.gz: !binary |-
6
- YWFhZjNkZGJkNDMyZDI1NmE4NDk0NGQyMzAxNGFkMDZlMWU0NzRkMw==
6
+ YWNkMjFhNmMwODQ2OGYxYjZmNDI1ZGIxZGJmNzg3YjQyY2I5ZDMxYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZDBiYjhmNDc5OTQ2ODAyNjI5NzU3YzY0YjE4MmQzYTRiMjRkY2NmYjdkZDJl
10
- N2UxYThkMDhiMzBjMmQ4YWQ1YjcyMDhlMjM2ZDVjNjhiNGJhMTg4ZjgzZTg1
11
- MDA0NWQ1OWZmMWM0MzhlNDkzZmNjODM4ZTdkOTUxMTQzYmFmNGY=
9
+ ZWJjN2JjMjA3Zjc1YTRmMzYwN2ZkODYyMzE4M2I2N2VkOTg4M2I1MDBjMDhj
10
+ ZGE3N2RhNWZlOGMwMDQ2MWVmNzNhMzQ3MWEwZTRiZDhjMjBkMDNjNDdhZjdh
11
+ ZjYxOGUwYTk1NDFlYTJmY2VhNGYxYWI5ODk5YzdmNDNkOThjYTE=
12
12
  data.tar.gz: !binary |-
13
- Y2UyY2ZhMDM1YTRlOTg5ODlmNzYwZDMyNGQyMTRiNjY1NmY3ZDdhYjAwN2Y1
14
- NmQxNDQ0NmQ1ZDUxZDA4YzgzZGI1YjdkODY4YTViZjc4MWMwNzVlZmNhM2E4
15
- MmY3MDlmZTFhZTBhZTAxYWVkODQ4NWFmYTJkOGQwOWMzNDIzMTE=
13
+ MmQzNzQxZWI0OTQ2YjI2Nzg1ODAxMzA0ODVlNmM0ODRmMTE2YTY0YmEwYzA2
14
+ YTdjMzZkMTY4NWRlNjlmMzdhNTc1NDdiYWM4OTQ1YjNkNzQzNjYzZTlmNDFl
15
+ Nzc3Mzk5ZmFhMDIxOTk0NmY2MzIyMTc2MGQ2YjFlYWQ5MDQxMGQ=
data/lib/hoodoo/client.rb CHANGED
@@ -10,6 +10,7 @@
10
10
  require 'hoodoo/client/headers'
11
11
 
12
12
  require 'hoodoo/client/augmented_base'
13
+ require 'hoodoo/client/paginated_enumeration'
13
14
  require 'hoodoo/client/augmented_hash'
14
15
  require 'hoodoo/client/augmented_array'
15
16
 
@@ -17,6 +17,7 @@ module Hoodoo
17
17
  #
18
18
  class AugmentedArray < ::Array
19
19
  include Hoodoo::Client::AugmentedBase
20
+ include Hoodoo::Client::PaginatedEnumeration
20
21
 
21
22
  # For lists, the (optional) total size of the data set, of which
22
23
  # the contents of this Array will often only represent a single
@@ -314,6 +314,35 @@ module Hoodoo
314
314
  end
315
315
  end
316
316
 
317
+ # Set the +augmented_array+'s +next_page_proc+ attribute to a Proc that
318
+ # will call the list endpoint to retrieve the next batch of of Resources
319
+ # using the same query parameters.
320
+ #
321
+ # +augmented_array+:: The Hoodoo::Client::AugmentedArray instance
322
+ # containing the initial set of Resources to
323
+ # be enumerated through.
324
+ #
325
+ # +query_hash+:: The query parameters to be used for this
326
+ # enumeration. See the constructor for more.
327
+ #
328
+ # Returns the +augmented_array+ passed in, with the +next_page_proc+
329
+ # value set.
330
+ #
331
+ def inject_enumeration_state ( augmented_array, query_hash )
332
+
333
+ endpoint = self
334
+ query_hash = query_hash.nil? ? {} : query_hash.dup
335
+ batch_size = [ 1, augmented_array.size ].max
336
+ augmented_array.next_page_proc = Proc.new do
337
+ query_hash[ :offset ] = ( query_hash[ :offset ] || 0 ) + batch_size
338
+ endpoint.list( query_hash )
339
+ end
340
+
341
+ return augmented_array
342
+
343
+ end
344
+
345
+
317
346
  public
318
347
 
319
348
  # Obtain a list of resource instance representations.
@@ -337,6 +366,9 @@ module Hoodoo
337
366
  # satisfying the list conditions were found. The array contents
338
367
  # are undefined in the case of errors.
339
368
  #
369
+ # Call Hoodoo::Client::PaginatedEnumeration#enumerate_all to enumerate
370
+ # over the list of resource instances with automatic pagination.
371
+ #
340
372
  def list( query_hash = nil )
341
373
  raise "Subclasses must implement Hoodoo::Client::Endpoint\#list"
342
374
  end
@@ -50,7 +50,7 @@ module Hoodoo
50
50
  d.action = :list
51
51
  d.query_hash = query_hash
52
52
 
53
- return do_http( d )
53
+ return inject_enumeration_state( do_http( d ), query_hash )
54
54
  end
55
55
 
56
56
  # See Hoodoo::Client::Endpoint#show.
@@ -0,0 +1,94 @@
1
+ ########################################################################
2
+ # File:: paginated_enumeration.rb
3
+ # (C):: Loyalty New Zealand 2016
4
+ #
5
+ # Purpose:: A module that adds support for enumeration over paginated
6
+ # resources.
7
+ # ----------------------------------------------------------------------
8
+ # 29-Sep-2016 (DJO): Created.
9
+ ########################################################################
10
+
11
+ module Hoodoo
12
+ class Client # Just used as a namespace here
13
+
14
+ # Ruby mixin providing an enumeration mechanism, allowing the
15
+ # caller to iterate over all the resource instances in the list,
16
+ # automatically performing the necessary pagination behind the scenes.
17
+ #
18
+ module PaginatedEnumeration
19
+
20
+ # Proc called by enumerate_all to provide the next 'page' of values
21
+ # to be enumerated through. Returns an Hoodoo::Client::AugmentedArray.
22
+ #
23
+ attr_accessor :next_page_proc
24
+
25
+ # Yields each resource instance, automatically paginating
26
+ # through the entire set of resources.
27
+ #
28
+ # Provide a block to process each resource instance. For example:
29
+ #
30
+ # results = members.list(:search => { :surname => 'Smith' } ).enumerate_all do | member |
31
+ # if member.platform_errors.has_errors?
32
+ # .. deal with error ...
33
+ # break
34
+ # else
35
+ # .. process member ...
36
+ # end
37
+ # end
38
+ #
39
+ # Each iteration yields a Hoodoo::Client::AugmentedHash representation of
40
+ # the requested resource instance. The caller must check for errors on
41
+ # the value yielded with each iteration, as per the example above.
42
+ #
43
+ def enumerate_all
44
+
45
+ raise "Must provide a block to enumerate_all" unless block_given?
46
+
47
+ # The first set of results is in 'this' AugmentedArray
48
+ results = self
49
+
50
+ loop do
51
+
52
+ if results.size > 0
53
+
54
+ if results.platform_errors.has_errors?
55
+ raise "Hoodoo::Client:: PaginatedEnumeration#enumerate_all: Unexpected internal state combination of results set and results error indication"
56
+ end
57
+
58
+ # Yield a resource at a time to the caller
59
+ #
60
+ # Note: An inter-resource call in a single service returns each
61
+ # resource as a Hash, which must be converted to AugmentedHash
62
+ results.each do | result |
63
+ yield to_augmented_hash(result)
64
+ end
65
+ results = next_page_proc.call()
66
+ else
67
+ # Return errors in an (empty) AugmentedHash
68
+ if results.platform_errors.has_errors?
69
+ yield copy_hash_errors_and_options( Hoodoo::Client::AugmentedHash.new, results )
70
+ end
71
+ break
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ private
79
+
80
+ # Convert a Hash to an AugmentedHash
81
+ def to_augmented_hash( src )
82
+ src.is_a?( Hoodoo::Client::AugmentedHash ) ? src : Hoodoo::Client::AugmentedHash[ src ]
83
+ end
84
+
85
+ # Copy the platform_errors and response_options from src -> dest
86
+ def copy_hash_errors_and_options( dest, src )
87
+ dest.set_platform_errors( src.platform_errors )
88
+ dest.response_options = src.response_options.dup if src.response_options
89
+ dest
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -53,7 +53,7 @@ module Hoodoo; module Services
53
53
  # See Hoodoo::Client::Endpoint#list.
54
54
  #
55
55
  def list( query_hash = nil )
56
- return @middleware.inter_resource_local(
56
+ result = @middleware.inter_resource_local(
57
57
  :source_interaction => self.interaction(),
58
58
  :discovery_result => @discovery_result,
59
59
  :endpoint => self,
@@ -62,6 +62,7 @@ module Hoodoo; module Services
62
62
 
63
63
  :query_hash => query_hash
64
64
  )
65
+ return inject_enumeration_state( result, query_hash )
65
66
  end
66
67
 
67
68
  # See Hoodoo::Client::Endpoint#show.
@@ -71,7 +71,7 @@ module Hoodoo
71
71
  def list( query_hash = nil )
72
72
  result = preprocess( :list )
73
73
  result = @wrapped_endpoint.list( query_hash ) if result.nil?
74
- return postprocess( result )
74
+ return inject_enumeration_state( postprocess( result ), query_hash )
75
75
  end
76
76
 
77
77
  # See Hoodoo::Client::Endpoint#show.
@@ -12,6 +12,6 @@ module Hoodoo
12
12
  # The Hoodoo gem version. If this changes, ensure that the date in
13
13
  # "hoodoo.gemspec" is correct and run "bundle install" (or "update").
14
14
  #
15
- VERSION = '1.10.0'
15
+ VERSION = '1.11.0'
16
16
 
17
17
  end
@@ -927,9 +927,21 @@ describe Hoodoo::ActiveRecord::ManuallyDated do
927
927
  # history entries
928
928
  #
929
929
  it 'updates work' do
930
- values = ( '1'..'9' ).to_a
930
+ values = ( '1'..'5' ).to_a
931
931
  threads = []
932
932
 
933
+ # The loop below creates a Thread for each 'value', and each Thread
934
+ # consumes a db connection, so we have to check that the pool is big enough
935
+ # to ensure that each thread gets a connection.
936
+ #
937
+ # A better solution would be to temporarily create a connection pool with
938
+ # more connections in it, but attempts to do that broke other parts of this
939
+ # spec :-(
940
+ #
941
+ expect( ActiveRecord::Base.connection_pool.size ).to be >= values.size
942
+ # Reclaim old, unused connections
943
+ ActiveRecord::Base.connection_pool.reap()
944
+
933
945
  @uuids.each do | uuid |
934
946
  values.each do | value |
935
947
  threads << Thread.new do
@@ -946,9 +958,9 @@ describe Hoodoo::ActiveRecord::ManuallyDated do
946
958
  end
947
959
  end
948
960
  end
961
+ threads.each { | thread | thread.join() }
949
962
  end
950
963
 
951
- threads.each { | thread | thread.join() }
952
964
 
953
965
  @uuids.each do | uuid |
954
966
  contemporary = RSpecModelManualDateTest.manually_dated_contemporary.where( :uuid => uuid ).to_a
@@ -32,7 +32,7 @@ describe Hoodoo::Client::Endpoint::HTTP do
32
32
  it 'should successfuly connect with valid certificate chain' do
33
33
  endpoint = connect_to_real_https_endpoint('127.0.0.1', 'spec/files/ca/ca-cert.pem')
34
34
  response = endpoint.list()
35
- expect(response["message"]).to eq("This data is a secret")
35
+ expect(response[0]["message"]).to eq("This data is a secret")
36
36
  end
37
37
 
38
38
  it "should fail when certificate doesn't match the hostname" do
@@ -51,7 +51,8 @@ describe Hoodoo::Client::Endpoint::HTTP do
51
51
 
52
52
  class SslSelfSignedApp
53
53
  def call(env)
54
- return [200, {'Content-Type' => 'application/json'}, ['{"message": "This data is a secret"}'] ]
54
+ # Note: Respond to 'list' calls with correct Hoodoo semantics
55
+ return [200, {'Content-Type' => 'application/json'}, ['{ "_data" : [ { "message": "This data is a secret" } ] }'] ]
55
56
  end
56
57
  end
57
58
 
@@ -0,0 +1,434 @@
1
+ require 'securerandom'
2
+ require 'spec_helper.rb'
3
+
4
+ #
5
+ # These tests define the following Services.
6
+ #
7
+ # Clients can call into any of them to invoke the different calling semantics
8
+ # between them.
9
+ #
10
+ #
11
+ # ┌──────────────────────────────────────────────┐ ┌──────────────────────────┐
12
+ # │ │ │ │
13
+ # │ RSpecNumberService │ │ RSpecRemoteNumberService │
14
+ # │ │ │ │
15
+ # │ │ │ │
16
+ # │ ┌──────────────┐ ┌────────────────┐│ │ ┌───────────────────┐ │
17
+ # │ │ │ inter │ ││ │ │ │ │
18
+ # │ │ RSpecNumber │◀resource ─│RSpecEvenNumber ││ │ │ RSpecOddNumber │ │
19
+ # │ │ │ local │ ││ │ │ │ │
20
+ # │ └──────────────┘ └────────────────┘│ │ └───────────────────┘ │
21
+ # │ ▲ │ │ │ │
22
+ # │ │ inter │ │ │ │
23
+ # │ └───────────────────────────resource ┼─┼────────────┘ │
24
+ # │ remote │ │ │
25
+ # └──────────────────────────────────────────────┘ └──────────────────────────┘
26
+ #
27
+ # To start the services in your specs do:
28
+ #
29
+ # spec_helper_start_svc_app_in_thread_for( RSpecNumberService )
30
+ # spec_helper_start_svc_app_in_thread_for( RSpecRemoteNumberService)
31
+ #
32
+
33
+ ################################################################################
34
+ #
35
+ # Create a 'RSpecNumber' Resource with the following properties:
36
+ #
37
+ # - manages 'Number' resources ie: { 'number': 3 }, for numbers between 0 & 999
38
+ # - provides a public 'list' endpoint (no session needed)
39
+ # - pagination
40
+ # - will generate an error when asked to retrieve any 'Number' resource with a
41
+ # number value >= 500 && filter_data['force_error'] is set (to anything)
42
+ #
43
+ class RSpecNumberImplementation < Hoodoo::Services::Implementation
44
+
45
+ public
46
+
47
+ # Number resources are all in this range
48
+ NUMBER_RANGE = 0..999
49
+
50
+ # Number resources that generate errors are all in this range
51
+ ERROR_RANGE = 500..999
52
+
53
+ def list( context )
54
+ request = context.request
55
+
56
+ resources = []
57
+ implode = false
58
+ 0.upto( request.list.limit - 1 ) do |i|
59
+ num = request.list.offset + i
60
+ implode = implode || ERROR_RANGE.include?( num )
61
+ if NUMBER_RANGE.include?( num )
62
+ resources << { 'number' => num }
63
+ else
64
+ break
65
+ end
66
+ end
67
+
68
+ context.response.set_resources( resources, resources.count )
69
+ if implode && request.list.filter_data[ 'force_error' ]
70
+ context.response.add_error( 'platform.malformed' )
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ #
77
+ # Interface for our implementation
78
+ #
79
+ class RSpecNumberInterface < Hoodoo::Services::Interface
80
+ interface :RSpecNumber do
81
+ endpoint :numbers, RSpecNumberImplementation
82
+ to_list do
83
+ filter :force_error
84
+ end
85
+ public_actions :list
86
+ end
87
+ end
88
+
89
+
90
+ ################################################################################
91
+ #
92
+ # Create a 'RSpecEvenNumber' Resource with the following properties:
93
+ #
94
+ # - Calls RSpecNumber via the 'inter_resource_local' calling mechanism
95
+ # - Only returns 'even' numbers, 0, 2, 4... for numbers between 0 & 999
96
+ # - provides a public 'list' endpoint (no session needed)
97
+ #
98
+ # See RSpecNumberImplementation for error handling etc
99
+ #
100
+ class RSpecEvenNumberImplementation < Hoodoo::Services::Implementation
101
+
102
+ public
103
+
104
+ def list( context )
105
+ request = context.request
106
+ endpoint = context.resource( :RSpecNumber, 1 )
107
+ resources = []
108
+ limit = request.list.limit ? request.list.limit : 50
109
+ offset = request.list.offset ? request.list.offset : 0
110
+
111
+ # We always iterate through every Number resource - yeah its dumb
112
+ endpoint.list( { :filter => request.list.filter_data } ).enumerate_all do | number_res |
113
+
114
+ if number_res.platform_errors.has_errors?
115
+ context.response.add_errors( number_res.platform_errors )
116
+ break
117
+ end
118
+
119
+ number = number_res['number']
120
+
121
+ # Number in the correct range & is 'even'
122
+ resources << number_res if number >= ( offset * 2 ) && number.even?
123
+ break if resources.size >= limit
124
+
125
+ end
126
+
127
+ context.response.set_resources( resources, resources.count )
128
+ end
129
+
130
+ end
131
+
132
+ #
133
+ # Interface for our implementation
134
+ #
135
+ class RSpecEvenNumberInterface < Hoodoo::Services::Interface
136
+ interface :RSpecEvenNumber do
137
+ endpoint :even_numbers, RSpecEvenNumberImplementation
138
+ to_list do
139
+ filter :force_error
140
+ end
141
+ public_actions :list
142
+ end
143
+ end
144
+
145
+ ################################################################################
146
+ #
147
+ # Define our service, that implements both resources
148
+ #
149
+ class RSpecNumberService < Hoodoo::Services::Service
150
+ comprised_of RSpecNumberInterface,
151
+ RSpecEvenNumberInterface
152
+ end
153
+
154
+
155
+ ################################################################################
156
+ #
157
+ # Create a 'RSpecOddNumber' Resource with the following properties:
158
+ #
159
+ # - Calls RSpecNumber via the 'inter_resource_remote' calling mechanism
160
+ # - Only returns 'odd' numbers, 1, 3, 5 ... for numbers between 0 & 999
161
+ # - provides a public 'list' endpoint (no session needed)
162
+ #
163
+ # See RSpecNumberImplementation for error handling etc
164
+ #
165
+ class RSpecOddNumberImplementation < Hoodoo::Services::Implementation
166
+
167
+ public
168
+
169
+ def list( context )
170
+ request = context.request
171
+ endpoint = context.resource( :RSpecNumber, 1 )
172
+ resources = []
173
+ limit = request.list.limit ? request.list.limit : 50
174
+ offset = request.list.offset ? request.list.offset : 0
175
+
176
+ # We always iterate through every Number resource - yeah its dumb
177
+ endpoint.list( { :filter => request.list.filter_data } ).enumerate_all do | number_res |
178
+
179
+ if number_res.platform_errors.has_errors?
180
+ context.response.add_errors( number_res.platform_errors )
181
+ break
182
+ end
183
+
184
+ number = number_res['number']
185
+
186
+ # Number in the correct range & is 'odd'
187
+ resources << number_res if number >= ( offset * 2 ) && number.odd?
188
+ break if resources.size >= limit
189
+
190
+ end
191
+
192
+ context.response.set_resources( resources, resources.count )
193
+ end
194
+
195
+ end
196
+
197
+ #
198
+ # Interface for our implementation
199
+ #
200
+ class RSpecOddNumberInterface < Hoodoo::Services::Interface
201
+ interface :RSpecOddNumber do
202
+ endpoint :odd_numbers, RSpecOddNumberImplementation
203
+ to_list do
204
+ filter :force_error
205
+ end
206
+ public_actions :list
207
+ end
208
+ end
209
+
210
+ ################################################################################
211
+ #
212
+ # Define our service, that implements both resources
213
+ #
214
+ class RSpecRemoteNumberService < Hoodoo::Services::Service
215
+ comprised_of RSpecOddNumberInterface
216
+ end
217
+
218
+
219
+
220
+ ##############################################################################
221
+ # Tests
222
+ ##############################################################################
223
+
224
+ describe Hoodoo::Client do
225
+
226
+ before :all do
227
+
228
+ # Start our services in background threads
229
+ spec_helper_start_svc_app_in_thread_for( RSpecNumberService )
230
+ spec_helper_start_svc_app_in_thread_for( RSpecRemoteNumberService )
231
+
232
+ end
233
+
234
+ before :each do
235
+
236
+ @client = Hoodoo::Client.new({
237
+ drb_port: URI.parse( Hoodoo::Services::Discovery::ByDRb::DRbServer.uri() ).port,
238
+ auto_session: false
239
+ })
240
+
241
+ end
242
+
243
+ context 'happy path behaviour' do
244
+
245
+ let( :resources ) { [
246
+ {
247
+ endpoint: @client.resource( :RSpecNumber, 1 ),
248
+ data: (0..999).to_a
249
+ },
250
+ {
251
+ endpoint: @client.resource( :RSpecEvenNumber, 1 ),
252
+ data: (0..999).step(2).to_a
253
+ },
254
+ {
255
+ endpoint: @client.resource( :RSpecOddNumber, 1 ),
256
+ data: (1..999).step(2).to_a
257
+ },
258
+ ] }
259
+
260
+ it 'returns every single result with the correct value' do
261
+
262
+ resources.each do | resource |
263
+ numbers = []
264
+
265
+ resource[ :endpoint ].list.enumerate_all do | result |
266
+ expect( result.platform_errors.errors ).to eq( [] )
267
+ break if result.platform_errors.has_errors?
268
+ numbers << result[ 'number' ]
269
+ end
270
+
271
+ expect( numbers ).to eq( resource[ :data ] )
272
+ end
273
+
274
+ end
275
+
276
+ context 'different "limit" sizes' do
277
+
278
+ let(:limits) {
279
+ # Note: Smaller limits will make the tests very slow
280
+ [ 250, 500, 750, 999, 1000, 1001 ]
281
+ }
282
+
283
+ it 'enumerates correctly with different batch sizes' do
284
+
285
+ resources.each do | resource |
286
+ limits.each do | limit |
287
+ numbers = []
288
+
289
+ resource[ :endpoint ].list( { 'limit' => limit } ).enumerate_all do | result |
290
+ expect( result.platform_errors.errors ).to eq( [] )
291
+ break if result.platform_errors.has_errors?
292
+ numbers << result[ 'number' ]
293
+ end
294
+
295
+ expect( numbers ).to eq( resource[ :data ] )
296
+ end
297
+ end
298
+
299
+ end
300
+
301
+ end
302
+
303
+ end
304
+
305
+ context 'error handling behaviour' do
306
+
307
+ let( :resources ) { [
308
+ {
309
+ endpoint: @client.resource( :RSpecNumber, 1 ),
310
+ expected_results: [
311
+ {
312
+ limit: 10,
313
+ data: ( 0..499 ).to_a,
314
+ },
315
+ {
316
+ limit: 250,
317
+ data: ( 0..499 ).to_a,
318
+ },
319
+ {
320
+ limit: 499,
321
+ data: ( 0..498 ).to_a,
322
+ },
323
+ {
324
+ limit: 500,
325
+ data: ( 0..499 ).to_a,
326
+ },
327
+ {
328
+ limit: 501,
329
+ data: [],
330
+ },
331
+ ]
332
+ },
333
+ {
334
+ endpoint: @client.resource( :RSpecEvenNumber, 1 ),
335
+ expected_results: [
336
+ {
337
+ limit: 10,
338
+ data: ( 0..498 ).step(2).to_a
339
+ },
340
+ {
341
+ limit: 249,
342
+ data: ( 0..496 ).step(2).to_a
343
+ },
344
+ {
345
+ limit: 250,
346
+ data: ( 0..498 ).step(2).to_a
347
+ },
348
+ {
349
+ limit: 251,
350
+ data: []
351
+ },
352
+ ]
353
+ },
354
+ {
355
+ endpoint: @client.resource( :RSpecOddNumber, 1 ),
356
+ expected_results: [
357
+ {
358
+ limit: 10,
359
+ data: ( 1..499 ).step(2).to_a
360
+ },
361
+ {
362
+ limit: 249,
363
+ data: ( 1..497 ).step(2).to_a
364
+ },
365
+ {
366
+ limit: 250,
367
+ data: ( 1..499 ).step(2).to_a
368
+ },
369
+ {
370
+ limit: 251,
371
+ data: []
372
+ },
373
+ ]
374
+ },
375
+ ] }
376
+
377
+ it 'returns values until an error occurs in the "list" call' do
378
+
379
+ resources.each do | resource |
380
+ resource[ :expected_results ].each do | expected |
381
+
382
+ numbers = []
383
+ errors = 0
384
+ query_hash = {
385
+ 'limit' => expected[ :limit ],
386
+ 'filter' => {
387
+ 'force_error' => 'true'
388
+ }
389
+ }
390
+
391
+ resource[ :endpoint ].list( query_hash ).enumerate_all do | result |
392
+ numbers << result[ 'number' ] if result.has_key? 'number'
393
+ errors += 1 if result.platform_errors.has_errors?
394
+ end
395
+
396
+ # The number of valid resources that you recieve is dependent on
397
+ # the 'limit' size that is passed through on the 'list' call
398
+ #
399
+ # Thats because the system will enumerate through an entire batch of
400
+ # resources (of size limit), OR return an error.
401
+ #
402
+ # So the underlying service retrieves 50 valid resources and returns
403
+ # then the caller will enumerate through those 50. On the other hand if
404
+ # the service reads 50 resources, and then detects an error on the 51st
405
+ # then 0 resources are retuned, only an error!
406
+ #
407
+ expect( numbers ).to eq( expected[ :data ] )
408
+ # Check that an error is returned
409
+ expect( errors ).to eq( 1 )
410
+ end
411
+ end
412
+
413
+ end
414
+
415
+
416
+ it 'raises an exception if no block supplied' do
417
+
418
+ endpoints = [
419
+ @client.resource( :RSpecNumber, 1 ),
420
+ @client.resource( :RSpecEvenNumber, 1 ),
421
+ @client.resource( :RSpecOddNumber, 1 ),
422
+ ]
423
+
424
+ endpoints.each do | endpoint |
425
+ expect {
426
+ endpoint.list.enumerate_all
427
+ }.to raise_exception( RuntimeError, 'Must provide a block to enumerate_all' )
428
+ end
429
+
430
+ end
431
+
432
+ end
433
+
434
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hoodoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Loyalty New Zealand
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-23 00:00:00.000000000 Z
11
+ date: 2016-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kgio
@@ -285,6 +285,7 @@ files:
285
285
  - lib/hoodoo/client/endpoint/endpoints/http_based.rb
286
286
  - lib/hoodoo/client/endpoint/endpoints/not_found.rb
287
287
  - lib/hoodoo/client/headers.rb
288
+ - lib/hoodoo/client/paginated_enumeration.rb
288
289
  - lib/hoodoo/communicators.rb
289
290
  - lib/hoodoo/communicators/fast.rb
290
291
  - lib/hoodoo/communicators/pool.rb
@@ -395,6 +396,7 @@ files:
395
396
  - spec/client/endpoint/endpoints/http_spec.rb
396
397
  - spec/client/endpoint/endpoints/not_found_spec.rb
397
398
  - spec/client/headers_spec.rb
399
+ - spec/client/paginated_enumeration_spec.rb
398
400
  - spec/communicators/fast_spec.rb
399
401
  - spec/communicators/pool_spec.rb
400
402
  - spec/communicators/slow_spec.rb
@@ -528,6 +530,7 @@ test_files:
528
530
  - spec/client/endpoint/endpoints/http_spec.rb
529
531
  - spec/client/endpoint/endpoints/not_found_spec.rb
530
532
  - spec/client/headers_spec.rb
533
+ - spec/client/paginated_enumeration_spec.rb
531
534
  - spec/communicators/fast_spec.rb
532
535
  - spec/communicators/pool_spec.rb
533
536
  - spec/communicators/slow_spec.rb