Skip to content

Commit 2ab00b2

Browse files
author
Matt Muller
committed
Move testing to smithy-client instead
1 parent 9ba8955 commit 2ab00b2

14 files changed

Lines changed: 268 additions & 714 deletions

File tree

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../../spec_helper'
4+
5+
require 'smithy-client/plugins/pageable_output'
6+
7+
module Smithy
8+
module Client
9+
module Plugins
10+
describe PageableOutput do
11+
let(:shapes) do
12+
{
13+
'smithy.ruby.tests#Example' => {
14+
'type' => 'service',
15+
'version' => '2019-06-27',
16+
'operations' => [
17+
{
18+
'target' => 'smithy.ruby.tests#GetFoos'
19+
}
20+
]
21+
},
22+
'smithy.ruby.tests#GetFoos' => {
23+
'type' => 'operation',
24+
'input' => { 'target' => 'smithy.ruby.tests#GetFoosInput' },
25+
'output' => { 'target' => 'smithy.ruby.tests#GetFoosOutput' },
26+
'traits' => {
27+
'smithy.api#paginated' => {
28+
'inputToken' => 'nextToken',
29+
'outputToken' => 'nextToken',
30+
'pageSize' => 'maxResults',
31+
'items' => 'foos'
32+
},
33+
'smithy.api#readonly' => {}
34+
}
35+
},
36+
'smithy.ruby.tests#GetFoosInput' => {
37+
'type' => 'structure',
38+
'members' => {
39+
'maxResults' => { 'target' => 'smithy.api#Integer' },
40+
'nextToken' => { 'target' => 'smithy.api#String' }
41+
},
42+
'traits' => { 'smithy.api#input' => {} }
43+
},
44+
'smithy.ruby.tests#GetFoosOutput' => {
45+
'type' => 'structure',
46+
'members' => {
47+
'nextToken' => { 'target' => 'smithy.api#String' },
48+
'foos' => { 'target' => 'smithy.ruby.tests#StringList', 'traits' => { 'smithy.api#required' => {} } }
49+
},
50+
'traits' => { 'smithy.api#output' => {} }
51+
},
52+
'smithy.ruby.tests#StringList' => {
53+
'type' => 'list',
54+
'member' => { 'target' => 'smithy.api#String' }
55+
}
56+
}
57+
end
58+
59+
let(:sample_service) { ClientHelper.sample_service(shapes: shapes) }
60+
61+
let(:client_class) do
62+
client_class = sample_service.const_get(:Client)
63+
client_class.clear_plugins
64+
client_class.add_plugin(sample_service::Plugins::Endpoint)
65+
client_class.add_plugin(Protocol)
66+
client_class.add_plugin(PageableOutput)
67+
client_class.add_plugin(StubResponses)
68+
client_class
69+
end
70+
71+
let(:client) { client_class.new(stub_responses: true, protocol: Smithy::Client::RPCv2CBOR::Protocol.new) }
72+
73+
context 'pagination' do
74+
it 'can paginate with next_page and next_page?' do
75+
client.stub_responses(
76+
:get_foos,
77+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
78+
{ next_token: 'next_token2', foos: ['foo3'] },
79+
{ next_token: nil, foos: ['foo4'] }
80+
)
81+
82+
pages = []
83+
output = client.get_foos
84+
pages << output
85+
while output.next_page?
86+
output = output.next_page
87+
pages << output
88+
end
89+
expect(pages.size).to eq 3
90+
expect(pages[0].foos).to eq %w[foo1 foo2]
91+
expect(pages[1].foos).to eq ['foo3']
92+
expect(pages[2].foos).to eq ['foo4']
93+
end
94+
95+
it 'can check with next_page? and last_page?' do
96+
client.stub_responses(
97+
:get_foos,
98+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
99+
{ next_token: 'next_token2', foos: ['foo3'] },
100+
{ next_token: nil, foos: ['foo4'] }
101+
)
102+
103+
output = client.get_foos
104+
expect(output.next_page?).to be true
105+
expect(output.last_page?).to be false
106+
output = output.next_page
107+
expect(output.next_page?).to be true
108+
expect(output.last_page?).to be false
109+
output = output.next_page
110+
expect(output.next_page?).to be false
111+
expect(output.last_page?).to be true
112+
end
113+
114+
it 'can paginate with each_page' do
115+
client.stub_responses(
116+
:get_foos,
117+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
118+
{ next_token: 'next_token2', foos: ['foo3'] },
119+
{ next_token: nil, foos: ['foo4'] }
120+
)
121+
122+
pages = []
123+
client.get_foos.each_page do |page|
124+
pages << page
125+
end
126+
expect(pages.size).to eq 3
127+
expect(pages[0].foos).to eq %w[foo1 foo2]
128+
expect(pages[1].foos).to eq ['foo3']
129+
expect(pages[2].foos).to eq ['foo4']
130+
end
131+
132+
it 'handles tail style truncation' do
133+
client.stub_responses(
134+
:get_foos,
135+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
136+
{ next_token: 'next_token2', foos: ['foo3'] },
137+
{ next_token: 'next_token2', foos: ['foo4'] }
138+
)
139+
140+
pages = []
141+
client.get_foos.each_page do |page|
142+
pages << page
143+
end
144+
expect(pages.size).to eq 3
145+
expect(pages[0].foos).to eq %w[foo1 foo2]
146+
expect(pages[1].foos).to eq ['foo3']
147+
expect(pages[2].foos).to eq ['foo4']
148+
end
149+
150+
it 'can paginate with each_item' do
151+
client.stub_responses(
152+
:get_foos,
153+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
154+
{ next_token: 'next_token2', foos: ['foo3'] },
155+
{ next_token: nil, foos: ['foo4'] }
156+
)
157+
158+
items = []
159+
client.get_foos.each_item do |item|
160+
items << item
161+
end
162+
expect(items.size).to eq 4
163+
expect(items).to eq %w[foo1 foo2 foo3 foo4]
164+
end
165+
end
166+
167+
it 'can inherit the paginated trait from the operation' do
168+
shapes['smithy.ruby.tests#Example']['traits'] = {
169+
'smithy.api#paginated' => {
170+
'inputToken' => 'nextToken',
171+
'outputToken' => 'nextToken',
172+
'pageSize' => 'maxResults'
173+
}
174+
}
175+
shapes['smithy.ruby.tests#GetFoos']['traits'] = {
176+
'smithy.api#paginated' => { 'items' => 'foos' }
177+
}
178+
179+
client.stub_responses(
180+
:get_foos,
181+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
182+
{ next_token: 'next_token2', foos: ['foo3'] },
183+
{ next_token: nil, foos: ['foo4'] }
184+
)
185+
186+
pages = []
187+
output = client.get_foos
188+
pages << output
189+
while output.next_page?
190+
output = output.next_page
191+
pages << output
192+
end
193+
expect(pages.size).to eq 3
194+
expect(pages[0].foos).to eq %w[foo1 foo2]
195+
expect(pages[1].foos).to eq ['foo3']
196+
expect(pages[2].foos).to eq ['foo4']
197+
end
198+
199+
it 'can handle nested member paths' do
200+
shapes['smithy.ruby.tests#GetFoosOutput'] = {
201+
'type' => 'structure',
202+
'members' => {
203+
'result' => { 'target' => 'smithy.ruby.tests#ResultWrapper', 'traits' => { 'smithy.api#required' => {} } }
204+
},
205+
'traits' => { 'smithy.api#output' => {} }
206+
}
207+
shapes['smithy.ruby.tests#ResultWrapper'] = {
208+
'type' => 'structure',
209+
'members' => {
210+
'nextToken' => { 'target' => 'smithy.api#String' },
211+
'foos' => { 'target' => 'smithy.ruby.tests#StringList', 'traits' => { 'smithy.api#required' => {} } }
212+
}
213+
}
214+
shapes['smithy.ruby.tests#GetFoos']['traits']['smithy.api#paginated']['outputToken'] = 'result.nextToken'
215+
shapes['smithy.ruby.tests#GetFoos']['traits']['smithy.api#paginated']['items'] = 'result.foos'
216+
217+
client.stub_responses(
218+
:get_foos,
219+
{ result: { next_token: 'next_token', foos: %w[foo1 foo2] } },
220+
{ result: { next_token: 'next_token2', foos: ['foo3'] } },
221+
{ result: { next_token: nil, foos: ['foo4'] } }
222+
)
223+
224+
pages = []
225+
client.get_foos.each_page do |page|
226+
pages << page
227+
end
228+
expect(pages.size).to eq 3
229+
expect(pages[0].result.foos).to eq %w[foo1 foo2]
230+
expect(pages[1].result.foos).to eq ['foo3']
231+
expect(pages[2].result.foos).to eq ['foo4']
232+
end
233+
234+
it 'raises NotImplementedError for each_item if no items' do
235+
shapes['smithy.ruby.tests#GetFoos']['traits']['smithy.api#paginated'].delete('items')
236+
237+
client.stub_responses(
238+
:get_foos,
239+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
240+
{ next_token: 'next_token2', foos: ['foo3'] },
241+
{ next_token: nil, foos: ['foo4'] }
242+
)
243+
244+
expect { client.get_foos.each_item {} } # empty
245+
.to raise_error NotImplementedError
246+
end
247+
248+
it 'adds a null paginator if no paginated trait' do
249+
shapes['smithy.ruby.tests#GetFoos']['traits'].delete('smithy.api#paginated')
250+
251+
client.stub_responses(
252+
:get_foos,
253+
{ next_token: 'next_token', foos: %w[foo1 foo2] },
254+
{ next_token: 'next_token2', foos: ['foo3'] },
255+
{ next_token: nil, foos: ['foo4'] }
256+
)
257+
258+
output = client.get_foos
259+
expect(output.paginator).to be_a(Smithy::Client::Plugins::PageableOutput::Handler::NullPaginator)
260+
expect(output.next_page?).to be false
261+
expect(output.last_page?).to be true
262+
expect { output.next_page }.to raise_error Smithy::Client::Errors::LastPageError
263+
end
264+
end
265+
end
266+
end
267+
end

gems/smithy/lib/smithy/templates/client/paginators.erb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ module <%= module_name %>
2020
<%= line %>
2121
<% end -%>
2222
end
23-
<%- if paginator.items? -%>
2423

2524
def items(data)
2625
<% paginator.items_code.each do |line| -%>
2726
<%= line %>
2827
<% end -%>
2928
end
30-
<% end -%>
3129
end
3230

3331
<% end -%>

gems/smithy/lib/smithy/views/client/paginators.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def prev_tokens_code
7373
end
7474

7575
def items_code
76-
return "raise NotImplementedError, 'item iteration is not implemented for this operation'" unless items?
76+
return ["raise NotImplementedError, 'item iteration is not implemented for this operation'"] unless items?
7777

7878
[output_getter(@items)]
7979
end

gems/smithy/spec/fixtures/paginated_trait/inheritance/model.json

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)