alephant-broker 3.11.0 → 3.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58251bb948e3620c95b0c67e8643e60426c25818
4
- data.tar.gz: c355b17fe2d366043fbd84f5e284377f9d353a44
3
+ metadata.gz: 60b6af683863285e27316bde5b7392d93439b20e
4
+ data.tar.gz: 7052275d91783c7b02ab1996cdced8e606b58e51
5
5
  SHA512:
6
- metadata.gz: dbdaf0f97e7c873b030be8418d6b7b7a076826fcd576d7f60b9c5f734f4ac8a13db6af1cb4744b222b48ee01abd267c6df051f22fac85dd8285b53b36128ce2c
7
- data.tar.gz: a143fb0fbca1a39ab62a1a7facd718f9f38221a53daae7514ca82d1f9b7a42b3992ba06f8b427da717a919a50801f9877bb56d7c4b34e7adeae69702c5d63fde
6
+ metadata.gz: b8307c2cbe4304ebf233878d20026529e21302cec83e78132b43a6bb7da377da977f85d2f48b447c76d4e3647d2f7915659ec56cdbb9b4ecda8b4e5e26b26777
7
+ data.tar.gz: 0c2ba375708bfb96376954db24ab557b8bc615db013d9e85bd4ad3833d5f03861c6efc1074cd72e4a890d25ca42181f57caaf5da74ea29c458bd16ad71a7dafe
@@ -25,7 +25,7 @@ module Alephant
25
25
  @content = STATUS_CODE_MAPPING[status]
26
26
  @headers = {
27
27
  "Content-Type" => content_type,
28
- "Access-Control-Allow-Headers" => "If-None-Match",
28
+ "Access-Control-Allow-Headers" => "If-None-Match, If-Modified-Since",
29
29
  "Access-Control-Allow-Origin" => "*"
30
30
  }
31
31
  headers.merge!(Broker.config[:headers]) if Broker.config.has_key?(:headers)
@@ -62,6 +62,7 @@ module Alephant
62
62
  end
63
63
 
64
64
  def self.component_not_modified(headers, request_env)
65
+ return false unless allow_not_modified_response_status
65
66
  return false if request_env.post?
66
67
  return false if request_env.if_modified_since.nil? && request_env.if_none_match.nil?
67
68
 
@@ -76,6 +77,10 @@ module Alephant
76
77
  etag.to_s.gsub(/\A"|"\Z/, '')
77
78
  end
78
79
 
80
+ def self.allow_not_modified_response_status
81
+ Broker.config[:allow_not_modified_response_status] || false
82
+ end
83
+
79
84
  def log
80
85
  logger.metric "BrokerNon200Response#{status}"
81
86
  end
@@ -1,5 +1,5 @@
1
1
  module Alephant
2
2
  module Broker
3
- VERSION = "3.11.0"
3
+ VERSION = "3.12.0"
4
4
  end
5
5
  end
@@ -0,0 +1,230 @@
1
+ require_relative "spec_helper"
2
+ require "alephant/broker"
3
+
4
+ describe Alephant::Broker::Application do
5
+ include Rack::Test::Methods
6
+
7
+ let(:options) do
8
+ {
9
+ :lookup_table_name => "test_table",
10
+ :bucket_id => "test_bucket",
11
+ :path => "bucket_path",
12
+ :allow_not_modified_response_status => true
13
+ }
14
+ end
15
+
16
+ let(:app) do
17
+ described_class.new(
18
+ Alephant::Broker::LoadStrategy::S3::Sequenced.new,
19
+ options
20
+ )
21
+ end
22
+
23
+ let(:content) do
24
+ AWS::Core::Data.new(
25
+ :content_type => "test/content",
26
+ :content => "Test",
27
+ :meta => {
28
+ "head_ETag" => "123",
29
+ "head_Last-Modified" => "Mon, 11 Apr 2016 10:39:57 GMT"
30
+ }
31
+ )
32
+ end
33
+
34
+ let(:sequencer_double) do
35
+ instance_double(
36
+ "Alephant::Sequencer::Sequencer",
37
+ :get_last_seen => "111"
38
+ )
39
+ end
40
+
41
+ let(:lookup_location_double) do
42
+ instance_double("Alephant::Lookup::Location", :location => "test/location")
43
+ end
44
+ let(:lookup_helper_double) do
45
+ instance_double(
46
+ "Alephant::Lookup::LookupHelper",
47
+ :read => lookup_location_double
48
+ )
49
+ end
50
+
51
+ let(:s3_double) { instance_double("Alephant::Storage", :get => content) }
52
+
53
+ let(:not_modified_status_code) { Alephant::Broker::Response::Base::NOT_MODIFIED_STATUS_CODE }
54
+
55
+ before do
56
+ allow_any_instance_of(Logger).to receive(:info)
57
+ allow_any_instance_of(Logger).to receive(:debug)
58
+ allow(Alephant::Lookup).to receive(:create) { lookup_helper_double }
59
+ allow(Alephant::Sequencer).to receive(:create) { sequencer_double }
60
+ end
61
+
62
+ describe "single component not modified response" do
63
+ before do
64
+ allow(Alephant::Storage).to receive(:new) { s3_double }
65
+ get(
66
+ "/component/test_component",
67
+ {},
68
+ {
69
+ "HTTP_IF_MODIFIED_SINCE" => "Mon, 11 Apr 2016 10:39:57 GMT"
70
+ }
71
+ )
72
+ end
73
+
74
+ specify { expect(last_response.status).to eql not_modified_status_code }
75
+ specify { expect(last_response.body).to eql "" }
76
+ specify { expect(last_response.headers).to_not include("Cache-Control") }
77
+ specify { expect(last_response.headers).to_not include("Pragma") }
78
+ specify { expect(last_response.headers).to_not include("Expires") }
79
+ specify { expect(last_response.headers["ETag"]).to eq("123") }
80
+ specify { expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT") }
81
+ end
82
+
83
+ describe "Components POST unmodified '/components' response" do
84
+ let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
85
+ let(:batch_json) { IO.read("#{fixture_path}/batch.json").strip }
86
+ let(:batch_compiled_json) { IO.read("#{fixture_path}/batch_compiled.json").strip }
87
+ let(:s3_double_with_etag) { instance_double("Alephant::Storage") }
88
+ let(:lookup_location_double_for_options_request) do
89
+ instance_double("Alephant::Lookup::Location", :location => "test/location/with/options")
90
+ end
91
+
92
+ before do
93
+ allow(lookup_helper_double).to receive(:read)
94
+ .with("ni_council_results_table", { :foo => "bar" }, "111")
95
+ .and_return(lookup_location_double_for_options_request)
96
+
97
+ allow(s3_double_with_etag).to receive(:get)
98
+ .with("test/location")
99
+ .and_return(
100
+ content
101
+ )
102
+
103
+ allow(s3_double_with_etag).to receive(:get)
104
+ .with("test/location/with/options")
105
+ .and_return(
106
+ AWS::Core::Data.new(
107
+ :content_type => "test/content",
108
+ :content => "Test",
109
+ :meta => {
110
+ "head_ETag" => "abc",
111
+ "head_Last-Modified" => "Mon, 11 Apr 2016 09:39:57 GMT"
112
+ }
113
+ )
114
+ )
115
+
116
+ allow(Alephant::Storage).to receive(:new) { s3_double_with_etag }
117
+ end
118
+
119
+ context "when requesting an unmodified response" do
120
+ let(:path) { "/components/batch" }
121
+ let(:content_type) { "application/json" }
122
+ let(:etag) { '"34774567db979628363e6e865127623f"' }
123
+
124
+ before do
125
+ post(path, batch_json,
126
+ "CONTENT_TYPE" => content_type,
127
+ "HTTP_IF_NONE_MATCH" => etag)
128
+ end
129
+
130
+ specify { expect(last_response.status).to eql 200 }
131
+ specify { expect(last_response.body).to eq batch_compiled_json }
132
+
133
+ describe "response should have headers" do
134
+ it "should have a Content-Type header" do
135
+ expect(last_response.headers).to include("Content-Type")
136
+ end
137
+
138
+ it "should have ETag cache header" do
139
+ expect(last_response.headers["ETag"]).to eq(etag)
140
+ end
141
+
142
+ it "should have most recent Last-Modified header" do
143
+ expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT")
144
+ end
145
+
146
+ it "shoud not have no cache headers" do
147
+ expect(last_response.headers).to_not include("Cache-Control")
148
+ expect(last_response.headers).to_not include("Pragma")
149
+ expect(last_response.headers).to_not include("Expires")
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "Components GET unmodified '/components' response" do
156
+ let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
157
+ let(:batch_compiled_json) { IO.read("#{fixture_path}/batch_compiled.json").strip }
158
+ let(:s3_double_with_etag) { instance_double("Alephant::Storage") }
159
+ let(:lookup_location_double_for_options_request) do
160
+ instance_double("Alephant::Lookup::Location", :location => "test/location/with/options")
161
+ end
162
+
163
+ before do
164
+ allow(lookup_helper_double).to receive(:read)
165
+ .with("ni_council_results_table", { :foo => "bar" }, "111")
166
+ .and_return(lookup_location_double_for_options_request)
167
+
168
+ allow(s3_double_with_etag).to receive(:get)
169
+ .with("test/location")
170
+ .and_return(
171
+ content
172
+ )
173
+
174
+ allow(s3_double_with_etag).to receive(:get)
175
+ .with("test/location/with/options")
176
+ .and_return(
177
+ AWS::Core::Data.new(
178
+ :content_type => "test/content",
179
+ :content => "Test",
180
+ :meta => {
181
+ "head_ETag" => "abc",
182
+ "head_Last-Modified" => "Mon, 11 Apr 2016 09:39:57 GMT"
183
+ }
184
+ )
185
+ )
186
+
187
+ allow(Alephant::Storage).to receive(:new) { s3_double_with_etag }
188
+ end
189
+
190
+ context "when requesting an unmodified response with GET" do
191
+ 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" }
192
+ let(:content_type) { "application/json" }
193
+ let(:etag) { '"34774567db979628363e6e865127623f"' }
194
+
195
+ before do
196
+ get(
197
+ path,
198
+ {},
199
+ {
200
+ "CONTENT_TYPE" => content_type,
201
+ "HTTP_IF_NONE_MATCH" => etag
202
+ }
203
+ )
204
+ end
205
+
206
+ specify { expect(last_response.status).to eql not_modified_status_code }
207
+ specify { expect(last_response.body).to eq "" }
208
+
209
+ describe "response should have headers" do
210
+ it "should not have a Content-Type header" do
211
+ expect(last_response.headers).to_not include("Content-Type")
212
+ end
213
+
214
+ it "should have ETag cache header" do
215
+ expect(last_response.headers["ETag"]).to eq(etag)
216
+ end
217
+
218
+ it "should have most recent Last-Modified header" do
219
+ expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT")
220
+ end
221
+
222
+ it "shoud not have no cache headers" do
223
+ expect(last_response.headers).to_not include("Cache-Control")
224
+ expect(last_response.headers).to_not include("Pragma")
225
+ expect(last_response.headers).to_not include("Expires")
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
@@ -96,27 +96,6 @@ describe Alephant::Broker::Application do
96
96
  end
97
97
  end
98
98
 
99
- describe "single component not modified response" do
100
- before do
101
- allow(Alephant::Storage).to receive(:new) { s3_double }
102
- get(
103
- "/component/test_component",
104
- {},
105
- {
106
- "HTTP_IF_MODIFIED_SINCE" => "Mon, 11 Apr 2016 10:39:57 GMT"
107
- }
108
- )
109
- end
110
-
111
- specify { expect(last_response.status).to eql not_modified_status_code }
112
- specify { expect(last_response.body).to eql "" }
113
- specify { expect(last_response.headers).to_not include("Cache-Control") }
114
- specify { expect(last_response.headers).to_not include("Pragma") }
115
- specify { expect(last_response.headers).to_not include("Expires") }
116
- specify { expect(last_response.headers["ETag"]).to eq("123") }
117
- specify { expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT") }
118
- end
119
-
120
99
  describe "Components endpoint '/components' POST" do
121
100
  let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
122
101
  let(:batch_json) do
@@ -169,78 +148,6 @@ describe Alephant::Broker::Application do
169
148
  end
170
149
  end
171
150
 
172
- describe "Components POST unmodified '/components' response" do
173
- let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
174
- let(:batch_json) { IO.read("#{fixture_path}/batch.json").strip }
175
- let(:batch_compiled_json) { IO.read("#{fixture_path}/batch_compiled.json").strip }
176
- let(:s3_double_with_etag) { instance_double("Alephant::Storage") }
177
- let(:lookup_location_double_for_options_request) do
178
- instance_double("Alephant::Lookup::Location", :location => "test/location/with/options")
179
- end
180
-
181
- before do
182
- allow(lookup_helper_double).to receive(:read)
183
- .with("ni_council_results_table", { :foo => "bar" }, "111")
184
- .and_return(lookup_location_double_for_options_request)
185
-
186
- allow(s3_double_with_etag).to receive(:get)
187
- .with("test/location")
188
- .and_return(
189
- content
190
- )
191
-
192
- allow(s3_double_with_etag).to receive(:get)
193
- .with("test/location/with/options")
194
- .and_return(
195
- AWS::Core::Data.new(
196
- :content_type => "test/content",
197
- :content => "Test",
198
- :meta => {
199
- "head_ETag" => "abc",
200
- "head_Last-Modified" => "Mon, 11 Apr 2016 09:39:57 GMT"
201
- }
202
- )
203
- )
204
-
205
- allow(Alephant::Storage).to receive(:new) { s3_double_with_etag }
206
- end
207
-
208
- context "when requesting an unmodified response" do
209
- let(:path) { "/components/batch" }
210
- let(:content_type) { "application/json" }
211
- let(:etag) { '"34774567db979628363e6e865127623f"' }
212
-
213
- before do
214
- post(path, batch_json,
215
- "CONTENT_TYPE" => content_type,
216
- "HTTP_IF_NONE_MATCH" => etag)
217
- end
218
-
219
- specify { expect(last_response.status).to eql 200 }
220
- specify { expect(last_response.body).to eq batch_compiled_json }
221
-
222
- describe "response should have headers" do
223
- it "should have a Content-Type header" do
224
- expect(last_response.headers).to include("Content-Type")
225
- end
226
-
227
- it "should have ETag cache header" do
228
- expect(last_response.headers["ETag"]).to eq(etag)
229
- end
230
-
231
- it "should have most recent Last-Modified header" do
232
- expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT")
233
- end
234
-
235
- it "shoud not have no cache headers" do
236
- expect(last_response.headers).to_not include("Cache-Control")
237
- expect(last_response.headers).to_not include("Pragma")
238
- expect(last_response.headers).to_not include("Expires")
239
- end
240
- end
241
- end
242
- end
243
-
244
151
  describe "Components endpoint '/components' GET" do
245
152
  let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
246
153
  let(:batch_compiled_json) do
@@ -290,82 +197,6 @@ describe Alephant::Broker::Application do
290
197
  end
291
198
  end
292
199
 
293
- describe "Components GET unmodified '/components' response" do
294
- let(:fixture_path) { "#{File.dirname(__FILE__)}/../fixtures/json" }
295
- let(:batch_compiled_json) { IO.read("#{fixture_path}/batch_compiled.json").strip }
296
- let(:s3_double_with_etag) { instance_double("Alephant::Storage") }
297
- let(:lookup_location_double_for_options_request) do
298
- instance_double("Alephant::Lookup::Location", :location => "test/location/with/options")
299
- end
300
-
301
- before do
302
- allow(lookup_helper_double).to receive(:read)
303
- .with("ni_council_results_table", { :foo => "bar" }, "111")
304
- .and_return(lookup_location_double_for_options_request)
305
-
306
- allow(s3_double_with_etag).to receive(:get)
307
- .with("test/location")
308
- .and_return(
309
- content
310
- )
311
-
312
- allow(s3_double_with_etag).to receive(:get)
313
- .with("test/location/with/options")
314
- .and_return(
315
- AWS::Core::Data.new(
316
- :content_type => "test/content",
317
- :content => "Test",
318
- :meta => {
319
- "head_ETag" => "abc",
320
- "head_Last-Modified" => "Mon, 11 Apr 2016 09:39:57 GMT"
321
- }
322
- )
323
- )
324
-
325
- allow(Alephant::Storage).to receive(:new) { s3_double_with_etag }
326
- end
327
-
328
- context "when requesting an unmodified response with GET" do
329
- 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" }
330
- let(:content_type) { "application/json" }
331
- let(:etag) { '"34774567db979628363e6e865127623f"' }
332
-
333
- before do
334
- get(
335
- path,
336
- {},
337
- {
338
- "CONTENT_TYPE" => content_type,
339
- "HTTP_IF_NONE_MATCH" => etag
340
- }
341
- )
342
- end
343
-
344
- specify { expect(last_response.status).to eql not_modified_status_code }
345
- specify { expect(last_response.body).to eq "" }
346
-
347
- describe "response should have headers" do
348
- it "should not have a Content-Type header" do
349
- expect(last_response.headers).to_not include("Content-Type")
350
- end
351
-
352
- it "should have ETag cache header" do
353
- expect(last_response.headers["ETag"]).to eq(etag)
354
- end
355
-
356
- it "should have most recent Last-Modified header" do
357
- expect(last_response.headers["Last-Modified"]).to eq("Mon, 11 Apr 2016 10:39:57 GMT")
358
- end
359
-
360
- it "shoud not have no cache headers" do
361
- expect(last_response.headers).to_not include("Cache-Control")
362
- expect(last_response.headers).to_not include("Pragma")
363
- expect(last_response.headers).to_not include("Expires")
364
- end
365
- end
366
- end
367
- end
368
-
369
200
  describe "S3 headers" do
370
201
  let(:content) do
371
202
  AWS::Core::Data.new(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alephant-broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.11.0
4
+ version: 3.12.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-04-27 00:00:00.000000000 Z
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -322,6 +322,7 @@ files:
322
322
  - spec/fixtures/json/batch.json
323
323
  - spec/fixtures/json/batch_compiled.json
324
324
  - spec/http_spec.rb
325
+ - spec/integration/not_modified_response_spec.rb
325
326
  - spec/integration/rack_spec.rb
326
327
  - spec/integration/spec_helper.rb
327
328
  - spec/spec_helper.rb
@@ -355,6 +356,7 @@ test_files:
355
356
  - spec/fixtures/json/batch.json
356
357
  - spec/fixtures/json/batch_compiled.json
357
358
  - spec/http_spec.rb
359
+ - spec/integration/not_modified_response_spec.rb
358
360
  - spec/integration/rack_spec.rb
359
361
  - spec/integration/spec_helper.rb
360
362
  - spec/spec_helper.rb