sinew 2.0.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +26 -0
  3. data/.rubocop.yml +9 -6
  4. data/.vscode/settings.json +0 -10
  5. data/Gemfile +9 -0
  6. data/README.md +13 -17
  7. data/Rakefile +33 -18
  8. data/bin/sinew +2 -0
  9. data/lib/sinew.rb +0 -1
  10. data/lib/sinew/connection.rb +52 -0
  11. data/lib/sinew/connection/log_formatter.rb +22 -0
  12. data/lib/sinew/connection/rate_limit.rb +29 -0
  13. data/lib/sinew/core_ext.rb +1 -1
  14. data/lib/sinew/dsl.rb +2 -1
  15. data/lib/sinew/main.rb +7 -55
  16. data/lib/sinew/output.rb +7 -23
  17. data/lib/sinew/request.rb +20 -71
  18. data/lib/sinew/response.rb +8 -57
  19. data/lib/sinew/runtime_options.rb +4 -4
  20. data/lib/sinew/version.rb +1 -1
  21. data/sample.sinew +2 -2
  22. data/sinew.gemspec +16 -17
  23. metadata +41 -99
  24. data/.travis.yml +0 -4
  25. data/lib/sinew/cache.rb +0 -79
  26. data/test/legacy/eu.httpbin.org/head/redirect,3 +0 -51
  27. data/test/legacy/eu.httpbin.org/head/status,500 +0 -1
  28. data/test/legacy/eu.httpbin.org/redirect,3 +0 -11
  29. data/test/legacy/eu.httpbin.org/status,500 +0 -1
  30. data/test/legacy/legacy.sinew +0 -2
  31. data/test/recipes/array_header.sinew +0 -6
  32. data/test/recipes/basic.sinew +0 -8
  33. data/test/recipes/dups.sinew +0 -7
  34. data/test/recipes/implicit_header.sinew +0 -5
  35. data/test/recipes/limit.sinew +0 -11
  36. data/test/recipes/noko.sinew +0 -9
  37. data/test/recipes/uri.sinew +0 -11
  38. data/test/recipes/xml.sinew +0 -8
  39. data/test/test.html +0 -45
  40. data/test/test_cache.rb +0 -69
  41. data/test/test_helper.rb +0 -126
  42. data/test/test_legacy.rb +0 -23
  43. data/test/test_main.rb +0 -34
  44. data/test/test_nokogiri_ext.rb +0 -18
  45. data/test/test_output.rb +0 -56
  46. data/test/test_recipes.rb +0 -60
  47. data/test/test_requests.rb +0 -164
  48. data/test/test_utf8.rb +0 -39
data/test/test_legacy.rb DELETED
@@ -1,23 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestLegacy < MiniTest::Test
4
- def setup
5
- super
6
-
7
- # These are legacy cache files, pulled from an older version of sinew. We
8
- # use them to test our legacy head parsing.
9
- src = 'legacy/eu.httpbin.org'
10
- dst = "#{TMP}/eu.httpbin.org"
11
- FileUtils.cp_r(File.expand_path(src, __dir__), dst)
12
- end
13
-
14
- def test_legacy
15
- assert_output(/failed with 999/) do
16
- sinew.dsl.get('http://eu.httpbin.org/status/500')
17
- assert_equal "\n", sinew.dsl.raw
18
- end
19
-
20
- sinew.dsl.get('http://eu.httpbin.org/redirect/3')
21
- assert_equal 'http://eu.httpbin.org/get', sinew.dsl.url
22
- end
23
- end
data/test/test_main.rb DELETED
@@ -1,34 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- require 'base64'
4
-
5
- class TestMain < MiniTest::Test
6
- def test_rate_limit
7
- # true network requests call sleep for timeouts, which interferes with our
8
- # instrumentation of Kernel#sleep
9
- skip if test_network?
10
-
11
- slept = false
12
-
13
- # change Kernel#sleep to not really sleep!
14
- Kernel.send(:alias_method, :old_sleep, :sleep)
15
- Kernel.send(:define_method, :sleep) do |_duration|
16
- slept = true
17
- end
18
-
19
- sinew.runtime_options.rate_limit = 1
20
- sinew.dsl.get('http://httpbin.org/html')
21
- sinew.dsl.get('http://httpbin.org/get')
22
- assert(slept)
23
-
24
- # restore old Kernel#sleep
25
- Kernel.send(:alias_method, :sleep, :old_sleep)
26
- Kernel.send(:undef_method, :old_sleep)
27
- end
28
-
29
- def test_gunzip
30
- body = Base64.decode64('H4sICBRI61oAA2d1Yi50eHQASy9N4gIAJlqRYgQAAAA=')
31
- body = Sinew::Response.process_body(OpenStruct.new(body: body))
32
- assert_equal 'gub', body.strip
33
- end
34
- end
@@ -1,18 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestNokogiriExt < MiniTest::Test
4
- def test_inner_text
5
- assert_equal('hello world', noko.css('li').inner_text)
6
- assert_equal('<li>hello</li> <li>world</li>', noko.css('ul').inner_html.squish)
7
- end
8
-
9
- def test_just_me
10
- assert_equal('a', noko.css('div').text_just_me.squish)
11
- assert_equal('b b', noko.css('p').text_just_me.squish)
12
- end
13
-
14
- def noko
15
- @noko ||= Nokogiri::HTML(HTML).css('#nokogiri_ext')
16
- end
17
- protected :noko
18
- end
data/test/test_output.rb DELETED
@@ -1,56 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestOutput < MiniTest::Test
4
- def test_filenames
5
- sinew = Sinew::Main.new(recipe: 'gub.sinew')
6
- assert_equal 'gub.csv', sinew.output.filename
7
- sinew = Sinew::Main.new(recipe: 'gub')
8
- assert_equal 'gub.csv', sinew.output.filename
9
- sinew = Sinew::Main.new(recipe: '/somewhere/gub.sinew')
10
- assert_equal '/somewhere/gub.csv', sinew.output.filename
11
- end
12
-
13
- def test_normalization
14
- output = Sinew::Output.new(nil)
15
-
16
- #
17
- # simple types
18
- #
19
-
20
- assert_equal '', output.send(:normalize, nil)
21
- assert_equal '', output.send(:normalize, '')
22
- assert_equal 'text', output.send(:normalize, 'text')
23
- assert_equal '123', output.send(:normalize, 123)
24
- assert_equal('1|2', output.send(:normalize, [ 1, 2 ]))
25
-
26
- #
27
- # nokogiri
28
- #
29
-
30
- noko = Nokogiri::HTML(HTML)
31
-
32
- # node => text
33
- assert_equal('text', output.send(:normalize, noko.css('#element')))
34
- # nodes => text joined with space
35
- assert_equal('text1 text2', output.send(:normalize, noko.css('.e')))
36
-
37
- #
38
- # string cleanups
39
- #
40
-
41
- # strip_html_tags
42
- assert_equal('gub', output.send(:normalize, '<tag>gub</tag>'))
43
- # strip_html_tags and replace with spaces
44
- assert_equal('hello world', output.send(:normalize, '<tag>hello<br>world</tag>'))
45
- # convert_smart_punctuation
46
- assert_equal('"gub"', output.send(:normalize, "\302\223gub\302\224"))
47
- # convert_accented_html_entities
48
- assert_equal('a', output.send(:normalize, '&aacute;'))
49
- # convert_miscellaneous_html_entities
50
- assert_equal('<&>', output.send(:normalize, '&lt;&amp;&gt;'))
51
- # to_ascii
52
- assert_equal('cafe', output.send(:normalize, "caf\xc3\xa9"))
53
- # squish
54
- assert_equal('hello world', output.send(:normalize, "\nhello \t \rworld"))
55
- end
56
- end
data/test/test_recipes.rb DELETED
@@ -1,60 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestRecipe < MiniTest::Test
4
- DIR = File.expand_path('recipes', __dir__)
5
- TEST_SINEW = "#{TMP}/test.sinew".freeze
6
- TEST_CSV = "#{TMP}/test.csv".freeze
7
-
8
- def test_recipes
9
- Dir.chdir(DIR) do
10
- Dir['*.sinew'].sort.each do |filename|
11
- recipe = IO.read(filename)
12
-
13
- # get ready
14
- IO.write(TEST_SINEW, recipe)
15
- sinew = Sinew::Main.new(cache: TMP, quiet: true, recipe: TEST_SINEW)
16
-
17
- # read OPTIONS
18
- if options = options_from(recipe)
19
- options.each do |key, value|
20
- sinew.options[key] = value
21
- end
22
- end
23
-
24
- # read OUTPUT
25
- output = output_from(recipe, filename)
26
-
27
- # run
28
- sinew.run
29
-
30
- # assert
31
- csv = IO.read(TEST_CSV)
32
- assert_equal(output, csv, "Output didn't match for recipes/#{filename}")
33
- end
34
- end
35
- end
36
-
37
- def options_from(recipe)
38
- if options = recipe[/^#\s*OPTIONS\s*(\{.*\})/, 1]
39
- # rubocop:disable Security/Eval
40
- eval(options)
41
- # rubocop:enable Security/Eval
42
- end
43
- end
44
- protected :options_from
45
-
46
- def output_from(recipe, filename)
47
- lines = recipe.split("\n")
48
- first_line = lines.index { |i| i =~ /^# OUTPUT/ }
49
- if !first_line
50
- raise "# OUTPUT not found in recipes/#{filename}"
51
- end
52
-
53
- output = lines[first_line + 1..-1]
54
- output = output.map { |i| i.gsub(/^# /, '') }
55
- output = output.join("\n")
56
- output += "\n"
57
- output
58
- end
59
- protected :output_from
60
- end
@@ -1,164 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestRequests < MiniTest::Test
4
- def test_user_agent
5
- sinew.dsl.get('http://httpbin.org/get', a: 1, b: 2)
6
- assert_match(/sinew/, sinew.dsl.json[:headers][:'User-Agent'])
7
- end
8
-
9
- def test_basic_methods
10
- sinew.dsl.get('http://httpbin.org/get', a: 1, b: 2)
11
- assert_equal(200, sinew.dsl.code)
12
- assert_equal({ a: '1', b: '2' }, sinew.dsl.json[:args])
13
-
14
- sinew.dsl.post('http://httpbin.org/post', a: 1, b: 2)
15
- assert_equal({ a: '1', b: '2' }, sinew.dsl.json[:form])
16
-
17
- sinew.dsl.post_json('http://httpbin.org/post', a: 1, b: 2)
18
- assert_equal({ a: 1, b: 2 }, sinew.dsl.json[:json])
19
- end
20
-
21
- def test_custom_headers
22
- sinew.dsl.http('get', 'http://httpbin.org/get', headers: { "User-Agent": '007' })
23
- assert_match(/007/, sinew.dsl.json[:headers][:'User-Agent'])
24
- end
25
-
26
- def test_redirects
27
- # absolute redirect
28
- sinew.dsl.get('http://httpbin.org/redirect/2')
29
- assert_equal 'http://httpbin.org/get', sinew.dsl.url
30
-
31
- # and relative redirect
32
- sinew.dsl.get('http://httpbin.org/relative-redirect/2')
33
- assert_equal 'http://httpbin.org/get', sinew.dsl.url
34
- end
35
-
36
- def test_errors
37
- skip if test_network?
38
-
39
- # 500
40
- assert_output(/failed with 500/) do
41
- sinew.dsl.get('http://httpbin.org/status/500')
42
- assert_equal 500, sinew.dsl.code
43
- assert_equal '500', sinew.dsl.raw
44
- end
45
-
46
- # timeout
47
- assert_output(/failed with 999/) do
48
- sinew.dsl.get('http://httpbin.org/delay/1')
49
- assert_equal 999, sinew.dsl.code
50
- end
51
-
52
- # uncommon errors
53
- errors = [
54
- Errno::ECONNREFUSED,
55
- HTTParty::RedirectionTooDeep.new(nil),
56
- OpenSSL::SSL::SSLError.new,
57
- SocketError.new,
58
- ]
59
- errors.each_with_index do |error, index|
60
- stub_request(:get, %r{http://[^/]+/error#{index}}).to_return { raise error }
61
- assert_output(/failed with 999/) do
62
- sinew.dsl.get("http://httpbin.org/error#{index}")
63
- assert_equal 999, sinew.dsl.code
64
- end
65
- end
66
- end
67
-
68
- def test_retry_timeout
69
- skip if test_network?
70
-
71
- errors = 2
72
- stub_request(:get, %r{http://[^/]+/error}).to_return do
73
- if errors > 0
74
- errors -= 1
75
- raise Timeout::Error
76
- end
77
- { body: 'done', status: 200 }
78
- end
79
- sinew.dsl.get('http://httpbin.org/error')
80
- assert_equal 0, errors
81
- assert_equal 'done', sinew.dsl.raw
82
- end
83
-
84
- def test_retry_500
85
- skip if test_network?
86
-
87
- errors = 2
88
- stub_request(:get, %r{http://[^/]+/error}).to_return do
89
- if errors > 0
90
- errors -= 1
91
- return { status: 500 }
92
- end
93
- { body: 'done', status: 200 }
94
- end
95
- sinew.dsl.get('http://httpbin.org/error')
96
- assert_equal 0, errors
97
- assert_equal 'done', sinew.dsl.raw
98
- end
99
-
100
- def test_cache_key
101
- # empty
102
- req = Sinew::Request.new(sinew, 'get', 'http://host')
103
- assert_equal req.cache_key, 'host/_root_'
104
-
105
- # path
106
- req = Sinew::Request.new(sinew, 'get', 'http://host/path')
107
- assert_equal req.cache_key, 'host/path'
108
-
109
- # query
110
- req = Sinew::Request.new(sinew, 'get', 'http://host/path', query: { a: 'b' })
111
- assert_equal req.cache_key, 'host/path,a=b'
112
-
113
- # post with body
114
- req = Sinew::Request.new(sinew, 'post', 'http://host/path', body: { c: 'd' })
115
- assert_equal req.cache_key, 'host/post,path,c=d'
116
-
117
- # too long should turn into digest
118
- path = 'xyz' * 123
119
- req = Sinew::Request.new(sinew, 'get', "http://host/#{path}")
120
- assert_equal "host/#{Digest::MD5.hexdigest(path)}", req.cache_key
121
- end
122
-
123
- def test_before_generate_cache_key
124
- # arity 1
125
- sinew.runtime_options.before_generate_cache_key = method(:redact_cache_key)
126
- req = Sinew::Request.new(sinew, 'get', 'http://host', query: { secret: 'xyz' })
127
- assert_equal 'host/secret=redacted', req.cache_key
128
-
129
- # arity 2
130
- sinew.runtime_options.before_generate_cache_key = method(:add_scheme)
131
- req = Sinew::Request.new(sinew, 'get', 'https://host/gub')
132
- assert_equal 'host/https,gub', req.cache_key
133
- end
134
-
135
- def test_urls
136
- # simple
137
- req = Sinew::Request.new(sinew, 'get', 'https://host')
138
- assert_equal 'https://host', req.uri.to_s
139
-
140
- # with query
141
- req = Sinew::Request.new(sinew, 'get', 'https://host', query: { a: 1 })
142
- assert_equal 'https://host?a=1', req.uri.to_s
143
-
144
- # entity decoding
145
- req = Sinew::Request.new(sinew, 'get', 'https://host?a=&lt;5')
146
- assert_equal 'https://host?a=%3C5', req.uri.to_s
147
-
148
- # sloppy urls
149
- req = Sinew::Request.new(sinew, 'get', 'https://host?a=b c&d=f\'g')
150
- assert_equal 'https://host?a=b%20c&d=f%27g', req.uri.to_s
151
- end
152
-
153
- def redact_cache_key(key)
154
- key[:query].gsub!(/secret=[^&]+/, 'secret=redacted')
155
- key
156
- end
157
- protected :redact_cache_key
158
-
159
- def add_scheme(key, uri)
160
- key[:scheme] = uri.scheme
161
- key
162
- end
163
- protected :add_scheme
164
- end
data/test/test_utf8.rb DELETED
@@ -1,39 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class TestRequests < MiniTest::Test
4
- def test_get
5
- # network (or stub)
6
- sinew.dsl.get('http://httpbin.org/get')
7
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
8
-
9
- # disk
10
- sinew.dsl.get('http://httpbin.org/get')
11
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
12
- end
13
-
14
- def test_utf8
15
- skip if !test_network?
16
-
17
- # network
18
- sinew.dsl.get('http://httpbin.org/encoding/utf8')
19
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
20
- assert_match(/∑/, sinew.dsl.raw)
21
-
22
- # disk
23
- sinew.dsl.get('http://httpbin.org/encoding/utf8')
24
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
25
- assert_match(/∑/, sinew.dsl.raw)
26
- end
27
-
28
- def test_encode
29
- skip if !test_network?
30
-
31
- # network
32
- sinew.dsl.get('https://www.google.co.jp')
33
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
34
-
35
- # disk
36
- sinew.dsl.get('https://www.google.co.jp')
37
- assert_equal 'UTF-8', sinew.dsl.raw.encoding.name
38
- end
39
- end