alephant-broker 3.14.0 → 3.15.0

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +22 -9
  3. data/README.md +35 -6
  4. data/alephant-broker.gemspec +3 -2
  5. data/lib/alephant/broker/cache.rb +1 -0
  6. data/lib/alephant/broker/cache/cached_object.rb +71 -0
  7. data/lib/alephant/broker/cache/client.rb +29 -17
  8. data/lib/alephant/broker/cache/null_client.rb +12 -4
  9. data/lib/alephant/broker/component.rb +3 -1
  10. data/lib/alephant/broker/component_meta.rb +2 -0
  11. data/lib/alephant/broker/error_component.rb +1 -1
  12. data/lib/alephant/broker/load_strategy.rb +1 -0
  13. data/lib/alephant/broker/load_strategy/http.rb +2 -3
  14. data/lib/alephant/broker/load_strategy/revalidate/fetcher.rb +51 -0
  15. data/lib/alephant/broker/load_strategy/revalidate/refresher.rb +75 -0
  16. data/lib/alephant/broker/load_strategy/revalidate/strategy.rb +86 -0
  17. data/lib/alephant/broker/load_strategy/s3/base.rb +2 -2
  18. data/lib/alephant/broker/response/asset.rb +1 -1
  19. data/lib/alephant/broker/response/base.rb +7 -8
  20. data/lib/alephant/broker/response/batch.rb +1 -1
  21. data/lib/alephant/broker/version.rb +1 -1
  22. data/spec/alephant/broker/cache/cached_object_spec.rb +107 -0
  23. data/spec/alephant/broker/load_strategy/http_spec.rb +5 -7
  24. data/spec/alephant/broker/load_strategy/revalidate/fetcher_spec.rb +88 -0
  25. data/spec/alephant/broker/load_strategy/revalidate/refresher_spec.rb +69 -0
  26. data/spec/alephant/broker/load_strategy/revalidate/strategy_spec.rb +185 -0
  27. data/spec/fixtures/json/batch_compiled_no_sequence.json +1 -0
  28. data/spec/integration/not_modified_response_spec.rb +4 -6
  29. data/spec/integration/rack_spec.rb +0 -3
  30. data/spec/integration/revalidate_spec.rb +174 -0
  31. data/spec/spec_helper.rb +1 -0
  32. metadata +99 -55
@@ -0,0 +1,185 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Alephant::Broker::LoadStrategy::Revalidate::Strategy do
4
+ subject { described_class.new }
5
+
6
+ let(:lookup_double) { instance_double(Alephant::Lookup::LookupHelper) }
7
+ let(:storage_double) { instance_double(Alephant::Storage) }
8
+ let(:refresher_double) { instance_double(Alephant::Broker::LoadStrategy::Revalidate::Refresher) }
9
+ let(:fetcher_double) { instance_double(Alephant::Broker::LoadStrategy::Revalidate::Fetcher) }
10
+
11
+ let(:content) do
12
+ {
13
+ content: 'Test',
14
+ content_type: 'test/content',
15
+ meta: {
16
+ :ttl => 100,
17
+ :head_ETag => '123',
18
+ :'head_Last-Modified' => Time.now.to_s
19
+ }
20
+ }
21
+ end
22
+
23
+ let(:expected_content) do
24
+ {
25
+ content: content[:content],
26
+ content_type: content[:content_type],
27
+ meta: content[:meta]
28
+ }
29
+ end
30
+
31
+ let(:cached_obj) do
32
+ Alephant::Broker::Cache::CachedObject.new(content)
33
+ end
34
+
35
+ let(:component_meta) do
36
+ Alephant::Broker::ComponentMeta.new('test', 'test_batch', {})
37
+ end
38
+
39
+ before do
40
+ allow_any_instance_of(Logger).to receive(:info)
41
+ allow_any_instance_of(Logger).to receive(:debug)
42
+ allow(Alephant::Broker).to receive(:config).and_return({})
43
+ allow(Thread).to receive(:new).and_yield
44
+ end
45
+
46
+ describe '#load' do
47
+ context 'when there is content in the cache' do
48
+ let(:cache) { subject.send(:cache) }
49
+
50
+ before do
51
+ allow(cache).to receive(:get).and_return(cached_obj)
52
+ end
53
+
54
+ context 'which is still fresh' do
55
+ before do
56
+ allow(cached_obj).to receive(:expired?).and_return(false)
57
+ end
58
+
59
+ it 'gets fetched from the cache and returned' do
60
+ expect(subject.load(component_meta)).to eq(expected_content)
61
+ end
62
+
63
+ it 'does NOT try to refresh the content' do
64
+ expect(Alephant::Broker::LoadStrategy::Revalidate::Refresher)
65
+ .to_not receive(:new)
66
+
67
+ subject.load(component_meta)
68
+ end
69
+ end
70
+
71
+ context 'which has expired' do
72
+ before do
73
+ allow(cached_obj).to receive(:expired?).and_return(true)
74
+
75
+ allow(Alephant::Broker::LoadStrategy::Revalidate::Refresher)
76
+ .to receive(:new)
77
+ .with(component_meta)
78
+ .and_return(refresher_double)
79
+
80
+ allow(refresher_double).to receive(:refresh)
81
+
82
+ allow(Alephant::Broker::LoadStrategy::Revalidate::Fetcher)
83
+ .to receive(:new)
84
+ .with(component_meta)
85
+ .and_return(fetcher_double)
86
+
87
+ allow(fetcher_double).to receive(:fetch).and_return(cached_obj)
88
+ end
89
+
90
+ it 'it gets fetched from the cache and returned to the user' do
91
+ expect(subject.load(component_meta)).to eq(expected_content)
92
+ end
93
+
94
+ context 'in the background...' do
95
+ let(:new_content) { { id: 'test', batch_id: '', meta: {} } }
96
+ let(:new_cached_obj) { Alephant::Broker::Cache::CachedObject.new(new_content) }
97
+
98
+ it 'checks the fetcher, to see if there is newer content (in S3)' do
99
+ expect(fetcher_double).to receive(:fetch).and_return(new_cached_obj)
100
+
101
+ subject.load(component_meta)
102
+ end
103
+
104
+ context 'when there IS newer, non-expired content' do
105
+ let(:cache) { subject.send(:cache) }
106
+
107
+ before do
108
+ expect(fetcher_double).to receive(:fetch).and_return(new_cached_obj)
109
+ expect(new_cached_obj).to receive(:expired?).and_return(false)
110
+ end
111
+
112
+ it 'replaces the cached content' do
113
+ expect(cache).to receive(:set).with(component_meta.component_key, new_cached_obj)
114
+
115
+ subject.load(component_meta)
116
+ end
117
+ end
118
+
119
+ context 'when there IS NOT newer content' do
120
+ before do
121
+ expect(fetcher_double).to receive(:fetch).and_return(new_cached_obj)
122
+ expect(new_cached_obj).to receive(:expired?).and_return(true)
123
+ end
124
+
125
+ it 'kicks off a refresh of the content (from the renderer)' do
126
+ expect(refresher_double).to receive(:refresh)
127
+
128
+ subject.load(component_meta)
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ context 'when there is NOT content in the cache' do
136
+ before do
137
+ allow(Alephant::Broker::LoadStrategy::Revalidate::Fetcher)
138
+ .to receive(:new)
139
+ .with(component_meta)
140
+ .and_return(fetcher_double)
141
+ end
142
+
143
+ it 'returns the data as expected' do
144
+ expect(fetcher_double).to receive(:fetch).and_return(cached_obj)
145
+ expect(subject.load(component_meta)).to eq(expected_content)
146
+ end
147
+
148
+ it 'uses the fetcher to get the data' do
149
+ expect(fetcher_double).to receive(:fetch).and_return(cached_obj)
150
+ subject.load(component_meta)
151
+ end
152
+
153
+ context 'and there is nothing returned from the fetcher' do
154
+ before do
155
+ allow(fetcher_double)
156
+ .to receive(:fetch)
157
+ .and_raise(Alephant::Broker::Errors::ContentNotFound)
158
+
159
+ expect(Alephant::Broker::LoadStrategy::Revalidate::Refresher)
160
+ .to receive(:new)
161
+ .with(component_meta)
162
+ .and_return(refresher_double)
163
+
164
+ allow(refresher_double)
165
+ .to receive(:refresh)
166
+ end
167
+
168
+ it 'kicks off a refresh of the content' do
169
+ expect(refresher_double).to receive(:refresh)
170
+ subject.load(component_meta)
171
+ end
172
+
173
+ it 'returns a response that will invoke a 202 (HTTP) response' do
174
+ expected_response = {
175
+ content: '',
176
+ content_type: 'text/html',
177
+ meta: { status: 202 }
178
+ }
179
+
180
+ expect(subject.load(component_meta)).to eq(expected_response)
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1 @@
1
+ {"batch_id":"baz","components":[{"component":"ni_council_results_table","options":{"foo":"bar"},"status":200,"content_type":"test/content","body":"Test"},{"component":"ni_council_results_table","options":{},"status":200,"content_type":"test/content","body":"Test"}]}
@@ -50,8 +50,6 @@ describe Alephant::Broker::Application do
50
50
 
51
51
  let(:s3_double) { instance_double("Alephant::Storage", :get => content) }
52
52
 
53
- let(:not_modified_status_code) { Alephant::Broker::Response::Base::NOT_MODIFIED_STATUS_CODE }
54
-
55
53
  before do
56
54
  allow_any_instance_of(Logger).to receive(:info)
57
55
  allow_any_instance_of(Logger).to receive(:debug)
@@ -69,8 +67,8 @@ describe Alephant::Broker::Application do
69
67
  )
70
68
  end
71
69
 
72
- specify { expect(last_response.status).to eql not_modified_status_code }
73
- specify { expect(last_response.body).to eql "" }
70
+ specify { expect(last_response.status).to eql(304) }
71
+ specify { expect(last_response.body).to eql("") }
74
72
  specify { expect(last_response.headers).to_not include("Cache-Control") }
75
73
  specify { expect(last_response.headers).to_not include("Pragma") }
76
74
  specify { expect(last_response.headers).to_not include("Expires") }
@@ -199,8 +197,8 @@ describe Alephant::Broker::Application do
199
197
  )
200
198
  end
201
199
 
202
- specify { expect(last_response.status).to eql not_modified_status_code }
203
- specify { expect(last_response.body).to eq "" }
200
+ specify { expect(last_response.status).to eql(304) }
201
+ specify { expect(last_response.body).to eq("") }
204
202
 
205
203
  describe "response should have headers" do
206
204
  it "should not have a Content-Type header" do
@@ -1,5 +1,4 @@
1
1
  require_relative "spec_helper"
2
- require "alephant/broker"
3
2
 
4
3
  describe Alephant::Broker::Application do
5
4
  include Rack::Test::Methods
@@ -49,8 +48,6 @@ describe Alephant::Broker::Application do
49
48
 
50
49
  let(:s3_double) { instance_double("Alephant::Storage", :get => content) }
51
50
 
52
- let(:not_modified_status_code) { Alephant::Broker::Response::Base::NOT_MODIFIED_STATUS_CODE }
53
-
54
51
  before do
55
52
  allow_any_instance_of(Logger).to receive(:info)
56
53
  allow_any_instance_of(Logger).to receive(:debug)
@@ -0,0 +1,174 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Alephant::Broker::Application do
4
+ include Rack::Test::Methods
5
+
6
+ let(:config) do
7
+ {
8
+ aws_account_id: '12345',
9
+ lookup_table_name: 'test_table',
10
+ s3_bucket_id: 'test_bucket',
11
+ s3_object_path: 'bucket_path',
12
+ sqs_queue_name: 'test_queue'
13
+ }
14
+ end
15
+
16
+ let(:app) do
17
+ described_class.new(
18
+ Alephant::Broker::LoadStrategy::Revalidate::Strategy.new,
19
+ config
20
+ )
21
+ end
22
+
23
+ let(:content) do
24
+ {
25
+ content: 'Test',
26
+ content_type: 'test/content',
27
+ meta: {
28
+ :ttl => '35',
29
+ :head_ETag => '123',
30
+ :'head_Last-Modified' => 'Mon, 11 Apr 2016 10:39:57 GMT'
31
+ }
32
+ }
33
+ end
34
+
35
+ let(:lookup_location_double) { instance_double(Alephant::Lookup::LookupLocation, location: 'test/location') }
36
+ let(:lookup_helper_double) { instance_double(Alephant::Lookup::LookupHelper, read: lookup_location_double) }
37
+ let(:storage_double) { instance_double(Alephant::Storage, get: content) }
38
+ let(:sqs_double) { instance_double(AWS::SQS, queues: sqs_queues_double) }
39
+ let(:sqs_queue_double) { instance_double(AWS::SQS::Queue, send_message: nil) }
40
+ let(:sqs_queues_double) { instance_double(AWS::SQS::QueueCollection, :url_for => 'example.com', :[] => sqs_queue_double) }
41
+
42
+ before do
43
+ allow_any_instance_of(Logger).to receive(:info)
44
+ allow_any_instance_of(Logger).to receive(:debug)
45
+ allow(Thread).to receive(:new).and_yield
46
+ allow(Alephant::Lookup).to receive(:create).and_return(lookup_helper_double)
47
+ allow(Alephant::Storage).to receive(:new).and_return(storage_double)
48
+ allow(AWS::SQS).to receive(:new).and_return(sqs_double)
49
+ end
50
+
51
+ describe 'GET `/status`' do
52
+ before { get('/status') }
53
+ specify { expect(last_response.status).to eql(200) }
54
+ specify { expect(last_response.body).to eql('ok') }
55
+ end
56
+
57
+ describe 'GET an undefined endpoint' do
58
+ before { get('/wotever') }
59
+ specify { expect(last_response.status).to eql(404) }
60
+ specify { expect(last_response.body).to eq('Not found') }
61
+ specify { expect(last_response.headers).to include('Cache-Control') }
62
+ specify { expect(last_response.headers).to include('Pragma') }
63
+ specify { expect(last_response.headers).to include('Expires') }
64
+ end
65
+
66
+ describe 'GET `/component/....`' do
67
+ context 'when the content IS available from S3/storage' do
68
+ before { get('/component/test_component') }
69
+
70
+ specify { expect(last_response.status).to eql(200) }
71
+ specify { expect(last_response.body).to eql('Test') }
72
+ specify { expect(last_response.headers).to_not include('Cache-Control') }
73
+ specify { expect(last_response.headers).to_not include('Pragma') }
74
+ specify { expect(last_response.headers).to_not include('Expires') }
75
+ specify { expect(last_response.headers['ETag']).to eq('123') }
76
+ specify { expect(last_response.headers['Last-Modified']).to eq('Mon, 11 Apr 2016 10:39:57 GMT') }
77
+ specify { expect(last_response.headers['Content-Type']).to eq('test/content') }
78
+ specify { expect(last_response.headers['Content-Length']).to eq('4') }
79
+ end
80
+
81
+ context 'when the content IS NOT available from S3/storage' do
82
+ before do
83
+ allow(storage_double)
84
+ .to receive(:get)
85
+ .and_raise(AWS::S3::Errors::NoSuchKey.new(nil, nil))
86
+
87
+ get('/component/test_component')
88
+ end
89
+
90
+ specify { expect(last_response.status).to eql(202) }
91
+ specify { expect(last_response.body).to eql('Accepted') }
92
+ end
93
+ end
94
+
95
+ describe '`/components`' do
96
+ let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
97
+ let(:batch_json) { IO.read("#{fixture_path}/batch.json").strip }
98
+ let(:batch_compiled_json) { IO.read("#{fixture_path}/batch_compiled_no_sequence.json").strip }
99
+
100
+ before do
101
+ allow(storage_double)
102
+ .to receive(:get)
103
+ .and_return(
104
+ content,
105
+ {
106
+ content: 'Test',
107
+ content_type: 'test/content',
108
+ meta: {
109
+ :head_ETag => '"abc"',
110
+ :'head_Last-Modified' => 'Mon, 11 Apr 2016 09:39:57 GMT'
111
+ }
112
+ }
113
+ )
114
+ end
115
+
116
+ describe 'POST' do
117
+ let(:path) { '/components/batch' }
118
+ let(:content_type) { 'application/json' }
119
+
120
+ context 'when the content is available from S3/Storage' do
121
+ before { post(path, batch_json, 'CONTENT_TYPE' => content_type) }
122
+
123
+ specify { expect(last_response.status).to eql(200) }
124
+ specify { expect(last_response.body).to eq(batch_compiled_json) }
125
+ end
126
+
127
+ context 'when the content IS NOT available from S3/storage' do
128
+ before do
129
+ allow(storage_double)
130
+ .to receive(:get)
131
+ .and_raise(AWS::S3::Errors::NoSuchKey.new(nil, nil))
132
+
133
+ post(path, batch_json, 'CONTENT_TYPE' => content_type)
134
+ end
135
+
136
+ specify { expect(last_response.status).to eql(200) }
137
+
138
+ specify do
139
+ statuses = JSON.parse(last_response.body)['components'].map { |c| c['status'] }
140
+ expect(statuses).to eq([202, 202])
141
+ end
142
+ end
143
+ end
144
+
145
+ describe 'GET' do
146
+ let(:path) { '/components/batch?batch_id=baz&components[ni_council_results_table][component]=ni_council_results_table&components[ni_council_results_table][options][foo]=bar&components[ni_council_results_table_no_options][component]=ni_council_results_table' }
147
+ let(:content_type) { 'application/json' }
148
+
149
+ context 'when the content is available from S3/Storage' do
150
+ before { get(path, {}, 'CONTENT_TYPE' => content_type) }
151
+
152
+ specify { expect(last_response.status).to eql(200) }
153
+ specify { expect(last_response.body).to eq(batch_compiled_json) }
154
+ end
155
+
156
+ context 'when the content IS NOT available from S3/storage' do
157
+ before do
158
+ allow(storage_double)
159
+ .to receive(:get)
160
+ .and_raise(AWS::S3::Errors::NoSuchKey.new(nil, nil))
161
+
162
+ get(path, {}, 'CONTENT_TYPE' => content_type)
163
+ end
164
+
165
+ specify { expect(last_response.status).to eql(200) }
166
+
167
+ specify do
168
+ statuses = JSON.parse(last_response.body)['components'].map { |c| c['status'] }
169
+ expect(statuses).to eq([202, 202])
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -9,6 +9,7 @@ end
9
9
  require "pry"
10
10
  require "json"
11
11
  require "rack/test"
12
+ require "timecop"
12
13
 
13
14
  require "alephant/broker"
14
15
 
metadata CHANGED
@@ -1,295 +1,323 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alephant-broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.14.0
4
+ version: 3.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - BBC News
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-06 00:00:00.000000000 Z
11
+ date: 2016-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
14
20
  requirement: !ruby/object:Gem::Requirement
15
21
  requirements:
16
22
  - - '>='
17
23
  - !ruby/object:Gem::Version
18
24
  version: '0'
19
- name: rspec
20
25
  prerelease: false
21
26
  type: :development
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-nc
22
29
  version_requirements: !ruby/object:Gem::Requirement
23
30
  requirements:
24
31
  - - '>='
25
32
  - !ruby/object:Gem::Version
26
33
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
34
  requirement: !ruby/object:Gem::Requirement
29
35
  requirements:
30
36
  - - '>='
31
37
  - !ruby/object:Gem::Version
32
38
  version: '0'
33
- name: rspec-nc
34
39
  prerelease: false
35
40
  type: :development
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard
36
43
  version_requirements: !ruby/object:Gem::Requirement
37
44
  requirements:
38
45
  - - '>='
39
46
  - !ruby/object:Gem::Version
40
47
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
48
  requirement: !ruby/object:Gem::Requirement
43
49
  requirements:
44
50
  - - '>='
45
51
  - !ruby/object:Gem::Version
46
52
  version: '0'
47
- name: guard
48
53
  prerelease: false
49
54
  type: :development
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
50
57
  version_requirements: !ruby/object:Gem::Requirement
51
58
  requirements:
52
59
  - - '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
62
  requirement: !ruby/object:Gem::Requirement
57
63
  requirements:
58
64
  - - '>='
59
65
  - !ruby/object:Gem::Version
60
66
  version: '0'
61
- name: guard-rspec
62
67
  prerelease: false
63
68
  type: :development
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
64
71
  version_requirements: !ruby/object:Gem::Requirement
65
72
  requirements:
66
73
  - - '>='
67
74
  - !ruby/object:Gem::Version
68
75
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
76
  requirement: !ruby/object:Gem::Requirement
71
77
  requirements:
72
78
  - - '>='
73
79
  - !ruby/object:Gem::Version
74
80
  version: '0'
75
- name: pry
76
81
  prerelease: false
77
82
  type: :development
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-remote
78
85
  version_requirements: !ruby/object:Gem::Requirement
79
86
  requirements:
80
87
  - - '>='
81
88
  - !ruby/object:Gem::Version
82
89
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
90
  requirement: !ruby/object:Gem::Requirement
85
91
  requirements:
86
92
  - - '>='
87
93
  - !ruby/object:Gem::Version
88
94
  version: '0'
89
- name: pry-remote
90
95
  prerelease: false
91
96
  type: :development
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-nav
92
99
  version_requirements: !ruby/object:Gem::Requirement
93
100
  requirements:
94
101
  - - '>='
95
102
  - !ruby/object:Gem::Version
96
103
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
104
  requirement: !ruby/object:Gem::Requirement
99
105
  requirements:
100
106
  - - '>='
101
107
  - !ruby/object:Gem::Version
102
108
  version: '0'
103
- name: pry-nav
104
109
  prerelease: false
105
110
  type: :development
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake-rspec
106
113
  version_requirements: !ruby/object:Gem::Requirement
107
114
  requirements:
108
115
  - - '>='
109
116
  - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
117
+ version: 0.0.2
112
118
  requirement: !ruby/object:Gem::Requirement
113
119
  requirements:
114
120
  - - '>='
115
121
  - !ruby/object:Gem::Version
116
122
  version: 0.0.2
117
- name: rake-rspec
118
123
  prerelease: false
119
124
  type: :development
125
+ - !ruby/object:Gem::Dependency
126
+ name: bundler
120
127
  version_requirements: !ruby/object:Gem::Requirement
121
128
  requirements:
122
- - - '>='
129
+ - - ~>
123
130
  - !ruby/object:Gem::Version
124
- version: 0.0.2
125
- - !ruby/object:Gem::Dependency
131
+ version: '1.5'
126
132
  requirement: !ruby/object:Gem::Requirement
127
133
  requirements:
128
134
  - - ~>
129
135
  - !ruby/object:Gem::Version
130
136
  version: '1.5'
131
- name: bundler
132
137
  prerelease: false
133
138
  type: :development
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
134
141
  version_requirements: !ruby/object:Gem::Requirement
135
142
  requirements:
136
- - - ~>
143
+ - - '>='
137
144
  - !ruby/object:Gem::Version
138
- version: '1.5'
139
- - !ruby/object:Gem::Dependency
145
+ version: '0'
140
146
  requirement: !ruby/object:Gem::Requirement
141
147
  requirements:
142
148
  - - '>='
143
149
  - !ruby/object:Gem::Version
144
150
  version: '0'
145
- name: rake
146
151
  prerelease: false
147
152
  type: :development
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack
155
+ version_requirements: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - <
158
+ - !ruby/object:Gem::Version
159
+ version: 2.0.0
160
+ requirement: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - <
163
+ - !ruby/object:Gem::Version
164
+ version: 2.0.0
165
+ prerelease: false
166
+ type: :development
167
+ - !ruby/object:Gem::Dependency
168
+ name: rack-test
148
169
  version_requirements: !ruby/object:Gem::Requirement
149
170
  requirements:
150
171
  - - '>='
151
172
  - !ruby/object:Gem::Version
152
173
  version: '0'
153
- - !ruby/object:Gem::Dependency
154
174
  requirement: !ruby/object:Gem::Requirement
155
175
  requirements:
156
176
  - - '>='
157
177
  - !ruby/object:Gem::Version
158
178
  version: '0'
159
- name: rack-test
160
179
  prerelease: false
161
180
  type: :development
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
162
183
  version_requirements: !ruby/object:Gem::Requirement
163
184
  requirements:
164
185
  - - '>='
165
186
  - !ruby/object:Gem::Version
166
187
  version: '0'
167
- - !ruby/object:Gem::Dependency
168
188
  requirement: !ruby/object:Gem::Requirement
169
189
  requirements:
170
190
  - - '>='
171
191
  - !ruby/object:Gem::Version
172
192
  version: '0'
173
- name: simplecov
174
193
  prerelease: false
175
194
  type: :development
195
+ - !ruby/object:Gem::Dependency
196
+ name: timecop
176
197
  version_requirements: !ruby/object:Gem::Requirement
177
198
  requirements:
178
199
  - - '>='
179
200
  - !ruby/object:Gem::Version
180
201
  version: '0'
181
- - !ruby/object:Gem::Dependency
182
202
  requirement: !ruby/object:Gem::Requirement
183
203
  requirements:
184
204
  - - '>='
185
205
  - !ruby/object:Gem::Version
186
206
  version: '0'
187
- name: alephant-lookup
188
207
  prerelease: false
189
- type: :runtime
208
+ type: :development
209
+ - !ruby/object:Gem::Dependency
210
+ name: alephant-lookup
190
211
  version_requirements: !ruby/object:Gem::Requirement
191
212
  requirements:
192
213
  - - '>='
193
214
  - !ruby/object:Gem::Version
194
- version: '0'
195
- - !ruby/object:Gem::Dependency
215
+ version: 2.0.2
196
216
  requirement: !ruby/object:Gem::Requirement
197
217
  requirements:
198
218
  - - '>='
199
219
  - !ruby/object:Gem::Version
200
- version: 1.1.1
201
- name: alephant-storage
220
+ version: 2.0.2
202
221
  prerelease: false
203
222
  type: :runtime
223
+ - !ruby/object:Gem::Dependency
224
+ name: alephant-storage
204
225
  version_requirements: !ruby/object:Gem::Requirement
205
226
  requirements:
206
227
  - - '>='
207
228
  - !ruby/object:Gem::Version
208
229
  version: 1.1.1
209
- - !ruby/object:Gem::Dependency
210
230
  requirement: !ruby/object:Gem::Requirement
211
231
  requirements:
212
- - - '='
232
+ - - '>='
213
233
  - !ruby/object:Gem::Version
214
- version: 1.2.0
215
- name: alephant-logger
234
+ version: 1.1.1
216
235
  prerelease: false
217
236
  type: :runtime
237
+ - !ruby/object:Gem::Dependency
238
+ name: alephant-logger
218
239
  version_requirements: !ruby/object:Gem::Requirement
219
240
  requirements:
220
241
  - - '='
221
242
  - !ruby/object:Gem::Version
222
243
  version: 1.2.0
223
- - !ruby/object:Gem::Dependency
224
244
  requirement: !ruby/object:Gem::Requirement
225
245
  requirements:
226
- - - '>='
246
+ - - '='
227
247
  - !ruby/object:Gem::Version
228
- version: '0'
229
- name: alephant-sequencer
248
+ version: 1.2.0
230
249
  prerelease: false
231
250
  type: :runtime
251
+ - !ruby/object:Gem::Dependency
252
+ name: alephant-sequencer
232
253
  version_requirements: !ruby/object:Gem::Requirement
233
254
  requirements:
234
255
  - - '>='
235
256
  - !ruby/object:Gem::Version
236
257
  version: '0'
237
- - !ruby/object:Gem::Dependency
238
258
  requirement: !ruby/object:Gem::Requirement
239
259
  requirements:
240
260
  - - '>='
241
261
  - !ruby/object:Gem::Version
242
262
  version: '0'
243
- name: dalli-elasticache
244
263
  prerelease: false
245
264
  type: :runtime
265
+ - !ruby/object:Gem::Dependency
266
+ name: dalli-elasticache
246
267
  version_requirements: !ruby/object:Gem::Requirement
247
268
  requirements:
248
269
  - - '>='
249
270
  - !ruby/object:Gem::Version
250
271
  version: '0'
251
- - !ruby/object:Gem::Dependency
252
272
  requirement: !ruby/object:Gem::Requirement
253
273
  requirements:
254
274
  - - '>='
255
275
  - !ruby/object:Gem::Version
256
276
  version: '0'
257
- name: faraday
258
277
  prerelease: false
259
278
  type: :runtime
279
+ - !ruby/object:Gem::Dependency
280
+ name: faraday
260
281
  version_requirements: !ruby/object:Gem::Requirement
261
282
  requirements:
262
283
  - - '>='
263
284
  - !ruby/object:Gem::Version
264
285
  version: '0'
265
- - !ruby/object:Gem::Dependency
266
286
  requirement: !ruby/object:Gem::Requirement
267
287
  requirements:
268
288
  - - '>='
269
289
  - !ruby/object:Gem::Version
270
290
  version: '0'
271
- name: crimp
272
291
  prerelease: false
273
292
  type: :runtime
293
+ - !ruby/object:Gem::Dependency
294
+ name: crimp
274
295
  version_requirements: !ruby/object:Gem::Requirement
275
296
  requirements:
276
297
  - - '>='
277
298
  - !ruby/object:Gem::Version
278
299
  version: '0'
279
- - !ruby/object:Gem::Dependency
280
300
  requirement: !ruby/object:Gem::Requirement
281
301
  requirements:
282
- - - ~>
302
+ - - '>='
283
303
  - !ruby/object:Gem::Version
284
- version: 3.0.0
285
- name: listen
304
+ version: '0'
286
305
  prerelease: false
287
306
  type: :runtime
307
+ - !ruby/object:Gem::Dependency
308
+ name: listen
288
309
  version_requirements: !ruby/object:Gem::Requirement
289
310
  requirements:
290
311
  - - ~>
291
312
  - !ruby/object:Gem::Version
292
313
  version: 3.0.0
314
+ requirement: !ruby/object:Gem::Requirement
315
+ requirements:
316
+ - - ~>
317
+ - !ruby/object:Gem::Version
318
+ version: 3.0.0
319
+ prerelease: false
320
+ type: :runtime
293
321
  description: Brokers requests for alephant components
294
322
  email:
295
323
  - FutureMediaNewsRubyGems@bbc.co.uk
@@ -309,6 +337,7 @@ files:
309
337
  - lib/alephant/broker.rb
310
338
  - lib/alephant/broker/application.rb
311
339
  - lib/alephant/broker/cache.rb
340
+ - lib/alephant/broker/cache/cached_object.rb
312
341
  - lib/alephant/broker/cache/client.rb
313
342
  - lib/alephant/broker/cache/null_client.rb
314
343
  - lib/alephant/broker/component.rb
@@ -322,6 +351,9 @@ files:
322
351
  - lib/alephant/broker/errors/invalid_cache_key.rb
323
352
  - lib/alephant/broker/load_strategy.rb
324
353
  - lib/alephant/broker/load_strategy/http.rb
354
+ - lib/alephant/broker/load_strategy/revalidate/fetcher.rb
355
+ - lib/alephant/broker/load_strategy/revalidate/refresher.rb
356
+ - lib/alephant/broker/load_strategy/revalidate/strategy.rb
325
357
  - lib/alephant/broker/load_strategy/s3/archived.rb
326
358
  - lib/alephant/broker/load_strategy/s3/base.rb
327
359
  - lib/alephant/broker/load_strategy/s3/sequenced.rb
@@ -336,13 +368,19 @@ files:
336
368
  - lib/alephant/broker/response/batch.rb
337
369
  - lib/alephant/broker/response/factory.rb
338
370
  - lib/alephant/broker/version.rb
371
+ - spec/alephant/broker/cache/cached_object_spec.rb
339
372
  - spec/alephant/broker/component_meta_spec.rb
340
373
  - spec/alephant/broker/load_strategy/http_spec.rb
374
+ - spec/alephant/broker/load_strategy/revalidate/fetcher_spec.rb
375
+ - spec/alephant/broker/load_strategy/revalidate/refresher_spec.rb
376
+ - spec/alephant/broker/load_strategy/revalidate/strategy_spec.rb
341
377
  - spec/alephant/broker/load_strategy/s3/archived_spec.rb
342
378
  - spec/fixtures/json/batch.json
343
379
  - spec/fixtures/json/batch_compiled.json
380
+ - spec/fixtures/json/batch_compiled_no_sequence.json
344
381
  - spec/integration/not_modified_response_spec.rb
345
382
  - spec/integration/rack_spec.rb
383
+ - spec/integration/revalidate_spec.rb
346
384
  - spec/integration/spec_helper.rb
347
385
  - spec/spec_helper.rb
348
386
  homepage: https://github.com/BBC-News/alephant-broker
@@ -370,12 +408,18 @@ signing_key:
370
408
  specification_version: 4
371
409
  summary: Brokers requests for alephant components
372
410
  test_files:
411
+ - spec/alephant/broker/cache/cached_object_spec.rb
373
412
  - spec/alephant/broker/component_meta_spec.rb
374
413
  - spec/alephant/broker/load_strategy/http_spec.rb
414
+ - spec/alephant/broker/load_strategy/revalidate/fetcher_spec.rb
415
+ - spec/alephant/broker/load_strategy/revalidate/refresher_spec.rb
416
+ - spec/alephant/broker/load_strategy/revalidate/strategy_spec.rb
375
417
  - spec/alephant/broker/load_strategy/s3/archived_spec.rb
376
418
  - spec/fixtures/json/batch.json
377
419
  - spec/fixtures/json/batch_compiled.json
420
+ - spec/fixtures/json/batch_compiled_no_sequence.json
378
421
  - spec/integration/not_modified_response_spec.rb
379
422
  - spec/integration/rack_spec.rb
423
+ - spec/integration/revalidate_spec.rb
380
424
  - spec/integration/spec_helper.rb
381
425
  - spec/spec_helper.rb