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 +8 -8
- data/lib/hoodoo/client.rb +1 -0
- data/lib/hoodoo/client/augmented_array.rb +1 -0
- data/lib/hoodoo/client/endpoint/endpoint.rb +32 -0
- data/lib/hoodoo/client/endpoint/endpoints/http.rb +1 -1
- data/lib/hoodoo/client/paginated_enumeration.rb +94 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +2 -1
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +1 -1
- data/lib/hoodoo/version.rb +1 -1
- data/spec/active/active_record/manually_dated_spec.rb +14 -2
- data/spec/client/endpoint/endpoints/http_spec.rb +3 -2
- data/spec/client/paginated_enumeration_spec.rb +434 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2FmMmNkOGIxNmI3Yjc3Njk2ZGU4MmJlMzVkZDkyYWQ2ZGI2NGNiNQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YWNkMjFhNmMwODQ2OGYxYjZmNDI1ZGIxZGJmNzg3YjQyY2I5ZDMxYw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWJjN2JjMjA3Zjc1YTRmMzYwN2ZkODYyMzE4M2I2N2VkOTg4M2I1MDBjMDhj
|
10
|
+
ZGE3N2RhNWZlOGMwMDQ2MWVmNzNhMzQ3MWEwZTRiZDhjMjBkMDNjNDdhZjdh
|
11
|
+
ZjYxOGUwYTk1NDFlYTJmY2VhNGYxYWI5ODk5YzdmNDNkOThjYTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MmQzNzQxZWI0OTQ2YjI2Nzg1ODAxMzA0ODVlNmM0ODRmMTE2YTY0YmEwYzA2
|
14
|
+
YTdjMzZkMTY4NWRlNjlmMzdhNTc1NDdiYWM4OTQ1YjNkNzQzNjYzZTlmNDFl
|
15
|
+
Nzc3Mzk5ZmFhMDIxOTk0NmY2MzIyMTc2MGQ2YjFlYWQ5MDQxMGQ=
|
data/lib/hoodoo/client.rb
CHANGED
@@ -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
|
@@ -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
|
-
|
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.
|
data/lib/hoodoo/version.rb
CHANGED
@@ -927,9 +927,21 @@ describe Hoodoo::ActiveRecord::ManuallyDated do
|
|
927
927
|
# history entries
|
928
928
|
#
|
929
929
|
it 'updates work' do
|
930
|
-
values = ( '1'..'
|
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
|
-
|
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.
|
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-
|
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
|