wayfarer 0.4.7 → 0.4.8

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/.env +17 -0
  3. data/.github/workflows/lint.yaml +8 -6
  4. data/.github/workflows/release.yaml +4 -3
  5. data/.github/workflows/tests.yaml +5 -14
  6. data/.gitignore +2 -2
  7. data/.rubocop.yml +31 -0
  8. data/.vale.ini +6 -3
  9. data/Dockerfile +3 -2
  10. data/Gemfile +21 -0
  11. data/Gemfile.lock +233 -128
  12. data/Rakefile +7 -0
  13. data/docker-compose.yml +13 -14
  14. data/docs/guides/callbacks.md +3 -1
  15. data/docs/guides/configuration.md +10 -35
  16. data/docs/guides/development.md +67 -0
  17. data/docs/guides/handlers.md +7 -7
  18. data/docs/guides/jobs.md +54 -11
  19. data/docs/guides/networking/custom_adapters.md +31 -10
  20. data/docs/guides/pages.md +24 -22
  21. data/docs/guides/routing.md +116 -34
  22. data/docs/guides/tasks.md +30 -10
  23. data/docs/guides/tutorial.md +23 -17
  24. data/docs/guides/user_agents.md +11 -9
  25. data/lib/wayfarer/base.rb +9 -8
  26. data/lib/wayfarer/batch_completion.rb +18 -14
  27. data/lib/wayfarer/callbacks.rb +14 -14
  28. data/lib/wayfarer/cli/route_printer.rb +78 -96
  29. data/lib/wayfarer/cli.rb +12 -30
  30. data/lib/wayfarer/gc.rb +6 -1
  31. data/lib/wayfarer/kv.rb +28 -0
  32. data/lib/wayfarer/middleware/chain.rb +7 -1
  33. data/lib/wayfarer/middleware/content_type.rb +20 -15
  34. data/lib/wayfarer/middleware/dedup.rb +9 -3
  35. data/lib/wayfarer/middleware/dispatch.rb +7 -2
  36. data/lib/wayfarer/middleware/normalize.rb +4 -12
  37. data/lib/wayfarer/middleware/router.rb +1 -1
  38. data/lib/wayfarer/middleware/uri_parser.rb +4 -3
  39. data/lib/wayfarer/networking/context.rb +12 -1
  40. data/lib/wayfarer/networking/ferrum.rb +1 -4
  41. data/lib/wayfarer/networking/follow.rb +2 -1
  42. data/lib/wayfarer/networking/pool.rb +12 -7
  43. data/lib/wayfarer/networking/selenium.rb +15 -7
  44. data/lib/wayfarer/page.rb +0 -2
  45. data/lib/wayfarer/parsing/xml.rb +1 -1
  46. data/lib/wayfarer/parsing.rb +2 -5
  47. data/lib/wayfarer/redis/barrier.rb +15 -2
  48. data/lib/wayfarer/redis/counter.rb +1 -2
  49. data/lib/wayfarer/routing/dsl.rb +166 -31
  50. data/lib/wayfarer/routing/hash_stack.rb +33 -0
  51. data/lib/wayfarer/routing/matchers/custom.rb +8 -5
  52. data/lib/wayfarer/routing/matchers/{suffix.rb → empty_params.rb} +2 -6
  53. data/lib/wayfarer/routing/matchers/host.rb +15 -9
  54. data/lib/wayfarer/routing/matchers/path.rb +11 -33
  55. data/lib/wayfarer/routing/matchers/query.rb +41 -17
  56. data/lib/wayfarer/routing/matchers/result.rb +12 -0
  57. data/lib/wayfarer/routing/matchers/scheme.rb +13 -5
  58. data/lib/wayfarer/routing/matchers/url.rb +13 -5
  59. data/lib/wayfarer/routing/path_consumer.rb +130 -0
  60. data/lib/wayfarer/routing/path_finder.rb +151 -23
  61. data/lib/wayfarer/routing/result.rb +1 -1
  62. data/lib/wayfarer/routing/root_route.rb +14 -2
  63. data/lib/wayfarer/routing/route.rb +71 -14
  64. data/lib/wayfarer/routing/serializable.rb +28 -0
  65. data/lib/wayfarer/routing/sub_route.rb +53 -0
  66. data/lib/wayfarer/routing/target_route.rb +17 -1
  67. data/lib/wayfarer/stringify.rb +1 -2
  68. data/lib/wayfarer/task.rb +3 -5
  69. data/lib/wayfarer/uri/normalization.rb +120 -0
  70. data/lib/wayfarer.rb +50 -10
  71. data/mise.toml +2 -0
  72. data/mkdocs.yml +8 -17
  73. data/rake/lint.rake +0 -96
  74. data/rake/release.rake +5 -11
  75. data/rake/tests.rake +8 -4
  76. data/requirements.txt +1 -1
  77. data/spec/factories/job.rb +8 -0
  78. data/spec/factories/middleware.rb +2 -2
  79. data/spec/factories/path_finder.rb +11 -0
  80. data/spec/factories/redis.rb +19 -0
  81. data/spec/factories/task.rb +39 -1
  82. data/spec/spec_helpers.rb +50 -57
  83. data/spec/support/active_job_helpers.rb +8 -0
  84. data/spec/support/integration_helpers.rb +21 -0
  85. data/spec/support/redis_helpers.rb +9 -0
  86. data/spec/support/test_app.rb +64 -43
  87. data/spec/{base_spec.rb → wayfarer/base_spec.rb} +32 -36
  88. data/spec/wayfarer/batch_completion_spec.rb +142 -0
  89. data/spec/wayfarer/cli/job_spec.rb +88 -0
  90. data/spec/wayfarer/cli/routing_spec.rb +322 -0
  91. data/spec/{cli → wayfarer/cli}/version_spec.rb +1 -1
  92. data/spec/wayfarer/gc_spec.rb +29 -0
  93. data/spec/{handler_spec.rb → wayfarer/handler_spec.rb} +1 -3
  94. data/spec/{integration → wayfarer/integration}/callbacks_spec.rb +9 -6
  95. data/spec/wayfarer/integration/content_type_spec.rb +37 -0
  96. data/spec/wayfarer/integration/custom_routing_spec.rb +51 -0
  97. data/spec/{integration → wayfarer/integration}/gc_spec.rb +9 -13
  98. data/spec/{integration → wayfarer/integration}/handler_spec.rb +9 -10
  99. data/spec/{integration → wayfarer/integration}/page_spec.rb +8 -6
  100. data/spec/{integration → wayfarer/integration}/params_spec.rb +4 -4
  101. data/spec/{integration → wayfarer/integration}/parsing_spec.rb +7 -33
  102. data/spec/wayfarer/integration/retry_spec.rb +112 -0
  103. data/spec/{integration → wayfarer/integration}/stage_spec.rb +5 -5
  104. data/spec/{middleware → wayfarer/middleware}/batch_completion_spec.rb +4 -5
  105. data/spec/{middleware → wayfarer/middleware}/chain_spec.rb +20 -15
  106. data/spec/{middleware → wayfarer/middleware}/content_type_spec.rb +18 -21
  107. data/spec/{middleware → wayfarer/middleware}/controller_spec.rb +22 -20
  108. data/spec/wayfarer/middleware/dedup_spec.rb +66 -0
  109. data/spec/wayfarer/middleware/normalize_spec.rb +32 -0
  110. data/spec/{middleware → wayfarer/middleware}/router_spec.rb +18 -20
  111. data/spec/{middleware → wayfarer/middleware}/stage_spec.rb +11 -10
  112. data/spec/wayfarer/middleware/uri_parser_spec.rb +63 -0
  113. data/spec/{middleware → wayfarer/middleware}/user_agent_spec.rb +34 -32
  114. data/spec/wayfarer/networking/capybara_spec.rb +13 -0
  115. data/spec/{networking → wayfarer/networking}/context_spec.rb +46 -38
  116. data/spec/wayfarer/networking/ferrum_spec.rb +13 -0
  117. data/spec/{networking → wayfarer/networking}/follow_spec.rb +9 -4
  118. data/spec/wayfarer/networking/http_spec.rb +12 -0
  119. data/spec/{networking → wayfarer/networking}/pool_spec.rb +11 -9
  120. data/spec/wayfarer/networking/selenium_spec.rb +12 -0
  121. data/spec/{networking → wayfarer/networking}/strategy.rb +33 -54
  122. data/spec/{page_spec.rb → wayfarer/page_spec.rb} +3 -3
  123. data/spec/{parsing → wayfarer/parsing}/json_spec.rb +1 -1
  124. data/spec/{parsing/xml_spec.rb → wayfarer/parsing/xml_parse_spec.rb} +4 -3
  125. data/spec/{redis → wayfarer/redis}/barrier_spec.rb +5 -4
  126. data/spec/wayfarer/redis/counter_spec.rb +34 -0
  127. data/spec/{redis → wayfarer/redis}/pool_spec.rb +3 -2
  128. data/spec/{routing → wayfarer/routing}/dsl_spec.rb +12 -22
  129. data/spec/wayfarer/routing/hash_stack_spec.rb +63 -0
  130. data/spec/wayfarer/routing/integration_spec.rb +101 -0
  131. data/spec/wayfarer/routing/matchers/custom_spec.rb +39 -0
  132. data/spec/wayfarer/routing/matchers/host_spec.rb +56 -0
  133. data/spec/wayfarer/routing/matchers/matcher.rb +17 -0
  134. data/spec/wayfarer/routing/matchers/path_spec.rb +43 -0
  135. data/spec/wayfarer/routing/matchers/query_spec.rb +123 -0
  136. data/spec/wayfarer/routing/matchers/scheme_spec.rb +45 -0
  137. data/spec/wayfarer/routing/matchers/url_spec.rb +33 -0
  138. data/spec/wayfarer/routing/path_consumer_spec.rb +123 -0
  139. data/spec/wayfarer/routing/path_finder_spec.rb +409 -0
  140. data/spec/wayfarer/routing/root_route_spec.rb +51 -0
  141. data/spec/wayfarer/routing/route_spec.rb +74 -0
  142. data/spec/wayfarer/routing/sub_route_spec.rb +103 -0
  143. data/spec/wayfarer/uri/normalization_spec.rb +98 -0
  144. data/spec/wayfarer_spec.rb +2 -2
  145. data/wayfarer.gemspec +17 -28
  146. metadata +768 -246
  147. data/.rbenv-gemsets +0 -1
  148. data/.ruby-version +0 -1
  149. data/RELEASING.md +0 -17
  150. data/docs/cookbook/user_agent.md +0 -7
  151. data/docs/design.md +0 -36
  152. data/docs/guides/jobs/error_handling.md +0 -40
  153. data/docs/reference/configuration.md +0 -36
  154. data/spec/batch_completion_spec.rb +0 -104
  155. data/spec/cli/job_spec.rb +0 -74
  156. data/spec/cli/routing_spec.rb +0 -101
  157. data/spec/fixtures/dummy_job.rb +0 -9
  158. data/spec/gc_spec.rb +0 -17
  159. data/spec/integration/content_type_spec.rb +0 -145
  160. data/spec/integration/routing_spec.rb +0 -18
  161. data/spec/middleware/dedup_spec.rb +0 -71
  162. data/spec/middleware/dispatch_spec.rb +0 -59
  163. data/spec/middleware/normalize_spec.rb +0 -60
  164. data/spec/middleware/uri_parser_spec.rb +0 -53
  165. data/spec/networking/capybara_spec.rb +0 -12
  166. data/spec/networking/ferrum_spec.rb +0 -12
  167. data/spec/networking/http_spec.rb +0 -12
  168. data/spec/networking/selenium_spec.rb +0 -12
  169. data/spec/redis/counter_spec.rb +0 -44
  170. data/spec/routing/integration_spec.rb +0 -110
  171. data/spec/routing/matchers/custom_spec.rb +0 -31
  172. data/spec/routing/matchers/host_spec.rb +0 -49
  173. data/spec/routing/matchers/path_spec.rb +0 -43
  174. data/spec/routing/matchers/query_spec.rb +0 -137
  175. data/spec/routing/matchers/scheme_spec.rb +0 -25
  176. data/spec/routing/matchers/suffix_spec.rb +0 -41
  177. data/spec/routing/matchers/uri_spec.rb +0 -27
  178. data/spec/routing/path_finder_spec.rb +0 -33
  179. data/spec/routing/root_route_spec.rb +0 -29
  180. data/spec/routing/route_spec.rb +0 -43
  181. data/docs/{reference → guides}/cli.md +0 -0
  182. data/spec/{stringify_spec.rb → wayfarer/stringify_spec.rb} +2 -2
  183. /data/spec/{task_spec.rb → wayfarer/task_spec.rb} +0 -0
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ # The RSpec/SpecFilePathFormat offense was not addressed as it requires renaming
6
+ # the file, not changing its content.
7
+ describe Wayfarer::BatchCompletion, :redis do
8
+ let(:task) { build(:task, :redis_pool) }
9
+ let(:job) { instance_spy(ActiveJob::Base, arguments: [task]) }
10
+
11
+ describe "::call" do
12
+ subject(:call_batch_completion) { described_class.call(name, nil, nil, nil, { job: job }) }
13
+
14
+ let(:name) { "foo" }
15
+
16
+ context "with Wayfarer job" do
17
+ before { job.extend(Wayfarer::Base) }
18
+
19
+ specify do
20
+ allow(described_class).to receive(:handle)
21
+
22
+ call_batch_completion
23
+
24
+ expect(described_class).to have_received(:handle).with(name, job, task)
25
+ end
26
+
27
+ it "does not reassign Redis pool" do
28
+ expect { call_batch_completion }.not_to change { task[:redis_pool] }.from(Wayfarer::Redis::Pool.instance)
29
+ end
30
+
31
+ context "without Redis pool" do
32
+ before do
33
+ task[:redis_pool] = nil
34
+ end
35
+
36
+ it "assigns Redis pool" do
37
+ expect { call_batch_completion }.to change { task[:redis_pool] }.from(nil).to(Wayfarer::Redis::Pool.instance)
38
+ end
39
+ end
40
+ end
41
+
42
+ context "with other job" do
43
+ specify do
44
+ allow(described_class).to receive(:handle)
45
+
46
+ call_batch_completion
47
+
48
+ expect(described_class).not_to have_received(:handle)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "::handle" do
54
+ subject(:handle) { described_class.handle(event, job, task) }
55
+
56
+ let(:job) do
57
+ instance_spy(ActiveJob::Base,
58
+ arguments: [task],
59
+ executions: executions,
60
+ exception_executions: exception_executions)
61
+ end
62
+
63
+ let(:initial_exception_executions) { {} }
64
+ let(:exception_executions) { initial_exception_executions }
65
+ let(:executions) { 0 }
66
+ let(:counter) { build(:counter, task: task) }
67
+
68
+ before do
69
+ task[:job] = job
70
+ task[:initial_exception_executions] = initial_exception_executions
71
+ end
72
+
73
+ context "with an 'enqueue.active_job' event" do
74
+ let(:event) { "enqueue.active_job" }
75
+
76
+ specify do
77
+ expect { handle }.to change(counter, :value).by(1)
78
+ end
79
+
80
+ context "with retry" do
81
+ let(:executions) { 1 }
82
+
83
+ specify do
84
+ expect { handle }.not_to(change(counter, :value))
85
+ end
86
+ end
87
+ end
88
+
89
+ context "with a 'perform.active_job' event" do
90
+ let(:event) { "perform.active_job" }
91
+
92
+ context "when job succeeds" do
93
+ specify do
94
+ expect { handle }.to change(counter, :value).by(-1)
95
+ end
96
+
97
+ context "when batch completes" do
98
+ before do
99
+ counter.increment
100
+ allow(Wayfarer::GC).to receive(:run).and_call_original
101
+ end
102
+
103
+ specify do
104
+ handle
105
+
106
+ expect(job).to have_received(:run_callbacks)
107
+ expect(Wayfarer::GC).to have_received(:run).with(task)
108
+ end
109
+ end
110
+
111
+ context "when batch does not complete" do
112
+ before do
113
+ allow(Wayfarer::GC).to receive(:run)
114
+ end
115
+
116
+ specify do
117
+ handle
118
+
119
+ expect(job).not_to have_received(:run_callbacks)
120
+ expect(Wayfarer::GC).not_to have_received(:run)
121
+ end
122
+ end
123
+ end
124
+
125
+ context "when an exception occurrs" do
126
+ let(:exception_executions) { { "[RuntimeError]" => 1 } }
127
+
128
+ specify do
129
+ expect { handle }.not_to(change(counter, :value))
130
+ end
131
+ end
132
+ end
133
+
134
+ context "with a 'retry_stopped.active_job' event" do
135
+ let(:event) { "retry_stopped.active_job" }
136
+
137
+ specify do
138
+ expect { handle }.to change(counter, :value).by(-1)
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe "Jobs", :cli, :integration, :redis do
6
+ include Wayfarer::Redis
7
+
8
+ subject(:cli) { Wayfarer::CLI }
9
+
10
+ let(:url) { test_app_path("/hello_world") }
11
+ let(:batch) { "my-batch" }
12
+
13
+ before do
14
+ mock_job! :dummy_job
15
+
16
+ write_file "dummy_job.rb", <<~FILE
17
+ Wayfarer::CLI.new.send(:load_environment, "dummy_job.rb")
18
+ class DummyJob < ActiveJob::Base
19
+ include Wayfarer::Base
20
+ end
21
+ FILE
22
+ end
23
+
24
+ describe "perform" do
25
+ it "performs the worker" do
26
+ # rubocop:disable RSpec/AnyInstance
27
+ # The CLI reloads DummyJob from file. #expect_any_instance_of alters the
28
+ # object initialization in a way that survives this class reloading.
29
+ expect_any_instance_of(DummyJob).to receive(:perform).with(kind_of(Wayfarer::Task)) do |job|
30
+ # rubocop:enable RSpec/AnyInstance
31
+ task = job.arguments.first
32
+ task[:job] = job
33
+ end
34
+
35
+ cli.start(["perform", "-r", "dummy_job.rb", "DummyJob", url])
36
+ end
37
+
38
+ context "when using MockRedis" do
39
+ it "performs the worker using MockRedis" do
40
+ cli.start(["perform", "--mock-redis", "DummyJob", url])
41
+ expect(Wayfarer.config[:redis][:factory].call(nil)).to be_a(MockRedis)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "enqueue" do
47
+ before do
48
+ allow(DummyJob).to receive(:crawl)
49
+ end
50
+
51
+ it "enqueues the job" do
52
+ cli.start(["enqueue", "DummyJob", url])
53
+ expect(DummyJob).to have_received(:crawl).with(Addressable::URI.parse(url), batch: kind_of(String))
54
+ end
55
+
56
+ context "with a batch provided" do
57
+ it "enqueues the job" do
58
+ cli.start(["enqueue", "--batch", batch, "DummyJob", url])
59
+ expect(DummyJob).to have_received(:crawl).with(Addressable::URI.parse(url), batch: batch)
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "execute" do
65
+ before do
66
+ allow(DummyJob).to receive(:crawl)
67
+ end
68
+
69
+ it "executes the job" do
70
+ cli.start(["execute", "--retain-pool", "DummyJob", url])
71
+ expect(DummyJob).to have_received(:crawl).with(Addressable::URI.parse(url), batch: kind_of(String))
72
+ end
73
+
74
+ context "with a batch provided" do
75
+ it "executes the job" do
76
+ cli.start(["execute", "--retain-pool", "--batch", batch, "DummyJob", url])
77
+ expect(DummyJob).to have_received(:crawl).with(Addressable::URI.parse(url), batch: batch)
78
+ end
79
+ end
80
+
81
+ context "with mock Redis" do
82
+ it "executes the worker using MockRedis" do
83
+ cli.start(["execute", "--retain-pool", "--mock-redis", "DummyJob", url])
84
+ expect(Wayfarer.config[:redis][:factory].call(nil)).to be_a(MockRedis)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe "Routing", :cli, :integration do
6
+ subject(:route) { Wayfarer::CLI.start(["route", "-r", "dummy_job.rb", "DummyJob", url]) }
7
+
8
+ before do
9
+ write_file("dummy_job.rb", contents)
10
+
11
+ mock_job! :dummy_job
12
+ end
13
+
14
+ let(:contents) do
15
+ <<~RUBY
16
+ class DummyJob < ActiveJob::Base
17
+ include Wayfarer::Base
18
+
19
+ #{routes}
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ context "without routes" do
25
+ let(:url) { "http://#{test_app_host}" }
26
+ let(:routes) { "" }
27
+
28
+ let(:expected_output) do
29
+ <<~OUTPUT
30
+ ---
31
+ routed: false
32
+ root_route:
33
+ match: false
34
+ params: {}
35
+ children: []
36
+ OUTPUT
37
+ end
38
+
39
+ specify do
40
+ expect { route }.to output(expected_output).to_stdout
41
+ end
42
+ end
43
+
44
+ context "with target route only" do
45
+ let(:url) { "http://#{test_app_host}" }
46
+ let(:routes) do
47
+ <<~RUBY
48
+ route.to :index
49
+ RUBY
50
+ end
51
+
52
+ let(:expected_output) do
53
+ <<~OUTPUT
54
+ ---
55
+ routed: true
56
+ params: {}
57
+ action: :index
58
+ root_route:
59
+ match: true
60
+ params: {}
61
+ children:
62
+ - target_route:
63
+ action: :index
64
+ children: []
65
+ OUTPUT
66
+ end
67
+
68
+ specify do
69
+ expect { route }.to output(expected_output).to_stdout
70
+ end
71
+ end
72
+
73
+ context "with a symbol target" do
74
+ let(:routes) do
75
+ <<~RUBY
76
+ route.host #{test_app_hostname.inspect}, to: :index
77
+ RUBY
78
+ end
79
+
80
+ context "with matching URL" do
81
+ let(:url) { "http://#{test_app_host}" }
82
+
83
+ let(:expected_output) do
84
+ <<~OUTPUT
85
+ ---
86
+ routed: true
87
+ params: {}
88
+ action: :index
89
+ root_route:
90
+ match: true
91
+ params: {}
92
+ children:
93
+ - route:
94
+ host:
95
+ name: #{test_app_hostname}
96
+ match: true
97
+ params: {}
98
+ children:
99
+ - target_route:
100
+ action: :index
101
+ children: []
102
+ OUTPUT
103
+ end
104
+
105
+ specify do
106
+ expect { route }.to output(expected_output).to_stdout
107
+ end
108
+ end
109
+
110
+ context "with mismatching URL" do
111
+ let(:url) { "http://example.com" }
112
+
113
+ let(:expected_output) do
114
+ <<~OUTPUT
115
+ ---
116
+ routed: false
117
+ root_route:
118
+ match: true
119
+ params: {}
120
+ children:
121
+ - route:
122
+ host:
123
+ name: #{test_app_hostname}
124
+ match: false
125
+ params: {}
126
+ children: []
127
+ OUTPUT
128
+ end
129
+
130
+ specify do
131
+ expect { route }.to output(expected_output).to_stdout
132
+ end
133
+ end
134
+ end
135
+
136
+ context "with a symbol target and params" do
137
+ let(:url) { "http://#{test_app_host}/barqux" }
138
+ let(:routes) do
139
+ <<~RUBY
140
+ route.host #{test_app_hostname.inspect}, to: :index do
141
+ path ":foobar"
142
+ end
143
+ RUBY
144
+ end
145
+
146
+ let(:expected_output) do
147
+ <<~OUTPUT
148
+ ---
149
+ routed: true
150
+ params:
151
+ foobar: barqux
152
+ action: :index
153
+ root_route:
154
+ match: true
155
+ params: {}
156
+ children:
157
+ - route:
158
+ host:
159
+ name: #{test_app_hostname}
160
+ match: true
161
+ params: {}
162
+ children:
163
+ - target_route:
164
+ action: :index
165
+ children:
166
+ - route:
167
+ path:
168
+ pattern: "/:foobar"
169
+ match: true
170
+ params:
171
+ foobar: barqux
172
+ children: []
173
+ OUTPUT
174
+ end
175
+
176
+ specify do
177
+ expect { route }.to output(expected_output).to_stdout
178
+ end
179
+ end
180
+
181
+ context "with a custom route, params, and a conditional target" do
182
+ let(:url) { "http://#{test_app_host}/users/42/edit" }
183
+ let(:routes) do
184
+ <<~RUBY
185
+ route.host #{test_app_hostname.inspect}, path: ":resource" do
186
+ custom do |root, uri|
187
+ root.path ":id", path: ":action" do
188
+ if uri.host == #{test_app_hostname.inspect}
189
+ root.to :foo
190
+ end
191
+ end
192
+ end
193
+ end
194
+ RUBY
195
+ end
196
+
197
+ let(:expected_output) do
198
+ <<~OUTPUT
199
+ ---
200
+ routed: true
201
+ params:
202
+ resource: users
203
+ id: '42'
204
+ action: edit
205
+ action: :foo
206
+ root_route:
207
+ match: true
208
+ params: {}
209
+ children:
210
+ - route:
211
+ host:
212
+ name: #{test_app_hostname}
213
+ match: true
214
+ params: {}
215
+ children:
216
+ - route:
217
+ path:
218
+ pattern: "/:resource"
219
+ match: true
220
+ params:
221
+ resource: users
222
+ children:
223
+ - sub_route:
224
+ custom:
225
+ custom: Proc
226
+ match: true
227
+ params:
228
+ resource: users
229
+ id: '42'
230
+ action: edit
231
+ children: []
232
+ OUTPUT
233
+ end
234
+
235
+ specify do
236
+ expect { route }.to output(expected_output).to_stdout
237
+ end
238
+ end
239
+
240
+ describe "query parameter matching" do
241
+ let(:url) { "http://#{test_app_host}?page=10&order=desc&mobile=0&referrer=startpage&foo=bar" }
242
+ let(:routes) do
243
+ <<~RUBY
244
+ route.query({ page: 1..20, order: "desc", mobile: 0, referrer: /start/ }, to: :foo)
245
+ RUBY
246
+ end
247
+
248
+ let(:expected_output) do
249
+ <<~OUTPUT
250
+ ---
251
+ routed: true
252
+ params:
253
+ page: '10'
254
+ order: desc
255
+ mobile: '0'
256
+ referrer: startpage
257
+ action: :foo
258
+ root_route:
259
+ match: true
260
+ params: {}
261
+ children:
262
+ - route:
263
+ query:
264
+ page:
265
+ min: 1
266
+ max: 20
267
+ order: desc
268
+ mobile: 0
269
+ referrer: "/start/"
270
+ match: true
271
+ params:
272
+ page: '10'
273
+ order: desc
274
+ mobile: '0'
275
+ referrer: startpage
276
+ children:
277
+ - target_route:
278
+ action: :foo
279
+ children: []
280
+ OUTPUT
281
+ end
282
+
283
+ specify do
284
+ expect { route }.to output(expected_output).to_stdout
285
+ end
286
+ end
287
+
288
+ context "with URL matcher" do
289
+ let(:url) { "http://#{test_app_host}" }
290
+ let(:routes) do
291
+ <<~RUBY
292
+ route.url "http://#{test_app_host}", to: :index
293
+ RUBY
294
+ end
295
+
296
+ let(:expected_output) do
297
+ <<~OUTPUT
298
+ ---
299
+ routed: true
300
+ params: {}
301
+ action: :index
302
+ root_route:
303
+ match: true
304
+ params: {}
305
+ children:
306
+ - route:
307
+ url:
308
+ url: #{url}
309
+ match: true
310
+ params: {}
311
+ children:
312
+ - target_route:
313
+ action: :index
314
+ children: []
315
+ OUTPUT
316
+ end
317
+
318
+ specify do
319
+ expect { route }.to output(expected_output).to_stdout
320
+ end
321
+ end
322
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "spec_helpers"
4
4
 
5
- describe Wayfarer::CLI, cli: true do
5
+ describe Wayfarer::CLI, :cli do # rubocop:disable RSpec/SpecFilePathFormat
6
6
  describe "version" do
7
7
  it "prints the version" do
8
8
  expect {
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe Wayfarer::GC, :integration, :redis do
6
+ describe "::run" do
7
+ subject(:run) { described_class.run(task) }
8
+
9
+ let(:job) { instance_spy(Class.new.include(Wayfarer::Base)) }
10
+ let(:task) { build(:task, :redis_pool, job: job) }
11
+ let(:barrier) { instance_spy(Wayfarer::Redis::Barrier) }
12
+
13
+ before do
14
+ allow(Wayfarer::Redis::Barrier).to receive(:new).with(task).and_return(barrier)
15
+ end
16
+
17
+ specify do
18
+ run
19
+
20
+ expect(job).to have_received(:run_callbacks).with(:batch)
21
+ end
22
+
23
+ specify do
24
+ run
25
+
26
+ expect(barrier).to have_received(:reset!)
27
+ end
28
+ end
29
+ end
@@ -5,7 +5,5 @@ require "spec_helpers"
5
5
  describe Wayfarer::Handler do
6
6
  subject { Class.new.include(described_class) }
7
7
 
8
- it "undefines ::after_batch" do
9
- expect(subject).not_to respond_to(:after_batch)
10
- end
8
+ it { is_expected.not_to respond_to(:after_batch) }
11
9
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  require "spec_helpers"
4
4
 
5
- describe Wayfarer::Callbacks, redis: true do
5
+ describe "Callbacks", :integration, :redis do
6
6
  before do
7
- stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base))
8
- stub_const("DummyHandler", Class.new.include(Wayfarer::Handler))
7
+ mock_job! :dummy_job
8
+ mock_handler! :dummy_handler
9
9
  end
10
10
 
11
11
  describe "job callbacks" do
@@ -103,9 +103,8 @@ describe Wayfarer::Callbacks, redis: true do
103
103
  end
104
104
 
105
105
  describe "job callbacks with handler" do
106
- before { stub_const("CallbacksFired", []) }
107
-
108
106
  before do
107
+ stub_const("CallbacksFired", [])
109
108
  DummyJob.class_eval do
110
109
  route.to [DummyHandler, :index]
111
110
 
@@ -191,7 +190,11 @@ describe Wayfarer::Callbacks, redis: true do
191
190
  end
192
191
 
193
192
  specify do
194
- DummyJob.new.perform(build(:task, url: test_app_path("alpha")))
193
+ DummyJob.crawl(test_app_path("alpha"))
194
+ perform_enqueued_jobs
195
+
196
+ assert_performed_jobs 1
197
+ expect(enqueued_jobs).to be_empty
195
198
  end
196
199
  end
197
200
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helpers"
4
+
5
+ describe "Content-Type allow listing", :redis do
6
+ using RSpec::Parameterized::TableSyntax
7
+
8
+ subject(:perform) { DummyJob.new.call(task) }
9
+
10
+ before do
11
+ mock_job! :dummy_job
12
+ end
13
+
14
+ with_them do
15
+ let(:task) { build(:task, url: url) }
16
+
17
+ specify do
18
+ types = content_types
19
+
20
+ DummyJob.class_eval do
21
+ route.to :index
22
+
23
+ content_type types
24
+
25
+ def index
26
+ true
27
+ end
28
+ end
29
+
30
+ expect(DummyJob.new.perform(task)).to be(expected)
31
+ end
32
+ end
33
+
34
+ where(:content_types, :url, :expected) do
35
+ "text/html" | test_app_path("response_header/Content-Type/text/html") | true
36
+ end
37
+ end