wayfarer 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yaml +25 -0
  3. data/.github/workflows/release.yaml +29 -0
  4. data/.github/workflows/tests.yaml +30 -0
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +5 -0
  7. data/.vale.ini +5 -0
  8. data/.yardopts +1 -3
  9. data/Dockerfile +5 -4
  10. data/Gemfile +3 -0
  11. data/Gemfile.lock +107 -102
  12. data/Rakefile +5 -56
  13. data/bin/wayfarer +1 -1
  14. data/docker-compose.yml +20 -9
  15. data/docs/cookbook/consent_screen.md +2 -2
  16. data/docs/cookbook/executing_javascript.md +3 -3
  17. data/docs/cookbook/navigation.md +12 -12
  18. data/docs/cookbook/querying_html.md +3 -3
  19. data/docs/cookbook/screenshots.md +2 -2
  20. data/docs/cookbook/user_agent.md +1 -1
  21. data/docs/design.md +36 -0
  22. data/docs/guides/callbacks.md +24 -126
  23. data/docs/guides/configuration.md +8 -8
  24. data/docs/guides/handlers.md +60 -0
  25. data/docs/guides/index.md +1 -0
  26. data/docs/guides/jobs/error_handling.md +40 -0
  27. data/docs/guides/jobs.md +99 -31
  28. data/docs/guides/navigation.md +1 -1
  29. data/docs/guides/networking/capybara.md +13 -22
  30. data/docs/guides/networking/custom_adapters.md +82 -41
  31. data/docs/guides/networking/ferrum.md +4 -4
  32. data/docs/guides/networking/http.md +9 -13
  33. data/docs/guides/networking/selenium.md +10 -11
  34. data/docs/guides/pages.md +76 -10
  35. data/docs/guides/redis.md +10 -0
  36. data/docs/guides/routing.md +74 -0
  37. data/docs/guides/tasks.md +33 -9
  38. data/docs/guides/tutorial.md +60 -0
  39. data/docs/guides/user_agents.md +113 -0
  40. data/docs/index.md +17 -40
  41. data/docs/reference/cli.md +35 -25
  42. data/docs/reference/configuration.md +36 -0
  43. data/lib/wayfarer/base.rb +124 -46
  44. data/lib/wayfarer/batch_completion.rb +56 -0
  45. data/lib/wayfarer/callbacks.rb +22 -48
  46. data/lib/wayfarer/cli/route_printer.rb +71 -57
  47. data/lib/wayfarer/cli.rb +121 -0
  48. data/lib/wayfarer/gc.rb +13 -6
  49. data/lib/wayfarer/handler.rb +15 -7
  50. data/lib/wayfarer/logging.rb +38 -0
  51. data/lib/wayfarer/middleware/base.rb +2 -0
  52. data/lib/wayfarer/middleware/batch_completion.rb +19 -0
  53. data/lib/wayfarer/middleware/content_type.rb +54 -0
  54. data/lib/wayfarer/middleware/controller.rb +19 -15
  55. data/lib/wayfarer/middleware/dedup.rb +16 -13
  56. data/lib/wayfarer/middleware/dispatch.rb +12 -4
  57. data/lib/wayfarer/middleware/normalize.rb +12 -11
  58. data/lib/wayfarer/middleware/redis.rb +15 -0
  59. data/lib/wayfarer/middleware/router.rb +33 -35
  60. data/lib/wayfarer/middleware/stage.rb +5 -5
  61. data/lib/wayfarer/middleware/uri_parser.rb +30 -0
  62. data/lib/wayfarer/middleware/user_agent.rb +49 -0
  63. data/lib/wayfarer/networking/capybara.rb +1 -1
  64. data/lib/wayfarer/networking/context.rb +2 -2
  65. data/lib/wayfarer/networking/ferrum.rb +2 -2
  66. data/lib/wayfarer/networking/follow.rb +12 -6
  67. data/lib/wayfarer/networking/http.rb +1 -1
  68. data/lib/wayfarer/networking/pool.rb +17 -12
  69. data/lib/wayfarer/networking/selenium.rb +3 -3
  70. data/lib/wayfarer/networking/strategy.rb +2 -2
  71. data/lib/wayfarer/page.rb +36 -14
  72. data/lib/wayfarer/parsing/xml.rb +6 -6
  73. data/lib/wayfarer/parsing.rb +24 -0
  74. data/lib/wayfarer/redis/barrier.rb +13 -21
  75. data/lib/wayfarer/redis/counter.rb +19 -9
  76. data/lib/wayfarer/redis/pool.rb +1 -1
  77. data/lib/wayfarer/redis/resettable.rb +19 -0
  78. data/lib/wayfarer/routing/dsl.rb +1 -0
  79. data/lib/wayfarer/routing/matchers/path.rb +4 -2
  80. data/lib/wayfarer/routing/root_route.rb +5 -1
  81. data/lib/wayfarer/routing/route.rb +4 -14
  82. data/lib/wayfarer/stringify.rb +22 -30
  83. data/lib/wayfarer/task.rb +12 -18
  84. data/lib/wayfarer.rb +28 -1
  85. data/mkdocs.yml +52 -7
  86. data/rake/docs.rake +26 -0
  87. data/rake/lint.rake +105 -0
  88. data/rake/release.rake +29 -0
  89. data/rake/tests.rake +28 -0
  90. data/requirements.txt +1 -1
  91. data/spec/base_spec.rb +140 -160
  92. data/spec/batch_completion_spec.rb +104 -0
  93. data/spec/cli/job_spec.rb +19 -23
  94. data/spec/cli/routing_spec.rb +101 -0
  95. data/spec/cli/version_spec.rb +1 -1
  96. data/spec/factories/task.rb +7 -1
  97. data/spec/fixtures/dummy_job.rb +5 -3
  98. data/spec/gc_spec.rb +8 -50
  99. data/spec/handler_spec.rb +1 -1
  100. data/spec/integration/callbacks_spec.rb +157 -45
  101. data/spec/integration/content_type_spec.rb +145 -0
  102. data/spec/integration/gc_spec.rb +44 -0
  103. data/spec/integration/handler_spec.rb +66 -0
  104. data/spec/integration/page_spec.rb +44 -29
  105. data/spec/integration/params_spec.rb +33 -25
  106. data/spec/integration/parsing_spec.rb +125 -0
  107. data/spec/integration/routing_spec.rb +18 -0
  108. data/spec/integration/stage_spec.rb +27 -20
  109. data/spec/middleware/batch_completion_spec.rb +34 -0
  110. data/spec/middleware/chain_spec.rb +8 -8
  111. data/spec/middleware/content_type_spec.rb +86 -0
  112. data/spec/middleware/controller_spec.rb +5 -5
  113. data/spec/middleware/dedup_spec.rb +38 -55
  114. data/spec/middleware/dispatch_spec.rb +23 -7
  115. data/spec/middleware/normalize_spec.rb +44 -13
  116. data/spec/middleware/router_spec.rb +29 -30
  117. data/spec/middleware/stage_spec.rb +8 -8
  118. data/spec/middleware/uri_parser_spec.rb +53 -0
  119. data/spec/middleware/{fetch_spec.rb → user_agent_spec.rb} +28 -27
  120. data/spec/networking/context_spec.rb +1 -1
  121. data/spec/networking/follow_spec.rb +2 -2
  122. data/spec/networking/pool_spec.rb +5 -5
  123. data/spec/networking/strategy.rb +2 -2
  124. data/spec/page_spec.rb +42 -20
  125. data/spec/parsing/xml_spec.rb +11 -12
  126. data/spec/redis/barrier_spec.rb +8 -48
  127. data/spec/redis/counter_spec.rb +13 -1
  128. data/spec/redis/pool_spec.rb +1 -1
  129. data/spec/spec_helpers.rb +27 -16
  130. data/spec/support/test_app.rb +8 -0
  131. data/spec/task_spec.rb +3 -24
  132. data/spec/wayfarer_spec.rb +1 -1
  133. data/wayfarer.gemspec +4 -3
  134. metadata +61 -51
  135. data/.github/workflows/ci.yaml +0 -32
  136. data/docs/guides/error_handling.md +0 -53
  137. data/docs/guides/networking.md +0 -94
  138. data/docs/guides/performance.md +0 -130
  139. data/docs/guides/reliability.md +0 -41
  140. data/docs/guides/routing/steering.md +0 -30
  141. data/docs/reference/api/base.md +0 -48
  142. data/docs/reference/configuration_keys.md +0 -43
  143. data/docs/reference/environment_variables.md +0 -83
  144. data/lib/wayfarer/cli/base.rb +0 -45
  145. data/lib/wayfarer/cli/generate.rb +0 -17
  146. data/lib/wayfarer/cli/job.rb +0 -56
  147. data/lib/wayfarer/cli/route.rb +0 -29
  148. data/lib/wayfarer/cli/runner.rb +0 -34
  149. data/lib/wayfarer/cli/templates/Gemfile.tt +0 -5
  150. data/lib/wayfarer/cli/templates/job.rb.tt +0 -10
  151. data/lib/wayfarer/config/capybara.rb +0 -10
  152. data/lib/wayfarer/config/ferrum.rb +0 -11
  153. data/lib/wayfarer/config/networking.rb +0 -29
  154. data/lib/wayfarer/config/redis.rb +0 -14
  155. data/lib/wayfarer/config/root.rb +0 -11
  156. data/lib/wayfarer/config/selenium.rb +0 -21
  157. data/lib/wayfarer/config/strconv.rb +0 -45
  158. data/lib/wayfarer/config/struct.rb +0 -72
  159. data/lib/wayfarer/middleware/fetch.rb +0 -56
  160. data/lib/wayfarer/redis/connection.rb +0 -13
  161. data/lib/wayfarer/redis/version.rb +0 -19
  162. data/lib/wayfarer/routing/router.rb +0 -28
  163. data/spec/callbacks_spec.rb +0 -102
  164. data/spec/cli/generate_spec.rb +0 -39
  165. data/spec/config/capybara_spec.rb +0 -18
  166. data/spec/config/ferrum_spec.rb +0 -24
  167. data/spec/config/networking_spec.rb +0 -73
  168. data/spec/config/redis_spec.rb +0 -32
  169. data/spec/config/root_spec.rb +0 -31
  170. data/spec/config/selenium_spec.rb +0 -56
  171. data/spec/config/strconv_spec.rb +0 -58
  172. data/spec/config/struct_spec.rb +0 -66
  173. data/spec/integration/steering_spec.rb +0 -57
  174. data/spec/redis/version_spec.rb +0 -13
  175. data/spec/routing/router_spec.rb +0 -24
@@ -5,16 +5,31 @@ require "spec_helpers"
5
5
  describe "Pages" do
6
6
  let(:url) { test_app_path("git-scm.com/book/en/v2.html") }
7
7
 
8
- describe Wayfarer::Base do
8
+ before do
9
+ stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
10
+ stub_const("DummyHandler", Class.new.include(Wayfarer::Handler))
11
+ end
12
+
13
+ shared_examples "executes" do
9
14
  specify do
10
- class self.class::DummyJob < Wayfarer::Base
11
- extend SpecHelpers
15
+ DummyJob.crawl(url)
16
+ perform_enqueued_jobs
17
+ assert_performed_jobs 1
18
+ expect(enqueued_jobs).to be_empty
19
+ end
20
+ end
21
+
22
+ describe "page content" do
23
+ before do
24
+ DummyJob.class_eval do
12
25
  include RSpec::Matchers
26
+ extend SpecHelpers
27
+ include SpecHelpers
13
28
 
14
- route { host test_app_host, to: :index }
29
+ route.host test_app_host, to: :index
15
30
 
16
31
  def index
17
- expect(page.url).to eq("http://test:9876/git-scm.com/book/en/v2.html")
32
+ expect(page.url).to eq(test_app_path("git-scm.com/book/en/v2.html"))
18
33
  expect(page.status_code).to be(200)
19
34
  expect(page.body).not_to be_empty
20
35
  expect(page.headers.count).to be(9)
@@ -24,39 +39,39 @@ describe "Pages" do
24
39
  expect(page.meta.links.external.count).to be(55)
25
40
  end
26
41
  end
27
-
28
- self.class::DummyJob.crawl(url)
29
- perform_enqueued_jobs
30
42
  end
31
- end
32
-
33
- describe Wayfarer::Handler do
34
- specify do
35
- class self.class::DummyJob < Wayfarer::Base
36
- extend SpecHelpers
37
43
 
38
- route { host test_app_host, to: DummyHandler }
44
+ it_behaves_like "executes"
45
+ end
39
46
 
40
- class DummyHandler < Wayfarer::Handler
41
- include RSpec::Matchers
47
+ describe "page content with handler" do
48
+ before do
49
+ DummyJob.class_eval do
50
+ include RSpec::Matchers
51
+ include SpecHelpers
42
52
 
43
- route { to :index }
53
+ route.to :index
44
54
 
45
- def index
46
- expect(page.url).to eq("http://test:9876/git-scm.com/book/en/v2.html")
47
- expect(page.status_code).to be(200)
48
- expect(page.body).not_to be_empty
49
- expect(page.headers.count).to be(9)
55
+ def index
56
+ expect(page.url).to eq(test_app_path("git-scm.com/book/en/v2.html"))
57
+ expect(page.status_code).to be(200)
58
+ expect(page.body).not_to be_empty
59
+ expect(page.headers.count).to be(9)
50
60
 
51
- expect(page.meta.links.all.count).to be(157)
52
- expect(page.meta.links.internal.count).to be(102)
53
- expect(page.meta.links.external.count).to be(55)
54
- end
61
+ expect(page.meta.links.all.count).to be(157)
62
+ expect(page.meta.links.internal.count).to be(102)
63
+ expect(page.meta.links.external.count).to be(55)
55
64
  end
56
65
  end
57
66
 
58
- self.class::DummyJob.crawl(url)
59
- perform_enqueued_jobs
67
+ DummyHandler.class_eval do
68
+ extend SpecHelpers
69
+ include SpecHelpers
70
+
71
+ route.host test_app_host, to: DummyHandler
72
+ end
60
73
  end
74
+
75
+ it_behaves_like "executes"
61
76
  end
62
77
  end
@@ -5,52 +5,60 @@ require "spec_helpers"
5
5
  describe "URL parameters" do
6
6
  let(:url) { test_app_path("git-scm.com/book/en/v2.html") }
7
7
 
8
- describe Wayfarer::Base do
8
+ before do
9
+ stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
10
+ stub_const("DummyHandler", Class.new.include(Wayfarer::Handler))
11
+ end
12
+
13
+ shared_examples "executes" do
9
14
  specify do
10
- class self.class::DummyJob < Wayfarer::Base
15
+ DummyJob.crawl(url)
16
+ perform_enqueued_jobs
17
+ assert_performed_jobs 1
18
+ expect(enqueued_jobs).to be_empty
19
+ end
20
+ end
21
+
22
+ describe "path pattern matching" do
23
+ before do
24
+ DummyJob.class_eval do
11
25
  extend SpecHelpers
12
26
  include RSpec::Matchers
13
27
 
14
- route do
15
- to :index, host: test_app_host do
16
- path "git-scm.com/book/:lang/:file"
17
- end
28
+ route.to :index, host: test_app_host do
29
+ path "git-scm.com/book/:lang/:file"
18
30
  end
19
31
 
20
32
  def index
21
33
  expect(params).to eq("lang" => "en", "file" => "v2.html")
22
34
  end
23
35
  end
24
-
25
- self.class::DummyJob.crawl(url)
26
- perform_enqueued_jobs
27
36
  end
37
+
38
+ it_behaves_like "executes"
28
39
  end
29
40
 
30
- describe Wayfarer::Handler do
31
- specify do
32
- class self.class::DummyJob < Wayfarer::Base
41
+ describe "path pattern matching with handler" do
42
+ before do
43
+ DummyJob.class_eval do
33
44
  extend SpecHelpers
34
45
 
35
- route do
36
- to DummyHandler, host: test_app_host do
37
- path "git-scm.com/book/:lang/:file"
38
- end
46
+ route.to DummyHandler, host: test_app_host do
47
+ path "git-scm.com/book/:lang/:file"
39
48
  end
49
+ end
40
50
 
41
- class DummyHandler < Wayfarer::Handler
42
- include RSpec::Matchers
51
+ DummyHandler.class_eval do
52
+ include RSpec::Matchers
43
53
 
44
- route { to :index }
54
+ route.to :index
45
55
 
46
- def index
47
- expect(params).to eq("lang" => "en", "file" => "v2.html")
48
- end
56
+ def index
57
+ expect(params).to eq("lang" => "en", "file" => "v2.html")
49
58
  end
50
59
  end
51
-
52
- self.class::DummyJob.crawl(url)
53
- perform_enqueued_jobs
54
60
  end
55
61
  end
62
+
63
+ it_behaves_like "executes"
56
64
  end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe "Response body parsing", redis: true do
6
+ before do
7
+ stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
8
+ stub_const("DummyHandler", Class.new.include(Wayfarer::Handler))
9
+ end
10
+
11
+ shared_examples "executes" do
12
+ specify do
13
+ DummyJob.crawl(url)
14
+ perform_enqueued_jobs
15
+ assert_performed_jobs 1
16
+ expect(enqueued_jobs).to be_empty
17
+ end
18
+ end
19
+
20
+ context "with XML" do
21
+ let(:url) { test_app_path("xml/dummy.xml") }
22
+
23
+ before do
24
+ DummyJob.class_eval do
25
+ include RSpec::Matchers
26
+
27
+ route.to :index
28
+
29
+ def index
30
+ expect(page.doc).to be_a(Nokogiri::XML::Document)
31
+ end
32
+ end
33
+
34
+ it_behaves_like "executes"
35
+ end
36
+ end
37
+
38
+ context "with HTML" do
39
+ let(:url) { test_app_path("finders.html") }
40
+
41
+ before do
42
+ DummyJob.class_eval do
43
+ include RSpec::Matchers
44
+
45
+ route.to :index
46
+
47
+ def index
48
+ expect(page.doc).to be_a(Nokogiri::HTML::Document)
49
+ end
50
+ end
51
+ end
52
+
53
+ it_behaves_like "executes"
54
+ end
55
+
56
+ context "with JSON" do
57
+ let(:url) { test_app_path("json/dummy.json") }
58
+
59
+ before do
60
+ DummyJob.class_eval do
61
+ include RSpec::Matchers
62
+
63
+ route.to :index
64
+
65
+ def index
66
+ expect(page.doc).to be_a(Hash)
67
+ end
68
+ end
69
+ end
70
+
71
+ it_behaves_like "executes"
72
+ end
73
+
74
+ describe "custom Content-Type parsers" do
75
+ context "with registered Content-Types" do
76
+ let(:parser) do
77
+ Class.new do
78
+ def self.parse(_body)
79
+ :ok
80
+ end
81
+ end
82
+ end
83
+
84
+ let(:parser_with_options) do
85
+ Class.new do
86
+ def self.parse(_body, options)
87
+ options
88
+ end
89
+ end
90
+ end
91
+
92
+ before do
93
+ Wayfarer::Parsing.registry["foo/bar"] = parser
94
+ Wayfarer::Parsing.registry["bar/qux"] = [parser_with_options, :ok]
95
+ end
96
+
97
+ after do
98
+ Wayfarer::Parsing.registry.delete("foo/bar")
99
+ Wayfarer::Parsing.registry.delete("bar/qux")
100
+ end
101
+
102
+ before do
103
+ DummyJob.class_eval do
104
+ route.to :index
105
+
106
+ def index
107
+ page.doc
108
+ end
109
+ end
110
+ end
111
+
112
+ def perform(content_type)
113
+ DummyJob.new.perform(
114
+ build(:task, url: test_app_path("response_header/Content-Type/#{content_type}"))
115
+ )
116
+ end
117
+
118
+ specify do
119
+ expect(perform("foo/bar")).to be(:ok)
120
+ expect(perform("bar/qux")).to be(:ok)
121
+ expect(perform("image/jpeg")).to be(nil)
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe "Routing" do
6
+ let(:task) { build(:task) }
7
+
8
+ before do
9
+ stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
10
+ end
11
+
12
+ describe "custom routing" do
13
+ before do
14
+ DummyJob.class_eval do
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,50 +2,57 @@
2
2
 
3
3
  require "spec_helpers"
4
4
 
5
- describe "Staging" do
5
+ describe "Staging", redis: true do
6
6
  let(:url) { test_app_path("git-scm.com/book/en/v2.html") }
7
7
 
8
- describe Wayfarer::Base do
9
- specify do
10
- class self.class::DummyJob < Wayfarer::Base
8
+ before do
9
+ stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
10
+ stub_const("DummyHandler", Class.new.include(Wayfarer::Handler))
11
+ end
12
+
13
+ describe "staging URLs" do
14
+ before do
15
+ DummyJob.class_eval do
11
16
  extend SpecHelpers
12
17
 
13
- route { host test_app_host, to: :index }
18
+ route.host test_app_host, to: :index
14
19
 
15
20
  def index
16
21
  stage page.meta.links.all
17
22
  end
18
23
  end
24
+ end
19
25
 
26
+ specify do
20
27
  expect {
21
- self.class::DummyJob.crawl(url)
28
+ DummyJob.crawl(url)
22
29
  perform_enqueued_jobs
23
- }.to change { enqueued_jobs.size }.by(156)
30
+ }.to change { enqueued_jobs.size }.by(157)
24
31
  end
25
32
  end
26
33
 
27
- describe Wayfarer::Handler do
28
- specify do
29
- class self.class::DummyJob < Wayfarer::Base
34
+ context "with handler" do
35
+ before do
36
+ DummyJob.class_eval do
30
37
  extend SpecHelpers
31
38
 
32
- route do
33
- host test_app_host, to: DummyHandler
34
- end
39
+ route.host test_app_host, to: DummyHandler
40
+ end
35
41
 
36
- class DummyHandler < Wayfarer::Handler
37
- route { to :index }
42
+ DummyHandler.class_eval do
43
+ route.to :index
38
44
 
39
- def index
40
- stage page.meta.links.all
41
- end
45
+ def index
46
+ stage page.meta.links.all
42
47
  end
43
48
  end
49
+ end
44
50
 
51
+ specify do
45
52
  expect {
46
- self.class::DummyJob.crawl(url)
53
+ DummyJob.crawl(url)
47
54
  perform_enqueued_jobs
48
- }.to change { enqueued_jobs.size }.by(156)
55
+ }.to change { enqueued_jobs.size }.by(157)
49
56
  end
50
57
  end
51
58
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::Middleware::BatchCompletion, "#call" do
6
+ let(:task) { build(:task) }
7
+ let(:job) { double(exception_executions: exception_executions) }
8
+ let(:exception_executions) { {} }
9
+ subject(:batch_completion) { described_class.new }
10
+
11
+ before { task[:job] = job }
12
+
13
+ it "assigns cloned exception_executions" do
14
+ expect {
15
+ batch_completion.call(task)
16
+ }.to change {
17
+ task[:initial_exception_executions]
18
+ }.from(nil).to(exception_executions)
19
+
20
+ expect(task[:initial_exception_executions]).not_to be(exception_executions)
21
+ end
22
+
23
+ context "when already assigned" do
24
+ before { task[:initial_exception_executions] = Object.new }
25
+
26
+ specify do
27
+ expect { |spy| batch_completion.call(task, &spy) }.to yield_control
28
+ end
29
+
30
+ it "doesn't assign exception_executions" do
31
+ expect { batch_completion.call(task) }.not_to(change { task[:initial_exception_executions] })
32
+ end
33
+ end
34
+ end
@@ -65,11 +65,11 @@ describe Wayfarer::Middleware::Chain do
65
65
  describe "Return value" do
66
66
  let(:middlewares) do
67
67
  [build(:middleware, receiver: lambda do |task, &block|
68
- task.metadata.foobar = 42
68
+ task[:foobar] = 42
69
69
  block.call
70
70
  end),
71
71
  build(:middleware, receiver: lambda do |task|
72
- task.metadata.foobar *= 1337
72
+ task[:foobar] *= 1337
73
73
  end)]
74
74
  end
75
75
 
@@ -81,16 +81,16 @@ describe Wayfarer::Middleware::Chain do
81
81
  describe "Metadata" do
82
82
  let(:first) do
83
83
  build(:middleware, receiver: lambda do |task, &block|
84
- task.metadata.foobar = 42
84
+ task[:foobar] = 42
85
85
  block.call
86
- task.metadata.barqux = 1337
86
+ task[:barqux] = 1337
87
87
  end)
88
88
  end
89
89
 
90
90
  let(:last) do
91
91
  build(:middleware, receiver: lambda do |task|
92
- raise unless task.metadata.foobar == 42
93
- raise if task.metadata.barqux
92
+ raise unless task[:foobar] == 42
93
+ raise if task[:barqux]
94
94
  end)
95
95
  end
96
96
 
@@ -101,8 +101,8 @@ describe Wayfarer::Middleware::Chain do
101
101
  chain.call(task)
102
102
  }.not_to raise_error
103
103
 
104
- expect(task.metadata.foobar).to be(42)
105
- expect(task.metadata.barqux).to be(1337)
104
+ expect(task[:foobar]).to be(42)
105
+ expect(task[:barqux]).to be(1337)
106
106
  end
107
107
  end
108
108
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::Middleware::ContentType do
6
+ let(:content_type) { "text/html" }
7
+ let(:task) { build(:task) }
8
+ let(:page) { build(:page, headers: { "Content-Type" => content_type }) }
9
+
10
+ describe "#call" do
11
+ subject { Class.new(described_class).include(described_class::API).new }
12
+
13
+ before do
14
+ task[:page] = page
15
+ task[:controller] = subject
16
+ end
17
+
18
+ before { subject.class.content_type "text/html" }
19
+
20
+ context "with permitted Content-Type" do
21
+ it "yields" do
22
+ expect { |spy| subject.call(task, &spy) }.to yield_control
23
+ end
24
+ end
25
+
26
+ context "when permitted Content-Type has parameters" do
27
+ let(:page) { build(:page, headers: { "Content-Type" => "#{content_type}; charset=UTF-" }) }
28
+
29
+ it "yields" do
30
+ expect { |spy| subject.call(task, &spy) }.to yield_control
31
+ end
32
+ end
33
+
34
+ context "with forbidden Content-Type" do
35
+ let(:content_type) { "application/json" }
36
+
37
+ it "does not yield" do
38
+ expect { |spy| subject.call(task, &spy) }.not_to yield_control
39
+ end
40
+ end
41
+
42
+ context "with permitted Regexp Content-Type" do
43
+ before do
44
+ subject.class.content_type(/text/)
45
+ end
46
+
47
+ it "yields" do
48
+ expect { |spy| subject.call(task, &spy) }.to yield_control
49
+ end
50
+ end
51
+ end
52
+
53
+ describe described_class::API do
54
+ subject(:controller) do
55
+ Struct.new(:task).include(described_class).new(task)
56
+ end
57
+
58
+ describe "::allowed_content_types" do
59
+ describe "index" do
60
+ subject { controller.class.allowed_content_types[:index] }
61
+
62
+ it { is_expected.to be_empty }
63
+ end
64
+
65
+ describe "patterns" do
66
+ subject { controller.class.allowed_content_types[:patterns] }
67
+
68
+ it { is_expected.to be_empty }
69
+ end
70
+ end
71
+
72
+ describe "#content_type" do
73
+ it "allows Content-Types" do
74
+ controller.class.content_type(content_type)
75
+
76
+ expect(controller.class.allowed_content_types[:index][content_type]).to be(true)
77
+ end
78
+
79
+ it "allows Content-Type patterns" do
80
+ controller.class.content_type(/text/)
81
+
82
+ expect(controller.class.allowed_content_types[:patterns]).to contain_exactly(/text/)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -54,28 +54,28 @@ describe Wayfarer::Middleware::Controller do
54
54
  it "assigns itself" do
55
55
  expect {
56
56
  subject.call(task)
57
- }.to change { task.metadata.job }.to(subject)
57
+ }.to change { task[:job] }.to(subject)
58
58
  end
59
59
  end
60
60
 
61
61
  context "with job assigned" do
62
- before { task.metadata.job = Object.new }
62
+ before { task[:job] = Object.new }
63
63
 
64
64
  it "does not override the job" do
65
65
  expect {
66
66
  subject.call(task)
67
- }.not_to(change { task.metadata.job })
67
+ }.not_to(change { task[:job] })
68
68
  end
69
69
  end
70
70
 
71
71
  it "assigns itself as controller" do
72
72
  expect {
73
73
  subject.call(task)
74
- }.to change { task.metadata.controller }.to(subject)
74
+ }.to change { task[:controller] }.to(subject)
75
75
  end
76
76
 
77
77
  it "calls the chain" do
78
- expect(subject.chain).to receive(:call)
78
+ expect(subject.class.chain).to receive(:call)
79
79
  subject.call(task)
80
80
  end
81
81