flexirest 1.11.0 → 1.11.1

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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3c99c9dcb4b2b2d6b4992a53d138877f251f0810bb94dc11faf9d9e1b89f9cb
4
- data.tar.gz: 22554cafc10d12337c1511828ab27471dbadf36de4e211c5383eae96c4fb4c34
3
+ metadata.gz: '036069384b97e0fbcf4e73c9e75154569cffbb9cbfcb8dfcda4ccfc4ef75cca2'
4
+ data.tar.gz: 3099f07f5284601a68ebba405a60e485975635b5306b72f2ead2090509bdb901
5
5
  SHA512:
6
- metadata.gz: 3cf855f9fbc7d4f213a19840e11cfa9b816de9b1a0750726538f288f559ec150c7a05a4ae8b63297e8aedcf8002103e2e4ae275cb497793144c83aebc7f7577e
7
- data.tar.gz: e1a5b90ace51f341a340e5ed32f5c8afc30f2784a38cf7281c621157a8b1233da9b81180ed6a5dc0694f4ac72933793b9e47dcf01d9389583b02bdd7dc3aefbd
6
+ metadata.gz: 18d64a00ceea9f1a9ee61dcdaedf64dbcc8eae7b9f4f3d20943e7b9209dd7d98acd08138a9c149d0f7cb7aa03740131030580c45f4d153e2f47df999e6415a61
7
+ data.tar.gz: 026a430bdc41b68adc6e46c42dc69983fca9ef431fb3cc068c96fb3714c687209393d15e66879bb46c3f26ba3f9e38dd08b94620a7d8b2f20d392f08690031fd
@@ -24,10 +24,7 @@ jobs:
24
24
  steps:
25
25
  - uses: actions/checkout@v2
26
26
  - name: Set up Ruby
27
- # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
- # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
- # uses: ruby/setup-ruby@v1
30
- uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
27
+ uses: ruby/setup-ruby@v1
31
28
  with:
32
29
  ruby-version: ${{ matrix.ruby-version }}
33
30
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.11.1
4
+
5
+ Enhancement:
6
+
7
+ - Add automatic expiry of cached responses based on the Expires header if set (thanks to Romain Gisiger for the issue and PR)
8
+
3
9
  ## 1.11.0
4
10
 
5
11
  Major change:
data/flexirest.gemspec CHANGED
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency 'faraday-typhoeus'
37
37
  spec.add_development_dependency 'activemodel'
38
38
  spec.add_development_dependency 'rest-client'
39
+ spec.add_development_dependency 'timecop'
39
40
 
40
41
  spec.add_runtime_dependency "mime-types"
41
42
  spec.add_runtime_dependency "multi_json"
@@ -74,7 +74,14 @@ module Flexirest
74
74
  cached_response.etag = "#{headers[:etag]}" if headers[:etag]
75
75
  cached_response.expires = Time.parse(headers[:expires]) rescue nil if headers[:expires]
76
76
  if cached_response.etag.present? || cached_response.expires
77
- cache_store.write(key, Marshal.dump(cached_response), {})
77
+ options = {}
78
+ if cached_response.expires.present?
79
+ exp_in_seconds = cached_response.expires.utc - Time.now.utc
80
+ return unless exp_in_seconds.positive?
81
+
82
+ options[:expires_in] = exp_in_seconds
83
+ end
84
+ cache_store.write(key, Marshal.dump(cached_response), options)
78
85
  end
79
86
  end
80
87
  end
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.11.0"
2
+ VERSION = "1.11.1"
3
3
  end
@@ -72,28 +72,21 @@ describe Flexirest::Caching do
72
72
  end
73
73
 
74
74
  it "should use a custom cache store if a valid one is manually set" do
75
- class CachingExampleCacheStore1
76
- def read(key) ; end
77
- def write(key, value, options={}) ; end
78
- def fetch(key, &block) ; end
79
- end
75
+ class CachingExampleCacheStore1 < ActiveSupport::Cache::MemoryStore; end
80
76
  cache_store = CachingExampleCacheStore1.new
81
77
  Flexirest::Base.cache_store = cache_store
82
78
  expect(Flexirest::Base.cache_store).to eq(cache_store)
83
79
  end
84
80
 
85
81
  it "should error if you try to use a custom cache store that doesn't match the required interface" do
86
- class CachingExampleCacheStore2
87
- def write(key, value, options={}) ; end
88
- def fetch(key, &block) ; end
82
+ class CachingExampleCacheStore2 < ActiveSupport::Cache::MemoryStore
83
+ undef_method :read
89
84
  end
90
- class CachingExampleCacheStore3
91
- def read(key) ; end
92
- def fetch(key, &block) ; end
85
+ class CachingExampleCacheStore3 < ActiveSupport::Cache::MemoryStore
86
+ undef_method :write
93
87
  end
94
- class CachingExampleCacheStore4
95
- def read(key) ; end
96
- def write(key, value, options={}) ; end
88
+ class CachingExampleCacheStore4 < ActiveSupport::Cache::MemoryStore
89
+ undef_method :fetch
97
90
  end
98
91
 
99
92
  expect{ Flexirest::Base.cache_store = CachingExampleCacheStore2.new }.to raise_error(Flexirest::InvalidCacheStoreException)
@@ -109,11 +102,7 @@ describe Flexirest::Caching do
109
102
  context "Reading/writing to the cache" do
110
103
  before :each do
111
104
  Object.send(:remove_const, :CachingExampleCacheStore5) if defined?(CachingExampleCacheStore5)
112
- class CachingExampleCacheStore5
113
- def read(key) ; end
114
- def write(key, value, options={}) ; end
115
- def fetch(key, &block) ; end
116
- end
105
+ class CachingExampleCacheStore5 < ActiveSupport::Cache::MemoryStore; end
117
106
 
118
107
  class Person < Flexirest::Base
119
108
  perform_caching true
@@ -122,7 +111,7 @@ describe Flexirest::Caching do
122
111
  put :save_all, "/"
123
112
  end
124
113
 
125
- Person.cache_store = CachingExampleCacheStore5.new
114
+ Person.cache_store = CachingExampleCacheStore5.new({ expires_in: 1.day.to_i }) # default cache expiration
126
115
 
127
116
  @etag = "6527914a91e0c5769f6de281f25bd891"
128
117
  @cached_object = Person.new(first_name:"Johnny")
@@ -173,7 +162,7 @@ describe Flexirest::Caching do
173
162
  expect(result.first_name).to eq new_name
174
163
  end
175
164
 
176
- it "should read from the cache store, and not call the server if there's a hard expiry" do
165
+ it "should read from the cache store, and not call the server if there's a hard expiry not passed yet" do
177
166
  cached_response = Flexirest::CachedResponse.new(
178
167
  status:200,
179
168
  result:@cached_object,
@@ -184,6 +173,18 @@ describe Flexirest::Caching do
184
173
  expect(ret.first_name).to eq("Johnny")
185
174
  end
186
175
 
176
+ it "should not read from the cache store, and call the server if there's a hard expiry already passed" do
177
+ cached_response = Flexirest::CachedResponse.new(
178
+ status:200,
179
+ result:@cached_object,
180
+ expires:Time.now + 30)
181
+ Timecop.travel(Time.now + 60)
182
+ expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
183
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, body:"{\"result\":true}", response_headers:{})))
184
+ ret = Person.all
185
+ Timecop.return
186
+ end
187
+
187
188
  it "cache read objects shouldn't be marked as changed" do
188
189
  cached_response = Flexirest::CachedResponse.new(
189
190
  status:200,
@@ -208,7 +209,7 @@ describe Flexirest::Caching do
208
209
  expect(ret.first_name).to eq("Johnny")
209
210
  end
210
211
 
211
- it "should restore a result iterator from the cache store, if there's a hard expiry" do
212
+ it "should restore a result iterator from the cache store, if there's a hard expiry not passed yet" do
212
213
  class CachingExample3 < Flexirest::Base ; end
213
214
  object = Flexirest::ResultIterator.new(double(status: 200))
214
215
  object << CachingExample3.new(first_name:"Johnny")
@@ -226,6 +227,26 @@ describe Flexirest::Caching do
226
227
  expect(ret._status).to eq(200)
227
228
  end
228
229
 
230
+ it "should not restore a result iterator from the cache store, if there's a hard expiry already passed" do
231
+ class CachingExample3 < Flexirest::Base ; end
232
+ object = Flexirest::ResultIterator.new(double(status: 200))
233
+ object << CachingExample3.new(first_name:"Johnny")
234
+ object << CachingExample3.new(first_name:"Billy")
235
+ etag = "6527914a91e0c5769f6de281f25bd891"
236
+ cached_response = Flexirest::CachedResponse.new(
237
+ status:200,
238
+ result:object,
239
+ etag:etag,
240
+ expires:Time.now + 30)
241
+ Timecop.travel(Time.now + 60)
242
+ expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
243
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, body:"[{\"first_name\":\"Billy\"}]", response_headers:{})))
244
+ ret = Person.all
245
+ expect(ret.first.first_name).to eq("Billy")
246
+ expect(ret._status).to eq(200)
247
+ Timecop.return
248
+ end
249
+
229
250
  it "should not write the response to the cache unless it has caching headers" do
230
251
  expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
231
252
  expect_any_instance_of(CachingExampleCacheStore5).not_to receive(:write)
@@ -233,9 +254,9 @@ describe Flexirest::Caching do
233
254
  Person.all
234
255
  end
235
256
 
236
- it "should write the response to the cache if there's an etag" do
257
+ it "should write the response to the cache without expires_in option if there's an etag" do
237
258
  expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
238
- expect_any_instance_of(CachingExampleCacheStore5).to receive(:write).once.with("Person:/", an_instance_of(String), {})
259
+ expect_any_instance_of(CachingExampleCacheStore5).to receive(:write).once.with("Person:/", an_instance_of(String), hash_excluding(:expires_in))
239
260
  expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, body:"{\"result\":true}", response_headers:{etag:"1234567890"})))
240
261
  Person.perform_caching true
241
262
  Person.all
@@ -264,14 +285,22 @@ describe Flexirest::Caching do
264
285
  end
265
286
  end
266
287
 
267
- it "should write the response to the cache if there's a hard expiry" do
288
+ it "should write the response to the cache with expires_in option if there's a hard expiry in the future" do
268
289
  expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
269
- expect_any_instance_of(CachingExampleCacheStore5).to receive(:write).once.with("Person:/", an_instance_of(String), an_instance_of(Hash))
290
+ expect_any_instance_of(CachingExampleCacheStore5).to receive(:write).once.with("Person:/", an_instance_of(String), hash_including(:expires_in))
270
291
  expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, body:"{\"result\":true}", response_headers:{expires:(Time.now + 30).rfc822})))
271
292
  Person.perform_caching = true
272
293
  Person.all
273
294
  end
274
295
 
296
+ it "should not write the response to the cache if there's a hard expiry in the past" do
297
+ expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
298
+ expect_any_instance_of(CachingExampleCacheStore5).not_to receive(:write)
299
+ expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, body:"{\"result\":true}", response_headers:{expires:(Time.now - 10).rfc822})))
300
+ Person.perform_caching = true
301
+ Person.all
302
+ end
303
+
275
304
  it "should not write the response to the cache if there's an invalid expiry" do
276
305
  expect_any_instance_of(CachingExampleCacheStore5).to receive(:read).once.with("Person:/").and_return(nil)
277
306
  expect_any_instance_of(CachingExampleCacheStore5).to_not receive(:write).once.with("Person:/", an_instance_of(String), an_instance_of(Hash))
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@ require 'simplecov'
3
3
  require 'flexirest'
4
4
  require "ostruct"
5
5
  require 'webmock/rspec'
6
+ require 'timecop'
6
7
 
7
8
  if ENV["JENKINS"]
8
9
  require 'simplecov-rcov'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexirest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: 1.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-03 00:00:00.000000000 Z
11
+ date: 2023-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: timecop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
181
195
  - !ruby/object:Gem::Dependency
182
196
  name: mime-types
183
197
  requirement: !ruby/object:Gem::Requirement
@@ -393,7 +407,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
393
407
  - !ruby/object:Gem::Version
394
408
  version: '0'
395
409
  requirements: []
396
- rubygems_version: 3.3.7
410
+ rubygems_version: 3.4.6
397
411
  signing_key:
398
412
  specification_version: 4
399
413
  summary: This gem is for accessing REST services in a flexible way. ActiveResource