web_fetch 0.4.0 → 0.5.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.
@@ -10,7 +10,9 @@ describe WebFetch::Router do
10
10
  describe '#route' do
11
11
  it 'provides a route to GET /' do
12
12
  expect(router.route('/'))
13
- .to eql(status: 200, payload: { application: 'WebFetch' })
13
+ .to eql(
14
+ status: 200, command: 'root', payload: { application: 'WebFetch' }
15
+ )
14
16
  end
15
17
 
16
18
  it 'provides a route to POST /gather' do
@@ -39,9 +41,9 @@ describe WebFetch::Router do
39
41
 
40
42
  it 'returns appropriate response when invaid json provided' do
41
43
  response = router.route('/gather',
42
- method: 'POST',
43
- query_string: 'json=uh oh :(',
44
- server: nil)
44
+ method: 'POST',
45
+ query_string: 'json=uh oh :(',
46
+ server: nil)
45
47
  expect(response).to eql(status: 400, payload: I18n.t(:bad_json))
46
48
  end
47
49
  end
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'web_fetch'
4
- require 'pp'
3
+ require 'betterp'
5
4
  require 'byebug'
6
- require 'webmock/rspec'
5
+ require 'pp'
7
6
  require 'rspec/its'
7
+ require 'web_fetch'
8
+ require 'webmock/rspec'
9
+
10
+ require File.join(__dir__, 'storage', 'shared_examples')
8
11
 
9
12
  WebMock.disable_net_connect!(allow_localhost: true)
10
13
 
@@ -33,8 +36,12 @@ module WebFetch
33
36
  class MockServer
34
37
  def gather(requests); end
35
38
 
39
+ def self.storage
40
+ @storage ||= Storage::Memory.new
41
+ end
42
+
36
43
  def storage
37
- Storage
44
+ self.class.storage
38
45
  end
39
46
  end
40
47
  end
@@ -44,13 +51,14 @@ RSpec.configure do |config|
44
51
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
45
52
  end
46
53
 
54
+ config.before(:each) { WebFetch::MockServer.storage.clear }
47
55
  config.mock_with :rspec do |mocks|
48
56
  mocks.verify_partial_doubles = true
49
57
  end
50
58
 
51
59
  config.shared_context_metadata_behavior = :apply_to_host_groups
52
60
 
53
- config.order = :random
54
-
55
- Kernel.srand config.seed
61
+ # config.order = :random
62
+ #
63
+ # Kernel.srand config.seed
56
64
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe WebFetch::Storage::Memcached do
4
+ before(:all) do
5
+ class MockDalliClient
6
+ def initialize(*_args)
7
+ @state = {}
8
+ end
9
+
10
+ def set(key, value)
11
+ @state[key] = value
12
+ end
13
+
14
+ def get(key)
15
+ @state[key]
16
+ end
17
+
18
+ def delete(key)
19
+ @state.delete(key)
20
+ end
21
+ end
22
+ end
23
+
24
+ subject { described_class.new(MockDalliClient) }
25
+
26
+ it_behaves_like 'a storage adapter'
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe WebFetch::Storage::Memory do
4
+ it_behaves_like 'a storage adapter'
5
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe WebFetch::Storage::Redis do
4
+ before(:all) do
5
+ class MockRedisClient
6
+ def initialize(*_args)
7
+ @state = {}
8
+ end
9
+
10
+ def set(key, value, _options = {})
11
+ @state[key] = value
12
+ end
13
+
14
+ def get(key)
15
+ @state[key]
16
+ end
17
+
18
+ def del(key)
19
+ @state.delete(key)
20
+ end
21
+ end
22
+ end
23
+
24
+ subject { described_class.new(MockRedisClient) }
25
+
26
+ it_behaves_like 'a storage adapter'
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples 'a storage adapter' do
4
+ describe '.store' do
5
+ it 'accepts a key and value to store' do
6
+ expect do
7
+ subject.store(:key, 'value')
8
+ end.to_not raise_error
9
+ end
10
+ end
11
+
12
+ describe '.fetch' do
13
+ it 'fetches stored values' do
14
+ subject.store(:key, 'value')
15
+ expect(subject.fetch(:key)).to eql 'value'
16
+ end
17
+ end
18
+
19
+ describe '.delete' do
20
+ it 'deletes stored values' do
21
+ subject.store(:key, 'value')
22
+ expect(subject.fetch(:key)).to eql 'value'
23
+ subject.delete(:key)
24
+ expect(subject.fetch(:key)).to eql nil
25
+ end
26
+ end
27
+ end
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.description = 'Fetches HTTP responses as batch requests concurrently'
14
14
  s.authors = ['Bob Farrell']
15
15
  s.email = 'robertanthonyfarrell@gmail.com'
16
- s.files = `git ls-files`.split($RS)
16
+ s.files = File.read(File.join(__dir__, 'manifest')).split
17
17
  s.homepage = 'https://github.com/bobf/web_fetch'
18
18
  s.licenses = ['MIT']
19
19
  s.require_paths = ['lib']
@@ -22,22 +22,26 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_dependency 'activesupport', '>= 4.0'
24
24
  s.add_dependency 'daemons', '~> 1.2'
25
+ s.add_dependency 'dalli', '~> 2.7'
25
26
  s.add_dependency 'em-http-request', '~> 1.1'
26
- s.add_dependency 'em-logger', '~> 0.1'
27
+ s.add_dependency 'em-logger', '~> 0.1.0'
27
28
  s.add_dependency 'eventmachine', '~> 1.0'
28
- s.add_dependency 'eventmachine_httpserver', '~> 0.2'
29
- s.add_dependency 'faraday', '~> 0.9'
29
+ s.add_dependency 'eventmachine_httpserver', '~> 0.2.1'
30
+ s.add_dependency 'faraday', '~> 0.15.4'
30
31
  s.add_dependency 'hanami-router', '~> 1.0'
31
32
  s.add_dependency 'hanami-utils', '~> 1.0'
32
33
  s.add_dependency 'i18n', '>= 0.7'
33
34
  s.add_dependency 'rack', '>= 1.6'
35
+ s.add_dependency 'redis', '~> 4.1'
34
36
  s.add_dependency 'subprocess', '~> 1.3'
35
37
 
38
+ s.add_development_dependency 'betterp', '~> 0.1.2'
36
39
  s.add_development_dependency 'byebug', '~> 9.0'
37
40
  s.add_development_dependency 'rake', '~> 12.3'
38
41
  s.add_development_dependency 'rspec', '~> 3.5'
39
42
  s.add_development_dependency 'rspec-its', '~> 1.2'
40
- s.add_development_dependency 'rubocop', '~> 0.59.2'
43
+ s.add_development_dependency 'rubocop', '~> 0.60.0'
44
+ s.add_development_dependency 'strong_versions', '~> 0.3.2'
41
45
  s.add_development_dependency 'webmock', '~> 3.4'
42
46
  end
43
47
  # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_fetch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dalli
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.7'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.7'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: em-http-request
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +72,14 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '0.1'
75
+ version: 0.1.0
62
76
  type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '0.1'
82
+ version: 0.1.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: eventmachine
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -86,28 +100,28 @@ dependencies:
86
100
  requirements:
87
101
  - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: '0.2'
103
+ version: 0.2.1
90
104
  type: :runtime
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: '0.2'
110
+ version: 0.2.1
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: faraday
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: '0.9'
117
+ version: 0.15.4
104
118
  type: :runtime
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: '0.9'
124
+ version: 0.15.4
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: hanami-router
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +178,20 @@ dependencies:
164
178
  - - ">="
165
179
  - !ruby/object:Gem::Version
166
180
  version: '1.6'
181
+ - !ruby/object:Gem::Dependency
182
+ name: redis
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '4.1'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '4.1'
167
195
  - !ruby/object:Gem::Dependency
168
196
  name: subprocess
169
197
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +206,20 @@ dependencies:
178
206
  - - "~>"
179
207
  - !ruby/object:Gem::Version
180
208
  version: '1.3'
209
+ - !ruby/object:Gem::Dependency
210
+ name: betterp
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: 0.1.2
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: 0.1.2
181
223
  - !ruby/object:Gem::Dependency
182
224
  name: byebug
183
225
  requirement: !ruby/object:Gem::Requirement
@@ -240,14 +282,28 @@ dependencies:
240
282
  requirements:
241
283
  - - "~>"
242
284
  - !ruby/object:Gem::Version
243
- version: 0.59.2
285
+ version: 0.60.0
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - "~>"
291
+ - !ruby/object:Gem::Version
292
+ version: 0.60.0
293
+ - !ruby/object:Gem::Dependency
294
+ name: strong_versions
295
+ requirement: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - "~>"
298
+ - !ruby/object:Gem::Version
299
+ version: 0.3.2
244
300
  type: :development
245
301
  prerelease: false
246
302
  version_requirements: !ruby/object:Gem::Requirement
247
303
  requirements:
248
304
  - - "~>"
249
305
  - !ruby/object:Gem::Version
250
- version: 0.59.2
306
+ version: 0.3.2
251
307
  - !ruby/object:Gem::Dependency
252
308
  name: webmock
253
309
  requirement: !ruby/object:Gem::Requirement
@@ -274,6 +330,7 @@ files:
274
330
  - ".rspec"
275
331
  - ".rubocop.yml"
276
332
  - ".ruby-version"
333
+ - ".strong_versions.yml"
277
334
  - Gemfile
278
335
  - LICENSE
279
336
  - Makefile
@@ -282,6 +339,7 @@ files:
282
339
  - TODO
283
340
  - bin/rspec
284
341
  - bin/rubocop
342
+ - bin/strong_versions
285
343
  - bin/web_fetch_control
286
344
  - bin/web_fetch_server
287
345
  - config/locales/en.yml
@@ -293,7 +351,6 @@ files:
293
351
  - lib/web_fetch.rb
294
352
  - lib/web_fetch/client.rb
295
353
  - lib/web_fetch/concerns/client_http.rb
296
- - lib/web_fetch/concerns/event_machine_helpers.rb
297
354
  - lib/web_fetch/concerns/http_helpers.rb
298
355
  - lib/web_fetch/concerns/validatable.rb
299
356
  - lib/web_fetch/errors.rb
@@ -308,7 +365,11 @@ files:
308
365
  - lib/web_fetch/router.rb
309
366
  - lib/web_fetch/server.rb
310
367
  - lib/web_fetch/storage.rb
368
+ - lib/web_fetch/storage/memcached.rb
369
+ - lib/web_fetch/storage/memory.rb
370
+ - lib/web_fetch/storage/redis.rb
311
371
  - lib/web_fetch/version.rb
372
+ - manifest
312
373
  - spec/client_spec.rb
313
374
  - spec/concerns/validatable_spec.rb
314
375
  - spec/features/http_fetching_spec.rb
@@ -323,7 +384,10 @@ files:
323
384
  - spec/router_spec.rb
324
385
  - spec/server_spec.rb
325
386
  - spec/spec_helper.rb
326
- - spec/storage_spec.rb
387
+ - spec/storage/memcached_spec.rb
388
+ - spec/storage/memory_spec.rb
389
+ - spec/storage/redis_spec.rb
390
+ - spec/storage/shared_examples.rb
327
391
  - swagger.yaml
328
392
  - web_fetch.gemspec
329
393
  homepage: https://github.com/bobf/web_fetch
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module WebFetch
4
- # EventMachine layer-specific helpers
5
- module EventMachineHelpers
6
- def request_async(target)
7
- request = target[:request]
8
- target[:start_time] = Time.now.utc
9
- async_request = EM::HttpRequest.new(request[:url])
10
- method = request.fetch(:method, 'GET').downcase.to_sym
11
- async_request.public_send(
12
- method,
13
- head: request[:headers],
14
- query: request.fetch(:query, {}),
15
- body: request.fetch(:body, nil)
16
- )
17
- end
18
-
19
- def apply_callbacks(request)
20
- request[:deferred].callback do
21
- Logger.debug("HTTP fetch complete for uid: #{request[:uid]}")
22
- save_response_time(request)
23
- request[:succeeded] = true
24
- end
25
-
26
- request[:deferred].errback do
27
- Logger.debug("HTTP fetch failed for uid: #{request[:uid]}")
28
- save_response_time(request)
29
- request[:failed] = true
30
- end
31
- end
32
-
33
- def wait_for_response(request, response)
34
- tick_loop(request, response)
35
- end
36
-
37
- def tick_loop(request, response)
38
- # XXX There may be a much nicer way to wait for an async task to complete
39
- # before returning a response but I couldn't figure it out, so I used
40
- # EM.tick_loop which effectively does the same as a Twisted deferred
41
- # callback chain, just much more explicitly.
42
- EM.tick_loop do
43
- if request[:succeeded]
44
- succeed(request, response)
45
- :stop
46
- elsif request[:failed]
47
- fail_(request, response)
48
- :stop
49
- end
50
- end
51
- end
52
-
53
- def save_response_time(request)
54
- request[:response_time] = Time.now.utc - request[:start_time]
55
- end
56
- end
57
- end