flexirest 1.11.0 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
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