files.com 1.1.768 → 1.1.770
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +47 -7
- data/_VERSION +1 -1
- data/docs/file.md +37 -0
- data/lib/files.com/api.rb +9 -4
- data/lib/files.com/api_client.rb +181 -55
- data/lib/files.com/list.rb +98 -66
- data/lib/files.com/models/action_log.rb +7 -2
- data/lib/files.com/models/action_notification_export.rb +13 -3
- data/lib/files.com/models/action_notification_export_result.rb +7 -2
- data/lib/files.com/models/ai_assistant_personality.rb +34 -8
- data/lib/files.com/models/ai_task.rb +39 -8
- data/lib/files.com/models/api_key.rb +49 -10
- data/lib/files.com/models/api_request_log.rb +7 -2
- data/lib/files.com/models/app.rb +7 -2
- data/lib/files.com/models/as2_incoming_message.rb +7 -2
- data/lib/files.com/models/as2_outgoing_message.rb +7 -2
- data/lib/files.com/models/as2_partner.rb +34 -8
- data/lib/files.com/models/as2_station.rb +34 -8
- data/lib/files.com/models/automation.rb +50 -10
- data/lib/files.com/models/automation_log.rb +7 -2
- data/lib/files.com/models/automation_run.rb +31 -6
- data/lib/files.com/models/bandwidth_snapshot.rb +7 -2
- data/lib/files.com/models/behavior.rb +46 -10
- data/lib/files.com/models/bundle.rb +39 -8
- data/lib/files.com/models/bundle_action.rb +7 -2
- data/lib/files.com/models/bundle_download.rb +7 -2
- data/lib/files.com/models/bundle_notification.rb +34 -8
- data/lib/files.com/models/bundle_recipient.rb +14 -4
- data/lib/files.com/models/bundle_registration.rb +7 -2
- data/lib/files.com/models/chat_session.rb +13 -3
- data/lib/files.com/models/child_site_management_policy.rb +34 -8
- data/lib/files.com/models/clickwrap.rb +34 -8
- data/lib/files.com/models/custom_domain.rb +40 -9
- data/lib/files.com/models/desktop_configuration_profile.rb +34 -8
- data/lib/files.com/models/dns_record.rb +7 -2
- data/lib/files.com/models/email_incoming_message.rb +7 -2
- data/lib/files.com/models/email_log.rb +7 -2
- data/lib/files.com/models/event_channel.rb +34 -8
- data/lib/files.com/models/event_delivery_attempt.rb +13 -3
- data/lib/files.com/models/event_record.rb +13 -3
- data/lib/files.com/models/event_subscription.rb +34 -8
- data/lib/files.com/models/event_target.rb +34 -8
- data/lib/files.com/models/exavault_api_request_log.rb +7 -2
- data/lib/files.com/models/expectation.rb +40 -9
- data/lib/files.com/models/expectation_evaluation.rb +13 -3
- data/lib/files.com/models/expectation_incident.rb +31 -6
- data/lib/files.com/models/external_event.rb +20 -5
- data/lib/files.com/models/file.rb +93 -15
- data/lib/files.com/models/file_comment.rb +28 -7
- data/lib/files.com/models/file_comment_reaction.rb +11 -2
- data/lib/files.com/models/file_migration.rb +6 -1
- data/lib/files.com/models/file_migration_log.rb +7 -2
- data/lib/files.com/models/folder.rb +13 -3
- data/lib/files.com/models/form_field_set.rb +34 -8
- data/lib/files.com/models/ftp_action_log.rb +7 -2
- data/lib/files.com/models/gpg_key.rb +34 -8
- data/lib/files.com/models/group.rb +34 -8
- data/lib/files.com/models/group_user.rb +29 -7
- data/lib/files.com/models/history.rb +35 -10
- data/lib/files.com/models/history_export.rb +13 -3
- data/lib/files.com/models/history_export_result.rb +7 -2
- data/lib/files.com/models/holiday_calendar.rb +34 -8
- data/lib/files.com/models/holiday_region.rb +7 -2
- data/lib/files.com/models/inbound_s3_log.rb +7 -2
- data/lib/files.com/models/inbox_recipient.rb +14 -4
- data/lib/files.com/models/inbox_registration.rb +7 -2
- data/lib/files.com/models/inbox_upload.rb +7 -2
- data/lib/files.com/models/integration_centric_profile.rb +34 -8
- data/lib/files.com/models/invoice.rb +13 -3
- data/lib/files.com/models/ip_address.rb +28 -8
- data/lib/files.com/models/key_lifecycle_rule.rb +34 -8
- data/lib/files.com/models/lock.rb +18 -3
- data/lib/files.com/models/metadata_category.rb +41 -10
- data/lib/files.com/models/notification.rb +34 -8
- data/lib/files.com/models/outbound_connection_log.rb +7 -2
- data/lib/files.com/models/partner.rb +34 -8
- data/lib/files.com/models/partner_channel.rb +34 -8
- data/lib/files.com/models/partner_channel_template.rb +34 -8
- data/lib/files.com/models/partner_site.rb +4 -0
- data/lib/files.com/models/partner_site_request.rb +33 -4
- data/lib/files.com/models/payment.rb +13 -3
- data/lib/files.com/models/pending_work_event.rb +13 -3
- data/lib/files.com/models/permission.rb +18 -4
- data/lib/files.com/models/public_hosting_request_log.rb +7 -2
- data/lib/files.com/models/public_key.rb +34 -8
- data/lib/files.com/models/remote_bandwidth_snapshot.rb +7 -2
- data/lib/files.com/models/remote_mount_backend.rb +39 -8
- data/lib/files.com/models/remote_server.rb +52 -11
- data/lib/files.com/models/remote_server_credential.rb +34 -8
- data/lib/files.com/models/request.rb +25 -6
- data/lib/files.com/models/restore.rb +14 -4
- data/lib/files.com/models/schedule.rb +34 -8
- data/lib/files.com/models/scheduled_export.rb +34 -8
- data/lib/files.com/models/scim_log.rb +13 -3
- data/lib/files.com/models/secret.rb +34 -8
- data/lib/files.com/models/session.rb +11 -2
- data/lib/files.com/models/settings_change.rb +7 -2
- data/lib/files.com/models/sftp_action_log.rb +7 -2
- data/lib/files.com/models/sftp_host_key.rb +34 -8
- data/lib/files.com/models/share_group.rb +34 -8
- data/lib/files.com/models/siem_http_destination.rb +39 -8
- data/lib/files.com/models/siem_http_destination_event.rb +13 -3
- data/lib/files.com/models/site.rb +16 -3
- data/lib/files.com/models/site_subdomain_redirect.rb +17 -3
- data/lib/files.com/models/snapshot.rb +39 -8
- data/lib/files.com/models/sso_event.rb +13 -3
- data/lib/files.com/models/sso_strategy.rb +18 -3
- data/lib/files.com/models/style.rb +20 -5
- data/lib/files.com/models/sync.rb +44 -8
- data/lib/files.com/models/sync_log.rb +7 -2
- data/lib/files.com/models/sync_run.rb +13 -3
- data/lib/files.com/models/usage_daily_snapshot.rb +7 -2
- data/lib/files.com/models/usage_snapshot.rb +7 -2
- data/lib/files.com/models/user.rb +50 -8
- data/lib/files.com/models/user_additional_email_recipient.rb +34 -8
- data/lib/files.com/models/user_cipher_use.rb +7 -2
- data/lib/files.com/models/user_lifecycle_rule.rb +34 -8
- data/lib/files.com/models/user_request.rb +24 -5
- data/lib/files.com/models/user_security_event.rb +13 -3
- data/lib/files.com/models/user_sftp_client_use.rb +7 -2
- data/lib/files.com/models/web_dav_action_log.rb +7 -2
- data/lib/files.com/models/webhook_test.rb +7 -2
- data/lib/files.com/models/workspace.rb +34 -8
- data/lib/files.com/response.rb +24 -0
- data/lib/files.com/sizable_io.rb +65 -4
- data/lib/files.com/version.rb +1 -1
- data/lib/files.com.rb +23 -1
- data/spec/language_spec.rb +20 -10
- data/spec/lib/api_client_spec.rb +173 -18
- data/spec/list_spec.rb +203 -187
- data/spec/models/file_transfer_spec.rb +346 -0
- data/spec/models/persistence_spec.rb +167 -0
- data/spec/spec_helper.rb +122 -6
- data/spec/support/stubbed_api.rb +14 -0
- data/spec/support/transfer_server.rb +60 -0
- metadata +6 -2
data/spec/list_spec.rb
CHANGED
|
@@ -1,215 +1,231 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
ResourceWrapper = Struct.new(:object, :options)
|
|
2
|
+
require_relative "support/stubbed_api"
|
|
4
3
|
|
|
5
4
|
RSpec.describe Files::List do
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
let(:
|
|
5
|
+
include StubbedApi
|
|
6
|
+
|
|
7
|
+
let(:requests) { [] }
|
|
8
|
+
|
|
9
|
+
# Serves Workspace pages by request cursor. Each page is its workspace IDs and
|
|
10
|
+
# the cursor the API returns for the page after it, if any.
|
|
11
|
+
def serve_pages(pages)
|
|
12
|
+
stubbed_api_client do |stub|
|
|
13
|
+
stub.get("/api/rest/v1/workspaces") do |env|
|
|
14
|
+
requests << env.params
|
|
15
|
+
raise "the SDK requested more pages than the list has" if requests.size > pages.size + 2
|
|
16
|
+
|
|
17
|
+
ids, next_cursor = pages.fetch(env.params["cursor"])
|
|
18
|
+
json_response(200, ids.map { |id| { id: id, name: "Workspace #{id}" } }, next_cursor ? { "X-Files-Cursor" => next_cursor } : {})
|
|
19
|
+
end
|
|
20
|
+
yield stub if block_given?
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def requested_cursors
|
|
25
|
+
requests.map { |params| params["cursor"] }
|
|
26
|
+
end
|
|
9
27
|
|
|
10
28
|
describe "#auto_paging_each" do
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
context "when response includes a cursor" do
|
|
16
|
-
let(:client) { instance_double(Files::ApiClient) }
|
|
17
|
-
let(:stubbed_cursors) {
|
|
18
|
-
[
|
|
19
|
-
'3',
|
|
20
|
-
'6',
|
|
21
|
-
nil
|
|
22
|
-
]
|
|
23
|
-
}
|
|
29
|
+
it "follows the cursor through short and empty pages with the caller's filters" do
|
|
30
|
+
client = serve_pages(nil => [ [ 1 ], "c2" ], "c2" => [ [], "c3" ], "c3" => [ [], "c4" ], "c4" => [ [ 4 ], nil ])
|
|
31
|
+
params = { per_page: 2, filter: { name: "Workspace" } }
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
allow(client).to receive(:cursor).and_return(*stubbed_cursors)
|
|
27
|
-
end
|
|
33
|
+
workspaces = Files::Workspace.list(params, api_key: "list-key", client: client).auto_paging_each.to_a
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
list = described_class.new(ResourceWrapper, params) {
|
|
36
|
-
times_block_yielded += 1
|
|
37
|
-
request_cursor = params[:cursor]
|
|
38
|
-
range_start = params[:cursor] ? params[:cursor].to_i : 0
|
|
39
|
-
|
|
40
|
-
response_data = server_results[range_start, per_page]
|
|
41
|
-
response_cursor = (range_start + per_page).to_s
|
|
42
|
-
[
|
|
43
|
-
instance_double(Files::Response, data: response_data, http_status: 200, http_headers: { "x-files-cursor" => response_cursor }),
|
|
44
|
-
options
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
results = list.auto_paging_each
|
|
48
|
-
expect(results.class).to eq(Enumerator::Lazy)
|
|
49
|
-
expect(times_block_yielded).to eq(0)
|
|
50
|
-
expect(results.next.object).to eq('a')
|
|
51
|
-
expect(times_block_yielded).to eq(1)
|
|
52
|
-
expect(request_cursor).to eq(nil)
|
|
53
|
-
expect(results.next.object).to eq('b')
|
|
54
|
-
expect(results.next.object).to eq('c')
|
|
55
|
-
expect(results.next.object).to eq('d')
|
|
56
|
-
expect(times_block_yielded).to eq(2)
|
|
57
|
-
expect(request_cursor).to eq("3")
|
|
58
|
-
expect(results.next.object).to eq('e')
|
|
59
|
-
expect(results.next.object).to eq('f')
|
|
60
|
-
expect(results.next.object).to eq('g')
|
|
61
|
-
expect(results.next.object).to eq('h')
|
|
62
|
-
expect(times_block_yielded).to eq(3)
|
|
63
|
-
expect(request_cursor).to eq("6")
|
|
64
|
-
end
|
|
35
|
+
expect(workspaces.map(&:id)).to eq([ 1, 4 ])
|
|
36
|
+
expect(workspaces.map { |workspace| workspace.options[:api_key] }).to eq([ "list-key", "list-key" ])
|
|
37
|
+
expect(requested_cursors).to eq([ nil, "c2", "c3", "c4" ])
|
|
38
|
+
expect(requests).to all(include("per_page" => "2", "filter" => { "name" => "Workspace" }))
|
|
39
|
+
expect(params).to eq(per_page: 2, filter: { name: "Workspace" })
|
|
40
|
+
end
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
list = described_class.new(ResourceWrapper, params) {
|
|
70
|
-
times_block_yielded += 1
|
|
71
|
-
[
|
|
72
|
-
instance_double(Files::Response, data: server_results.shift(per_page), http_status: 400),
|
|
73
|
-
options
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
results = list.auto_paging_each
|
|
77
|
-
expect(results.count).to eq(0)
|
|
78
|
-
expect(times_block_yielded).to eq(1)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
42
|
+
it "requests a later page only when iteration reaches it" do
|
|
43
|
+
client = serve_pages(nil => [ [ 1, 2 ], "c2" ], "c2" => [ [ 3 ], nil ])
|
|
44
|
+
list = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
81
45
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
options
|
|
93
|
-
]
|
|
94
|
-
}
|
|
95
|
-
results = list.auto_paging_each
|
|
96
|
-
expect(results.count).to eq(3)
|
|
97
|
-
expect(times_block_yielded).to eq(1)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
46
|
+
workspaces = list.auto_paging_each
|
|
47
|
+
expect(requests).to be_empty
|
|
48
|
+
|
|
49
|
+
expect(workspaces.first(2).map(&:id)).to eq([ 1, 2 ])
|
|
50
|
+
expect(workspaces.take(2).map(&:id).to_a).to eq([ 1, 2 ])
|
|
51
|
+
list.auto_paging_each { |workspace| break if workspace.id == 2 }
|
|
52
|
+
expect(requests.size).to eq(1)
|
|
53
|
+
|
|
54
|
+
expect(workspaces.map(&:id).to_a).to eq([ 1, 2, 3 ])
|
|
55
|
+
expect(requested_cursors).to eq([ nil, "c2" ])
|
|
100
56
|
end
|
|
101
57
|
|
|
102
|
-
it "
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
58
|
+
it "starts at the page it is called on and leaves next_page where it was" do
|
|
59
|
+
client = serve_pages(nil => [ [ 1, 2 ], "c2" ], "c2" => [ [ 3, 4 ], nil ])
|
|
60
|
+
list = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
61
|
+
|
|
62
|
+
expect(list.map(&:id)).to eq([ 1, 2 ])
|
|
63
|
+
expect(list.auto_paging_each.map(&:id).to_a).to eq([ 1, 2, 3, 4 ])
|
|
64
|
+
expect(list.next_page.map(&:id)).to eq([ 3, 4 ])
|
|
65
|
+
expect(requested_cursors).to eq([ nil, "c2", "c2" ])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "raises instead of following a cursor the list already used" do
|
|
69
|
+
client = serve_pages(nil => [ [ 1 ], "a" ], "a" => [ [ 2 ], "a" ])
|
|
70
|
+
seen = []
|
|
71
|
+
|
|
72
|
+
expect {
|
|
73
|
+
Files::Workspace.list({ per_page: 1 }, api_key: "list-key", client: client).auto_paging_each { |workspace| seen << workspace.id }
|
|
74
|
+
}.to raise_error(Files::APIConnectionError, /repeated a list cursor/)
|
|
75
|
+
expect(seen).to eq([ 1, 2 ])
|
|
76
|
+
expect(requested_cursors).to eq([ nil, "a" ])
|
|
115
77
|
end
|
|
116
78
|
end
|
|
117
79
|
|
|
118
80
|
describe "#each" do
|
|
119
|
-
it "returns
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
expect(results.count).to eq(8)
|
|
130
|
-
expect(times_block_yielded).to eq(1)
|
|
81
|
+
it "returns the block's results, or an Enumerator without a block" do
|
|
82
|
+
client = serve_pages(nil => [ [ 1, 2 ], nil ])
|
|
83
|
+
list = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
84
|
+
|
|
85
|
+
expect(list.each(&:name)).to eq([ "Workspace 1", "Workspace 2" ])
|
|
86
|
+
expect(list.each).to be_an(Enumerator)
|
|
87
|
+
expect(list.each.map(&:id)).to eq([ 1, 2 ])
|
|
88
|
+
expect(requests.size).to eq(1)
|
|
131
89
|
end
|
|
90
|
+
end
|
|
132
91
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
context "when response includes a cursor" do
|
|
138
|
-
let(:client) { instance_double(Files::ApiClient, cursor: "XXX-XXX") }
|
|
139
|
-
|
|
140
|
-
it "does not call the API until out of responses" do
|
|
141
|
-
server_results = ('a'..'h').to_a
|
|
142
|
-
times_block_yielded = 0
|
|
143
|
-
list = described_class.new(ResourceWrapper, params) {
|
|
144
|
-
times_block_yielded += 1
|
|
145
|
-
[
|
|
146
|
-
instance_double(Files::Response, data: server_results.shift(per_page), http_status: 200),
|
|
147
|
-
options
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
results = list.enum_for(:each)
|
|
151
|
-
expect(times_block_yielded).to eq(0)
|
|
152
|
-
expect(results.next.object).to eq('a')
|
|
153
|
-
expect(times_block_yielded).to eq(1)
|
|
154
|
-
expect(results.next.object).to eq('b')
|
|
155
|
-
expect(results.next.object).to eq('c')
|
|
156
|
-
next_results = list.next_page.enum_for(:each)
|
|
157
|
-
expect(times_block_yielded).to eq(2)
|
|
158
|
-
expect(next_results.next.object).to eq('d')
|
|
159
|
-
expect(next_results.next.object).to eq('e')
|
|
160
|
-
expect(next_results.next.object).to eq('f')
|
|
161
|
-
next_results = list.next_page.enum_for(:each)
|
|
162
|
-
expect(times_block_yielded).to eq(3)
|
|
163
|
-
expect(next_results.next.object).to eq('g')
|
|
164
|
-
expect(next_results.next.object).to eq('h')
|
|
165
|
-
next_results = list.next_page.enum_for(:each)
|
|
166
|
-
expect(next_results.count).to eq(0)
|
|
167
|
-
end
|
|
92
|
+
describe "manual paging" do
|
|
93
|
+
it "steps through every page, including empty ones, with has_next_page? and next_page" do
|
|
94
|
+
client = serve_pages(nil => [ [ 1, 2 ], "c2" ], "c2" => [ [], "c3" ], "c3" => [ [ 3 ], "c4" ], "c4" => [ [], nil ])
|
|
95
|
+
page = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
168
96
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
97
|
+
pages = []
|
|
98
|
+
loop do
|
|
99
|
+
pages << page.each.map(&:id)
|
|
100
|
+
break unless page.has_next_page?
|
|
101
|
+
|
|
102
|
+
page = page.next_page
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
expect(pages).to eq([ [ 1, 2 ], [], [ 3 ], [] ])
|
|
106
|
+
expect(requested_cursors).to eq([ nil, "c2", "c3", "c4" ])
|
|
107
|
+
|
|
108
|
+
after_last = page.next_page
|
|
109
|
+
expect(after_last).to be_a(Files::List)
|
|
110
|
+
expect(after_last.to_a).to be_empty
|
|
111
|
+
expect(after_last.has_next_page?).to be(false)
|
|
112
|
+
expect(requests.size).to eq(4)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "continues from each page's own cursor when other requests happen in between" do
|
|
116
|
+
client = serve_pages(nil => [ [ 1 ], "c2" ], "c2" => [ [ 2 ], "c3" ], "c3" => [ [ 3 ], "c4" ], "c4" => [ [ 4 ], nil ]) do |stub|
|
|
117
|
+
stub.get("/api/rest/v1/workspaces/9") { json_response(200, { id: 9, name: "Workspace 9" }) }
|
|
118
|
+
end
|
|
119
|
+
list = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
120
|
+
|
|
121
|
+
expect(list.map(&:id)).to eq([ 1 ])
|
|
122
|
+
second = list.next_page
|
|
123
|
+
Files::Workspace.find(9, {}, api_key: "list-key", client: client)
|
|
124
|
+
expect(second.map(&:id)).to eq([ 2 ])
|
|
125
|
+
expect(second.map(&:id)).to eq([ 2 ])
|
|
126
|
+
|
|
127
|
+
third = list.next_page
|
|
128
|
+
expect(third.map(&:id)).to eq([ 3 ])
|
|
129
|
+
expect(third.next_page.map(&:id)).to eq([ 4 ])
|
|
130
|
+
expect(list.has_next_page?).to be(false)
|
|
131
|
+
expect(requested_cursors).to eq([ nil, "c2", "c3", "c4" ])
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "requests the same page again after a failed request" do
|
|
135
|
+
failures = [ json_response(429, { error: "Slow down", type: "too-many-requests" }) ]
|
|
136
|
+
client = stubbed_api_client do |stub|
|
|
137
|
+
stub.get("/api/rest/v1/workspaces") do |env|
|
|
138
|
+
requests << env.params
|
|
139
|
+
next failures.shift if env.params["cursor"] == "c2" && failures.any?
|
|
140
|
+
|
|
141
|
+
env.params["cursor"] ? json_response(200, [ { id: 2 } ]) : json_response(200, [ { id: 1 } ], "X-Files-Cursor" => "c2")
|
|
178
142
|
end
|
|
143
|
+
end
|
|
144
|
+
page = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
145
|
+
|
|
146
|
+
expect(page.has_next_page?).to be(true)
|
|
147
|
+
expect { page.next_page }.to raise_error(Files::TooManyRequestsError)
|
|
148
|
+
expect(page.next_page.map(&:id)).to eq([ 2 ])
|
|
149
|
+
expect(requested_cursors).to eq([ nil, "c2", "c2" ])
|
|
150
|
+
end
|
|
179
151
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
152
|
+
{
|
|
153
|
+
"JSON null" => "null",
|
|
154
|
+
"a JSON object" => { data: [ { id: 2 } ], note: "sentinel" }.to_json,
|
|
155
|
+
"a JSON scalar" => "\"sentinel\"",
|
|
156
|
+
"a list holding something other than objects" => [ { id: 2 }, "sentinel" ].to_json,
|
|
157
|
+
}.each do |description, malformed|
|
|
158
|
+
it "raises APIConnectionError for a page that is #{description}, and can request it again" do
|
|
159
|
+
replies = [ malformed, [ { id: 2 } ].to_json ]
|
|
160
|
+
client = stubbed_api_client do |stub|
|
|
161
|
+
stub.get("/api/rest/v1/workspaces") do |env|
|
|
162
|
+
requests << env.params
|
|
163
|
+
next json_response(200, [ { id: 1 } ], "X-Files-Cursor" => "c2") unless env.params["cursor"]
|
|
164
|
+
|
|
165
|
+
[ 200, { "Content-Type" => "application/json" }, replies.shift ]
|
|
166
|
+
end
|
|
192
167
|
end
|
|
168
|
+
page = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
169
|
+
expect(page.map(&:id)).to eq([ 1 ])
|
|
170
|
+
|
|
171
|
+
expect { page.next_page }.to raise_error(Files::APIConnectionError) { |error|
|
|
172
|
+
expect(error).to be_an_instance_of(Files::APIConnectionError)
|
|
173
|
+
expect(error.message).not_to include("sentinel")
|
|
174
|
+
expect(error.http_status).to eq(200)
|
|
175
|
+
expect(error.http_body).to eq(malformed)
|
|
176
|
+
}
|
|
177
|
+
expect(page.map(&:id)).to eq([ 1 ])
|
|
178
|
+
expect(page.has_next_page?).to be(true)
|
|
179
|
+
expect(page.next_page.map(&:id)).to eq([ 2 ])
|
|
180
|
+
expect(requested_cursors).to eq([ nil, "c2", "c2" ])
|
|
193
181
|
end
|
|
182
|
+
end
|
|
194
183
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
184
|
+
it "leaves the caller's options alone when the first page is rejected, then keeps the client that succeeds" do
|
|
185
|
+
rejecting = stubbed_api_client do |stub|
|
|
186
|
+
stub.get("/api/rest/v1/workspaces") do
|
|
187
|
+
requests << :rejecting
|
|
188
|
+
[ 200, { "Content-Type" => "application/json" }, "null" ]
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
accepting = stubbed_api_client do |stub|
|
|
192
|
+
stub.get("/api/rest/v1/workspaces") do |env|
|
|
193
|
+
requests << :accepting
|
|
194
|
+
env.params["cursor"] ? json_response(200, [ { id: 2 } ]) : json_response(200, [ { id: 1 } ], "X-Files-Cursor" => "c2")
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
other = stubbed_api_client do |stub|
|
|
198
|
+
stub.get("/api/rest/v1/workspaces") do
|
|
199
|
+
requests << :other
|
|
200
|
+
json_response(200, [])
|
|
211
201
|
end
|
|
212
202
|
end
|
|
203
|
+
options = { api_key: "list-key" }
|
|
204
|
+
list = Files::Workspace.list({}, options)
|
|
205
|
+
|
|
206
|
+
expect { rejecting.request { list.to_a } }.to raise_error(Files::APIConnectionError)
|
|
207
|
+
expect(options).to eq(api_key: "list-key")
|
|
208
|
+
|
|
209
|
+
first_ids = nil
|
|
210
|
+
accepting.request { first_ids = list.map(&:id) }
|
|
211
|
+
expect(first_ids).to eq([ 1 ])
|
|
212
|
+
expect(options).to include(api_key: "list-key", client: accepting)
|
|
213
|
+
|
|
214
|
+
second = nil
|
|
215
|
+
other.request { second = list.next_page }
|
|
216
|
+
expect(second.map(&:id)).to eq([ 2 ])
|
|
217
|
+
expect(requests).to eq(%i[rejecting accepting accepting])
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "raises instead of returning to a page it already requested" do
|
|
221
|
+
client = serve_pages(nil => [ [ 1 ], "a" ], "a" => [ [ 2 ], "b" ], "b" => [ [ 3 ], "a" ])
|
|
222
|
+
page = Files::Workspace.list({}, api_key: "list-key", client: client)
|
|
223
|
+
|
|
224
|
+
page = page.next_page.next_page
|
|
225
|
+
expect(page.map(&:id)).to eq([ 3 ])
|
|
226
|
+
expect(page.has_next_page?).to be(true)
|
|
227
|
+
expect { page.next_page }.to raise_error(Files::APIConnectionError, /repeated a list cursor/)
|
|
228
|
+
expect(requested_cursors).to eq([ nil, "a", "b" ])
|
|
213
229
|
end
|
|
214
230
|
end
|
|
215
231
|
end
|