pdc 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +27 -0
- data/.gitignore +10 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +21 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +32 -0
- data/Guardfile +36 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +11 -0
- data/bin/console +11 -0
- data/bin/setup +11 -0
- data/docs/.gitignore +3 -0
- data/docs/LICENSE_sphinx_deployment +27 -0
- data/docs/Makefile +179 -0
- data/docs/source/conf.py +257 -0
- data/docs/source/example.rst +10 -0
- data/docs/source/index.rst +23 -0
- data/docs/sphinx_deployment.mk +117 -0
- data/examples/active_attr.rb +33 -0
- data/examples/http_failures.rb +18 -0
- data/examples/local_pdc_dev.rb +15 -0
- data/examples/logger.rb +50 -0
- data/examples/pdc_curb_access_token.rb +36 -0
- data/examples/pdc_resource_tests.rb +173 -0
- data/examples/pdc_test_cache.rb +48 -0
- data/examples/prod_failures.rb +26 -0
- data/examples/prod_pdc.rb +14 -0
- data/lib/pdc/base.rb +14 -0
- data/lib/pdc/config.rb +157 -0
- data/lib/pdc/errors.rb +8 -0
- data/lib/pdc/http/errors.rb +43 -0
- data/lib/pdc/http/request/append_slash.rb +19 -0
- data/lib/pdc/http/request.rb +12 -0
- data/lib/pdc/http/response/pagination.rb +43 -0
- data/lib/pdc/http/response/parser.rb +62 -0
- data/lib/pdc/http/response/raise_error.rb +13 -0
- data/lib/pdc/http/response.rb +3 -0
- data/lib/pdc/http/result.rb +28 -0
- data/lib/pdc/http.rb +12 -0
- data/lib/pdc/logger.rb +19 -0
- data/lib/pdc/resource/attribute_modifier.rb +43 -0
- data/lib/pdc/resource/attribute_store.rb +22 -0
- data/lib/pdc/resource/attributes.rb +144 -0
- data/lib/pdc/resource/errors.rb +3 -0
- data/lib/pdc/resource/identity.rb +75 -0
- data/lib/pdc/resource/path.rb +63 -0
- data/lib/pdc/resource/per_thread_registry.rb +54 -0
- data/lib/pdc/resource/relation/finder.rb +24 -0
- data/lib/pdc/resource/relation/pagination.rb +33 -0
- data/lib/pdc/resource/relation/query.rb +14 -0
- data/lib/pdc/resource/relation.rb +81 -0
- data/lib/pdc/resource/rest_api.rb +34 -0
- data/lib/pdc/resource/scope_registry.rb +19 -0
- data/lib/pdc/resource/scopes.rb +29 -0
- data/lib/pdc/resource/value_parser.rb +31 -0
- data/lib/pdc/resource/wip.rb +0 -0
- data/lib/pdc/resource.rb +12 -0
- data/lib/pdc/v1/arch.rb +6 -0
- data/lib/pdc/v1/product.rb +5 -0
- data/lib/pdc/v1/release.rb +18 -0
- data/lib/pdc/v1/release_variant.rb +17 -0
- data/lib/pdc/v1.rb +8 -0
- data/lib/pdc/version.rb +3 -0
- data/lib/pdc.rb +25 -0
- data/pdc.gemspec +38 -0
- data/spec/fixtures/vcr/_page_count_returns_total_count.yml +141 -0
- data/spec/fixtures/vcr/brew_can_be_nil.yml +61 -0
- data/spec/fixtures/vcr/brew_may_be_present.yml +50 -0
- data/spec/fixtures/vcr/caches_multiple_response.yml +173 -0
- data/spec/fixtures/vcr/caches_response_with_a_query.yml +64 -0
- data/spec/fixtures/vcr/caches_response_with_multiple_query.yml +64 -0
- data/spec/fixtures/vcr/caches_response_without_query.yml +61 -0
- data/spec/fixtures/vcr/can_iterate_using_each.yml +187 -0
- data/spec/fixtures/vcr/fetches_variants_of_a_release.yml +663 -0
- data/spec/fixtures/vcr/must_return_number_of_resources.yml +61 -0
- data/spec/fixtures/vcr/preserves_the_filters.yml +49 -0
- data/spec/fixtures/vcr/returns_resources_on_that_page.yml +49 -0
- data/spec/fixtures/vcr/returns_the_total_count_and_not_items_in_page.yml +135 -0
- data/spec/fixtures/vcr/should_not_be_in_the_list_of_attributes.yml +95 -0
- data/spec/fixtures/vcr/works_with_where.yml +49 -0
- data/spec/pdc/config_spec.rb +115 -0
- data/spec/pdc/http/errors_spec.rb +58 -0
- data/spec/pdc/resource/attributes_spec.rb +231 -0
- data/spec/pdc/resource/cache_spec.rb +88 -0
- data/spec/pdc/resource/count_spec.rb +45 -0
- data/spec/pdc/resource/identity_spec.rb +96 -0
- data/spec/pdc/resource/pagination_spec.rb +51 -0
- data/spec/pdc/resource/path_spec.rb +30 -0
- data/spec/pdc/resource/relation_spec.rb +94 -0
- data/spec/pdc/resource/rest_api_spec.rb +23 -0
- data/spec/pdc/resource/value_parser_spec.rb +15 -0
- data/spec/pdc/resource/wip_spec.rb +0 -0
- data/spec/pdc/v1/arch_spec.rb +34 -0
- data/spec/pdc/v1/release_spec.rb +54 -0
- data/spec/pdc/version_spec.rb +5 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/fixtures.rb +116 -0
- data/spec/support/vcr.rb +10 -0
- data/spec/support/webmock.rb +34 -0
- metadata +295 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PDC::Resource::AttributeStore do
|
4
|
+
subject { PDC::Resource::AttributeStore }
|
5
|
+
|
6
|
+
it '#to_params' do
|
7
|
+
attr = PDC::Resource::AttributeStore.new(
|
8
|
+
id: 3, 'title' => 'Fish',
|
9
|
+
groups: [
|
10
|
+
{ name: 'Dessert' }
|
11
|
+
]
|
12
|
+
)
|
13
|
+
attr.to_params.must_equal(
|
14
|
+
'id' => 3,
|
15
|
+
'title' => 'Fish',
|
16
|
+
'groups' => [{ 'name' => 'Dessert' }]
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe PDC::Resource::Attributes do
|
22
|
+
it 'returns all attributes' do
|
23
|
+
Product.attributes.wont_be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'primary_key will be in attributes by default' do
|
27
|
+
Product.attributes.must_include Product.primary_key
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'allows block initialization' do
|
31
|
+
prod = Product.new do |p|
|
32
|
+
p.name = 'RHEL'
|
33
|
+
p.description = 'Enterprise Linux'
|
34
|
+
end
|
35
|
+
assert_equal 'RHEL', prod.name
|
36
|
+
assert_equal 'Enterprise Linux', prod.description
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can handle predicate' do
|
40
|
+
stub_get('products/1').to_return_json(data: [{ id: 1, name: 'RHEL' }])
|
41
|
+
product = Product.find(1)
|
42
|
+
assert_equal true, product.name?
|
43
|
+
assert_equal false, product.description?
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'can assign a hash' do
|
47
|
+
product = Product.new(id: 2)
|
48
|
+
product.attributes = { name: 'RHEL' }
|
49
|
+
|
50
|
+
product.name.must_equal 'RHEL'
|
51
|
+
product.id.must_equal 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'can get and set value' do
|
55
|
+
product = Product.new
|
56
|
+
product.name = 'RHEL'
|
57
|
+
product.name.must_equal 'RHEL'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'works with []' do
|
61
|
+
product = Product.new(name: 'Fedora')
|
62
|
+
product[:name].must_equal 'Fedora'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'works with []=' do
|
66
|
+
product = Product.new
|
67
|
+
product[:name] = 'bar'
|
68
|
+
product.name.must_equal 'bar'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'allows assigning unknown attributes' do
|
72
|
+
product = Product.new
|
73
|
+
|
74
|
+
product.wont_respond_to :foobar
|
75
|
+
product.must_respond_to :foobar=
|
76
|
+
|
77
|
+
product.foobar = 'bar'
|
78
|
+
product.foobar.must_equal 'bar'
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#respond_to' do
|
82
|
+
it 'returns true for known attributes' do
|
83
|
+
stub_get('products/1').to_return_json(data: [{ id: 1, name: 'RHEL' }])
|
84
|
+
|
85
|
+
product = Product.find(1)
|
86
|
+
product.must_respond_to :name
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns false for unknown attributes that are not set' do
|
90
|
+
stub_get('products/1').to_return_json(data: [{ id: 1, name: 'RHEL' }])
|
91
|
+
|
92
|
+
product = Product.find(1)
|
93
|
+
product.wont_respond_to :title
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns true for unknown attributes after it is set' do
|
97
|
+
product = Product.new
|
98
|
+
product.wont_respond_to :foobar
|
99
|
+
|
100
|
+
product.foobar = 'bar'
|
101
|
+
product.must_respond_to :foobar
|
102
|
+
Product.attributes.wont_include :foobar
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'nested hash attributes' do
|
108
|
+
it 'returns OpenStruct for nested hash' do
|
109
|
+
allowed_tags = %w(foo bar baz)
|
110
|
+
stub_get('nested-models/1').to_return_json(
|
111
|
+
data: [{
|
112
|
+
id: 1, name: 'RHEL',
|
113
|
+
nested: {
|
114
|
+
tag: 'foobar',
|
115
|
+
allowed_tags: allowed_tags.clone
|
116
|
+
}
|
117
|
+
}]
|
118
|
+
)
|
119
|
+
|
120
|
+
model = NestedModel.find(1)
|
121
|
+
model.must_respond_to :nested
|
122
|
+
model.nested.must_be_instance_of OpenStruct
|
123
|
+
model.nested.must_respond_to :tag
|
124
|
+
model.nested.must_respond_to :allowed_tags
|
125
|
+
model.nested.tag.must_equal 'foobar'
|
126
|
+
model.nested.allowed_tags.must_equal allowed_tags
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns OpenStruct for deep nested hash' do
|
130
|
+
stub_get('nested-models/1').to_return_json(
|
131
|
+
data: [{
|
132
|
+
id: 1, name: 'RHEL',
|
133
|
+
nested: {
|
134
|
+
second_level: {
|
135
|
+
value: 'deep'
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}]
|
139
|
+
)
|
140
|
+
|
141
|
+
model = NestedModel.find(1)
|
142
|
+
model.must_respond_to :nested
|
143
|
+
|
144
|
+
model.nested.must_respond_to :second_level
|
145
|
+
model.nested.second_level.must_be_instance_of OpenStruct
|
146
|
+
model.nested.second_level.must_respond_to :value
|
147
|
+
model.nested.second_level.value.must_equal 'deep'
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'returns OpenStruct for even unregistered attributes' do
|
151
|
+
stub_get('nested-models/1').to_return_json(
|
152
|
+
data: [{
|
153
|
+
id: 1, name: 'RHEL',
|
154
|
+
unregistered_nested: {
|
155
|
+
value: 'unregistered'
|
156
|
+
}
|
157
|
+
}]
|
158
|
+
)
|
159
|
+
|
160
|
+
model = NestedModel.find(1)
|
161
|
+
model.must_respond_to :unregistered_nested
|
162
|
+
model.unregistered_nested.must_be_instance_of OpenStruct
|
163
|
+
model.unregistered_nested.must_respond_to :value
|
164
|
+
model.unregistered_nested.value.must_equal 'unregistered'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
describe 'Custom ValueParser' do
|
170
|
+
subject { CustomParserModel }
|
171
|
+
it 'must return fixnum for age' do
|
172
|
+
stub_get('custom-parser-models/1').to_return_json(
|
173
|
+
data: [{
|
174
|
+
id: 1, name: 'RHEL', age: '20'
|
175
|
+
}]
|
176
|
+
)
|
177
|
+
|
178
|
+
model = subject.find(1)
|
179
|
+
model.must_respond_to :age
|
180
|
+
model.age.must_be_instance_of Fixnum
|
181
|
+
model.age.must_equal 20
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# class AttributesTest < MiniTest::Test
|
186
|
+
|
187
|
+
# def test_equality
|
188
|
+
# assert_equal Product.new(id: 2, title: 'Fish'), Product.new(id: 2, title: 'Fish')
|
189
|
+
# refute_equal Product.new(id: 2, title: 'Fish'), Product.new(id: 1, title: 'Fish')
|
190
|
+
# refute_equal Product.new(id: 2, title: 'Fish'), 'not_a_spyke_object'
|
191
|
+
# refute_equal Product.new(id: 2, title: 'Fish'), Image.new(id: 2, title: 'Fish')
|
192
|
+
# refute_equal Product.new, Product.new
|
193
|
+
# refute_equal StepImage.new(id: 1), Image.new(id: 1)
|
194
|
+
# end
|
195
|
+
|
196
|
+
# def test_uniqueness
|
197
|
+
# product_1 = Product.new(id: 1)
|
198
|
+
# product_2 = Product.new(id: 1)
|
199
|
+
# product_3 = Product.new(id: 2)
|
200
|
+
# image_1 = Image.new(id: 2)
|
201
|
+
# records = [product_1, product_2, product_3, image_1]
|
202
|
+
# assert_equal [product_1, product_3, image_1], records.uniq
|
203
|
+
# end
|
204
|
+
|
205
|
+
# def test_super_with_explicit_attributes
|
206
|
+
# assert_equal nil, Product.new.description
|
207
|
+
# end
|
208
|
+
|
209
|
+
# def test_inheriting_explicit_attributes
|
210
|
+
# assert_equal nil, Image.new.description
|
211
|
+
# assert_equal nil, Image.new.caption
|
212
|
+
# assert_raises NoMethodError do
|
213
|
+
# Image.new.note
|
214
|
+
# end
|
215
|
+
# assert_equal nil, StepImage.new.description
|
216
|
+
# assert_equal nil, StepImage.new.caption
|
217
|
+
# assert_equal nil, StepImage.new.note
|
218
|
+
# end
|
219
|
+
|
220
|
+
# def test_inspect
|
221
|
+
# product = Product.new(id: 2, title: 'Pizza', description: 'Delicious')
|
222
|
+
# assert_equal '#<Product(products/(:id)) id: 2 title: "Pizza" description: "Delicious">', product.inspect
|
223
|
+
# product = Product.new
|
224
|
+
# assert_equal '#<Product(products/(:id)) id: nil >', product.inspect
|
225
|
+
# require 'pry'; binding.pry
|
226
|
+
# user = Product.new.build_user
|
227
|
+
# assert_equal '#<User(users/:uuid) id: nil >', user.inspect
|
228
|
+
# group = Product.new.groups.build
|
229
|
+
# assert_equal '#<Group(products/:product_id/groups/(:id)) id: nil product_id: nil>', group.inspect
|
230
|
+
# end
|
231
|
+
# end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop' # for Timecop.freeze
|
3
|
+
|
4
|
+
# How it works
|
5
|
+
#
|
6
|
+
# The test records http response using +vcr+ as fixtures which are
|
7
|
+
# stored under spec/fixtures/vcr directory. After the response is
|
8
|
+
# stored as fixtures, vcr will start replaying those requests when
|
9
|
+
# same url is accessed by faraday.
|
10
|
+
#
|
11
|
+
# To deal with the cache expiry, the cache_store is set to in-memory so
|
12
|
+
# that the first fetch will be missed and handled by vcr. Time is
|
13
|
+
# frozen to 2016 which makes the cache valid/fresh after it is
|
14
|
+
# fetched/played once by vcr.
|
15
|
+
|
16
|
+
# NOTE: disable webmock to record a new test
|
17
|
+
# WebMock.disable!
|
18
|
+
|
19
|
+
# returns http cache status for all http calls made
|
20
|
+
# using faraday in the +&block+ passed
|
21
|
+
def record_cache_access(&block)
|
22
|
+
cache_access = []
|
23
|
+
record_status = lambda do |*args|
|
24
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
25
|
+
cache_access << event.payload[:cache_status]
|
26
|
+
end
|
27
|
+
ActiveSupport::Notifications.subscribed(record_status, 'http_cache.faraday', &block)
|
28
|
+
cache_access
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe 'Caching' do
|
33
|
+
before do
|
34
|
+
@old_config = PDC.config
|
35
|
+
config = @old_config.clone
|
36
|
+
config.disable_caching = false
|
37
|
+
config.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
|
38
|
+
|
39
|
+
PDC.config = config
|
40
|
+
|
41
|
+
VCR.insert_cassette fixture_name
|
42
|
+
Timecop.travel(Time.local(2016)) # based on fixtures
|
43
|
+
end
|
44
|
+
|
45
|
+
after do
|
46
|
+
Timecop.return
|
47
|
+
VCR.eject_cassette
|
48
|
+
PDC.config = @old_config
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'caches response without query' do
|
52
|
+
cache = record_cache_access { PDC::V1::Release.scoped.contents! }
|
53
|
+
cache.must_equal [:miss]
|
54
|
+
|
55
|
+
cache = record_cache_access { PDC::V1::Release.scoped.contents! }
|
56
|
+
cache.must_equal [:fresh]
|
57
|
+
|
58
|
+
cache = record_cache_access { PDC::V1::Release.scoped.contents! }
|
59
|
+
cache.must_equal [:fresh]
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'caches response with a query' do
|
63
|
+
cache = record_cache_access { PDC::V1::Release.page(2).contents! }
|
64
|
+
cache.must_equal [:miss]
|
65
|
+
|
66
|
+
cache = record_cache_access { PDC::V1::Release.page(2).contents! }
|
67
|
+
cache.must_equal [:fresh]
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'caches response with multiple query' do
|
71
|
+
cache = record_cache_access do
|
72
|
+
PDC::V1::Release.page(2).page_size(30).contents!
|
73
|
+
PDC::V1::Release.page(2).page_size(30).contents!
|
74
|
+
end
|
75
|
+
cache.must_equal [:miss, :fresh]
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'caches multiple response' do
|
79
|
+
cache = record_cache_access { PDC::V1::Release.where(active: true).all }
|
80
|
+
|
81
|
+
# must paginate so at least 2 pages
|
82
|
+
cache.length.must_be :>=, 2
|
83
|
+
cache.must_equal [:miss] * cache.length
|
84
|
+
|
85
|
+
second_time = record_cache_access { PDC::V1::Release.where(active: true).all }
|
86
|
+
second_time.must_equal [:fresh] * cache.length
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
#WebMock.disable! # enable to re-record
|
4
|
+
|
5
|
+
describe PDC do
|
6
|
+
before do
|
7
|
+
VCR.insert_cassette fixture_name
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
VCR.eject_cassette
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'count' do
|
15
|
+
let(:release) { PDC::V1::Release }
|
16
|
+
let(:arch) { PDC::V1::Arch }
|
17
|
+
|
18
|
+
it 'must return number of resources' do
|
19
|
+
count = release.count
|
20
|
+
count.must_equal 54
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'works with where' do
|
24
|
+
count = release.where(active: false).count
|
25
|
+
count.must_equal 0
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns the total count and not items in page' do
|
29
|
+
total_count = arch.count
|
30
|
+
page_count = arch.page(2).count
|
31
|
+
page_count.must_equal total_count
|
32
|
+
|
33
|
+
arch_in_page = arch.page(2).contents!
|
34
|
+
arch_in_page.length.must_be :<, page_count
|
35
|
+
end
|
36
|
+
|
37
|
+
it '.page.count returns total count' do
|
38
|
+
pg2 = arch.page(2)
|
39
|
+
pg2_count = pg2.all.length
|
40
|
+
|
41
|
+
arches_count = pg2.count # must return all arches count
|
42
|
+
arches_count.wont_equal pg2_count
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ap'
|
3
|
+
|
4
|
+
describe ModelWithIdentity do
|
5
|
+
subject { ModelWithIdentity }
|
6
|
+
|
7
|
+
describe '##primary_key' do
|
8
|
+
it 'must exist' do
|
9
|
+
class_methods = subject.methods - subject.instance_methods
|
10
|
+
class_methods.must_include :primary_key
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'must default to class_name_id' do
|
14
|
+
subject.primary_key.must_equal 'model_with_identity_id'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'uri' do
|
19
|
+
it 'must have a default uri' do
|
20
|
+
subject.uri.wont_be_nil
|
21
|
+
subject.uri.must_equal 'fixtures/model-with-identities/(:model_with_identity_id)'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns path with variables expanded for an object' do
|
25
|
+
instance = subject.new(subject.primary_key => :foobar)
|
26
|
+
expected_uri = PDC::Resource::Path.new('fixtures/model-with-identities/foobar').expanded
|
27
|
+
instance.uri.must_equal expected_uri
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'new' do
|
32
|
+
it 'returns nil for id' do
|
33
|
+
object = subject.new
|
34
|
+
object.id.must_be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'can accept primary_key' do
|
38
|
+
pkey = subject.primary_key
|
39
|
+
instance = subject.new(pkey => 'something')
|
40
|
+
instance.id.must_equal 'something'
|
41
|
+
instance.model_with_identity_id.must_equal 'something'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe CustomPrimaryKeyModel do
|
47
|
+
subject { CustomPrimaryKeyModel }
|
48
|
+
|
49
|
+
describe '##primary_key' do
|
50
|
+
it 'can be set' do
|
51
|
+
subject.primary_key.must_equal :foobar
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can accept primary_key' do
|
56
|
+
pkey = subject.primary_key
|
57
|
+
object = subject.new(pkey => 'something')
|
58
|
+
object.id.must_equal 'something'
|
59
|
+
object.foobar.must_equal 'something'
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'uri' do
|
63
|
+
it 'must use custom primary_key' do
|
64
|
+
subject.uri.must_equal 'fixtures/custom-primary-key-models/(:foobar)'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
describe V1::Foobar do
|
71
|
+
subject { V1::Foobar }
|
72
|
+
it 'must have a pkey' do
|
73
|
+
subject.primary_key.must_equal 'foobar_id'
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'must have a uri' do
|
77
|
+
subject.uri.must_equal 'fixtures/v1/foobars/(:foobar_id)'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'attributes' do
|
82
|
+
it 'base must have primary key' do
|
83
|
+
ModelBase.new.id.must_be_nil
|
84
|
+
base = ModelBase.new(model_base_id: 1)
|
85
|
+
base.id.must_equal 1
|
86
|
+
base.attributes.must_include :model_base_id
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'sub must not have primary key of base' do
|
90
|
+
Model.new.id.must_be_nil
|
91
|
+
model = Model.new(model_id: 3)
|
92
|
+
model.id.must_equal 3
|
93
|
+
model.attributes.must_include :model_id
|
94
|
+
model.attributes.wont_include :model_base_id
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PDC do
|
4
|
+
before do
|
5
|
+
VCR.insert_cassette fixture_name
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
VCR.eject_cassette
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'pagination' do
|
13
|
+
let(:arch) { PDC::V1::Arch }
|
14
|
+
let(:release_variant) { PDC::V1::ReleaseVariant }
|
15
|
+
|
16
|
+
it 'can iterate using each' do
|
17
|
+
count = arch.count # makes single call
|
18
|
+
|
19
|
+
all = arch.scoped.each_with_object([]) do |a, o|
|
20
|
+
o << a
|
21
|
+
end
|
22
|
+
count.must_equal all.length
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'preserves the filters' do
|
26
|
+
variants = release_variant.where(type: 'variant', name: 'rh-common')
|
27
|
+
count = variants.count
|
28
|
+
|
29
|
+
all = variants.each_with_object([]) do |a, o|
|
30
|
+
o << a
|
31
|
+
end
|
32
|
+
count.must_equal all.length
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'page' do
|
37
|
+
subject { PDC::V1::Arch }
|
38
|
+
it 'returns resources on that page' do
|
39
|
+
pg2 = subject.page(2)
|
40
|
+
resources = pg2.contents!
|
41
|
+
resources.length.must_equal 20
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not be in the list of attributes' do
|
45
|
+
pg2 = subject.page(2)
|
46
|
+
arch = pg2.all.first
|
47
|
+
arch.attributes.wont_include :page
|
48
|
+
arch.attributes.wont_include 'page'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PDC::Resource::Path do
|
4
|
+
subject { PDC::Resource::Path }
|
5
|
+
|
6
|
+
it 'can handle optional variables' do
|
7
|
+
assert_equal '/recipes/(:id)', subject.new('/recipes/(:id)').to_s
|
8
|
+
assert_equal '/recipes', subject.new('/recipes/(:id)').expanded
|
9
|
+
assert_equal '/recipes/2', subject.new('/recipes/(:id)', id: 2).expanded
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'nested collections' do
|
13
|
+
path = subject.new('/users/:user_id/recipes/(:id)',
|
14
|
+
user_id: 1, status: 'published')
|
15
|
+
|
16
|
+
assert_equal [:user_id, :id], path.variables
|
17
|
+
assert_equal '/users/1/recipes', path.expanded
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
it 'nested_resource_path' do
|
22
|
+
assert_equal '/users/1/recipes/2', subject.new('/users/:user_id/recipes/:id', user_id: 1, id: 2).expanded
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises if required_params are missing' do
|
26
|
+
lambda {
|
27
|
+
subject.new('/users/:user_id/recipes/(:id)', id: 2).expanded
|
28
|
+
}.must_raise PDC::InvalidPathError, 'Missing required params: user_id in /users/:user_id/recipes/(:id)'
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class SearchableModel < Base
|
4
|
+
attributes :name, :product
|
5
|
+
|
6
|
+
### NOTE: where() will have no impact since the data is hardcoded
|
7
|
+
def self.fake_data
|
8
|
+
[
|
9
|
+
{ name: 'foobar-1', product: 'prod' },
|
10
|
+
{ name: 'foobar-2', product: 'prod' },
|
11
|
+
{ name: 'foobar-3', product: 'prod' },
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.fetch(params)
|
16
|
+
response = OpenStruct.new(
|
17
|
+
body: { data: fake_data },
|
18
|
+
status: 200,
|
19
|
+
env: OpenStruct.new(url: 'http://foobar')
|
20
|
+
)
|
21
|
+
|
22
|
+
PDC::Http::Result.new(response)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe SearchableModel do
|
27
|
+
subject { SearchableModel }
|
28
|
+
|
29
|
+
|
30
|
+
describe '#where' do
|
31
|
+
it 'returns a scope with params' do
|
32
|
+
filters = { name: :foobar, age: 10 }
|
33
|
+
rel = subject.where(filters)
|
34
|
+
|
35
|
+
rel.must_be_instance_of PDC::Resource::Relation
|
36
|
+
rel.params.must_equal(filters)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can be called multiple times' do
|
40
|
+
filter_name = { name: :foobar }
|
41
|
+
filter_age = { age: 10 }
|
42
|
+
|
43
|
+
rel = subject.where(filter_name).where(filter_age)
|
44
|
+
.where(filter_name)
|
45
|
+
rel.must_be_instance_of PDC::Resource::Relation
|
46
|
+
|
47
|
+
filters = filter_name.merge(filter_age)
|
48
|
+
rel.params.must_equal filters
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#find' do
|
53
|
+
let(:one_result) { [{ name: 'foobar2', product: 'prod' }] }
|
54
|
+
let(:no_result) { [] }
|
55
|
+
|
56
|
+
it 'returns a record' do
|
57
|
+
subject.stub(:fake_data, one_result) do
|
58
|
+
result = subject.find(:foobar)
|
59
|
+
result.must_be_instance_of SearchableModel
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'raises MultipleResultsError more than a record exists' do
|
64
|
+
-> { subject.find(:foobar) }.must_raise PDC::MultipleResultsError
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'raise ResourceNotFound when no record exists' do
|
68
|
+
subject.stub(:fake_data, no_result) do
|
69
|
+
-> { subject.find(:foobar) }.must_raise PDC::ResourceNotFound
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can call first' do
|
75
|
+
first = subject.first
|
76
|
+
first.must_be_instance_of subject
|
77
|
+
first.name.must_equal subject.fake_data.first[:name]
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'relation' do
|
81
|
+
it 'can call all on a relation' do
|
82
|
+
relation = subject.where(name: :foobar)
|
83
|
+
relation.must_be_instance_of PDC::Resource::Relation
|
84
|
+
results = relation.all
|
85
|
+
results.length.must_equal subject.fake_data.length
|
86
|
+
results.first.must_be_instance_of subject
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'all works with resource' do
|
90
|
+
results = subject.all
|
91
|
+
results.length.must_equal subject.fake_data.length
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe :find do
|
4
|
+
it 'finds a specific resource' do
|
5
|
+
stub_get('products/1')
|
6
|
+
.to_return_json(data: [{ product_id: 1, title: 'foobar' }])
|
7
|
+
|
8
|
+
product = Fixtures::Product.find(1)
|
9
|
+
product.id.must_equal 1
|
10
|
+
product.product_id.must_equal 1
|
11
|
+
product.title.must_equal 'foobar'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'must work when primary_key is user defined' do
|
15
|
+
stub_get('product-variants/v2')
|
16
|
+
.to_return_json(data: [{ v_id: 'v2', title: 'variant' }])
|
17
|
+
|
18
|
+
variant = Fixtures::ProductVariant.find('v2')
|
19
|
+
variant.id.must_equal 'v2'
|
20
|
+
variant.v_id.must_equal 'v2'
|
21
|
+
variant.title.must_equal 'variant'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PDC::Resource::ValueParser do
|
4
|
+
subject { PDC::Resource::ValueParser }
|
5
|
+
|
6
|
+
it 'must respond_to? parse' do
|
7
|
+
subject.must_respond_to :parse
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#parse' do
|
11
|
+
it 'must return value for plain types' do
|
12
|
+
subject.parse(:foobar).must_equal :foobar
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
File without changes
|