wayfarer 0.4.6 → 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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/.env +17 -0
  3. data/.github/workflows/lint.yaml +27 -0
  4. data/.github/workflows/release.yaml +30 -0
  5. data/.github/workflows/tests.yaml +21 -0
  6. data/.gitignore +5 -1
  7. data/.rubocop.yml +36 -0
  8. data/.vale.ini +8 -0
  9. data/.yardopts +1 -3
  10. data/Dockerfile +6 -4
  11. data/Gemfile +24 -0
  12. data/Gemfile.lock +274 -164
  13. data/Rakefile +7 -51
  14. data/bin/wayfarer +1 -1
  15. data/docker-compose.yml +23 -13
  16. data/docs/cookbook/consent_screen.md +2 -2
  17. data/docs/cookbook/executing_javascript.md +3 -3
  18. data/docs/cookbook/navigation.md +12 -12
  19. data/docs/cookbook/querying_html.md +3 -3
  20. data/docs/cookbook/screenshots.md +2 -2
  21. data/docs/guides/callbacks.md +25 -125
  22. data/docs/guides/cli.md +71 -0
  23. data/docs/guides/configuration.md +10 -35
  24. data/docs/guides/development.md +67 -0
  25. data/docs/guides/handlers.md +60 -0
  26. data/docs/guides/index.md +1 -0
  27. data/docs/guides/jobs.md +142 -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 +103 -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 +78 -10
  35. data/docs/guides/redis.md +10 -0
  36. data/docs/guides/routing.md +156 -0
  37. data/docs/guides/tasks.md +53 -9
  38. data/docs/guides/tutorial.md +66 -0
  39. data/docs/guides/user_agents.md +115 -0
  40. data/docs/index.md +17 -40
  41. data/lib/wayfarer/base.rb +125 -46
  42. data/lib/wayfarer/batch_completion.rb +60 -0
  43. data/lib/wayfarer/callbacks.rb +22 -48
  44. data/lib/wayfarer/cli/route_printer.rb +85 -89
  45. data/lib/wayfarer/cli.rb +103 -0
  46. data/lib/wayfarer/gc.rb +18 -6
  47. data/lib/wayfarer/handler.rb +15 -7
  48. data/lib/wayfarer/kv.rb +28 -0
  49. data/lib/wayfarer/logging.rb +38 -0
  50. data/lib/wayfarer/middleware/base.rb +2 -0
  51. data/lib/wayfarer/middleware/batch_completion.rb +19 -0
  52. data/lib/wayfarer/middleware/chain.rb +7 -1
  53. data/lib/wayfarer/middleware/content_type.rb +59 -0
  54. data/lib/wayfarer/middleware/controller.rb +19 -15
  55. data/lib/wayfarer/middleware/dedup.rb +22 -13
  56. data/lib/wayfarer/middleware/dispatch.rb +17 -4
  57. data/lib/wayfarer/middleware/normalize.rb +7 -14
  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 +31 -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 +14 -3
  65. data/lib/wayfarer/networking/ferrum.rb +1 -4
  66. data/lib/wayfarer/networking/follow.rb +14 -7
  67. data/lib/wayfarer/networking/http.rb +1 -1
  68. data/lib/wayfarer/networking/pool.rb +23 -13
  69. data/lib/wayfarer/networking/selenium.rb +15 -7
  70. data/lib/wayfarer/networking/strategy.rb +2 -2
  71. data/lib/wayfarer/page.rb +34 -14
  72. data/lib/wayfarer/parsing/xml.rb +6 -6
  73. data/lib/wayfarer/parsing.rb +21 -0
  74. data/lib/wayfarer/redis/barrier.rb +26 -21
  75. data/lib/wayfarer/redis/counter.rb +18 -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 +166 -30
  79. data/lib/wayfarer/routing/hash_stack.rb +33 -0
  80. data/lib/wayfarer/routing/matchers/custom.rb +8 -5
  81. data/lib/wayfarer/routing/matchers/{suffix.rb → empty_params.rb} +2 -6
  82. data/lib/wayfarer/routing/matchers/host.rb +15 -9
  83. data/lib/wayfarer/routing/matchers/path.rb +11 -31
  84. data/lib/wayfarer/routing/matchers/query.rb +41 -17
  85. data/lib/wayfarer/routing/matchers/result.rb +12 -0
  86. data/lib/wayfarer/routing/matchers/scheme.rb +13 -5
  87. data/lib/wayfarer/routing/matchers/url.rb +13 -5
  88. data/lib/wayfarer/routing/path_consumer.rb +130 -0
  89. data/lib/wayfarer/routing/path_finder.rb +151 -23
  90. data/lib/wayfarer/routing/result.rb +1 -1
  91. data/lib/wayfarer/routing/root_route.rb +17 -1
  92. data/lib/wayfarer/routing/route.rb +66 -19
  93. data/lib/wayfarer/routing/serializable.rb +28 -0
  94. data/lib/wayfarer/routing/sub_route.rb +53 -0
  95. data/lib/wayfarer/routing/target_route.rb +17 -1
  96. data/lib/wayfarer/stringify.rb +21 -30
  97. data/lib/wayfarer/task.rb +9 -17
  98. data/lib/wayfarer/uri/normalization.rb +120 -0
  99. data/lib/wayfarer.rb +72 -5
  100. data/mise.toml +2 -0
  101. data/mkdocs.yml +44 -8
  102. data/rake/docs.rake +26 -0
  103. data/rake/lint.rake +9 -0
  104. data/rake/release.rake +23 -0
  105. data/rake/tests.rake +32 -0
  106. data/requirements.txt +1 -1
  107. data/spec/factories/job.rb +8 -0
  108. data/spec/factories/middleware.rb +2 -2
  109. data/spec/factories/path_finder.rb +11 -0
  110. data/spec/factories/redis.rb +19 -0
  111. data/spec/factories/task.rb +46 -2
  112. data/spec/spec_helpers.rb +55 -51
  113. data/spec/support/active_job_helpers.rb +8 -0
  114. data/spec/support/integration_helpers.rb +21 -0
  115. data/spec/support/redis_helpers.rb +9 -0
  116. data/spec/support/test_app.rb +66 -37
  117. data/spec/wayfarer/base_spec.rb +200 -0
  118. data/spec/wayfarer/batch_completion_spec.rb +142 -0
  119. data/spec/wayfarer/cli/job_spec.rb +88 -0
  120. data/spec/wayfarer/cli/routing_spec.rb +322 -0
  121. data/spec/{cli → wayfarer/cli}/version_spec.rb +1 -1
  122. data/spec/wayfarer/gc_spec.rb +29 -0
  123. data/spec/wayfarer/handler_spec.rb +9 -0
  124. data/spec/wayfarer/integration/callbacks_spec.rb +200 -0
  125. data/spec/wayfarer/integration/content_type_spec.rb +37 -0
  126. data/spec/wayfarer/integration/custom_routing_spec.rb +51 -0
  127. data/spec/wayfarer/integration/gc_spec.rb +40 -0
  128. data/spec/wayfarer/integration/handler_spec.rb +65 -0
  129. data/spec/wayfarer/integration/page_spec.rb +79 -0
  130. data/spec/wayfarer/integration/params_spec.rb +64 -0
  131. data/spec/wayfarer/integration/parsing_spec.rb +99 -0
  132. data/spec/wayfarer/integration/retry_spec.rb +112 -0
  133. data/spec/wayfarer/integration/stage_spec.rb +58 -0
  134. data/spec/wayfarer/middleware/batch_completion_spec.rb +33 -0
  135. data/spec/{middleware → wayfarer/middleware}/chain_spec.rb +24 -19
  136. data/spec/wayfarer/middleware/content_type_spec.rb +83 -0
  137. data/spec/{middleware → wayfarer/middleware}/controller_spec.rb +24 -22
  138. data/spec/wayfarer/middleware/dedup_spec.rb +66 -0
  139. data/spec/wayfarer/middleware/normalize_spec.rb +32 -0
  140. data/spec/wayfarer/middleware/router_spec.rb +102 -0
  141. data/spec/wayfarer/middleware/stage_spec.rb +63 -0
  142. data/spec/wayfarer/middleware/uri_parser_spec.rb +63 -0
  143. data/spec/wayfarer/middleware/user_agent_spec.rb +158 -0
  144. data/spec/wayfarer/networking/capybara_spec.rb +13 -0
  145. data/spec/{networking → wayfarer/networking}/context_spec.rb +46 -38
  146. data/spec/wayfarer/networking/ferrum_spec.rb +13 -0
  147. data/spec/{networking → wayfarer/networking}/follow_spec.rb +11 -6
  148. data/spec/wayfarer/networking/http_spec.rb +12 -0
  149. data/spec/{networking → wayfarer/networking}/pool_spec.rb +16 -14
  150. data/spec/wayfarer/networking/selenium_spec.rb +12 -0
  151. data/spec/{networking → wayfarer/networking}/strategy.rb +33 -54
  152. data/spec/wayfarer/page_spec.rb +69 -0
  153. data/spec/{parsing → wayfarer/parsing}/json_spec.rb +1 -1
  154. data/spec/wayfarer/parsing/xml_parse_spec.rb +25 -0
  155. data/spec/wayfarer/redis/barrier_spec.rb +39 -0
  156. data/spec/wayfarer/redis/counter_spec.rb +34 -0
  157. data/spec/{redis → wayfarer/redis}/pool_spec.rb +4 -3
  158. data/spec/{routing → wayfarer/routing}/dsl_spec.rb +12 -22
  159. data/spec/wayfarer/routing/hash_stack_spec.rb +63 -0
  160. data/spec/wayfarer/routing/integration_spec.rb +101 -0
  161. data/spec/wayfarer/routing/matchers/custom_spec.rb +39 -0
  162. data/spec/wayfarer/routing/matchers/host_spec.rb +56 -0
  163. data/spec/wayfarer/routing/matchers/matcher.rb +17 -0
  164. data/spec/wayfarer/routing/matchers/path_spec.rb +43 -0
  165. data/spec/wayfarer/routing/matchers/query_spec.rb +123 -0
  166. data/spec/wayfarer/routing/matchers/scheme_spec.rb +45 -0
  167. data/spec/wayfarer/routing/matchers/url_spec.rb +33 -0
  168. data/spec/wayfarer/routing/path_consumer_spec.rb +123 -0
  169. data/spec/wayfarer/routing/path_finder_spec.rb +409 -0
  170. data/spec/wayfarer/routing/root_route_spec.rb +51 -0
  171. data/spec/wayfarer/routing/route_spec.rb +74 -0
  172. data/spec/wayfarer/routing/sub_route_spec.rb +103 -0
  173. data/spec/wayfarer/task_spec.rb +13 -0
  174. data/spec/wayfarer/uri/normalization_spec.rb +98 -0
  175. data/spec/wayfarer_spec.rb +2 -2
  176. data/wayfarer.gemspec +18 -28
  177. metadata +797 -265
  178. data/.github/workflows/ci.yaml +0 -32
  179. data/.rbenv-gemsets +0 -1
  180. data/.ruby-version +0 -1
  181. data/RELEASING.md +0 -17
  182. data/docs/cookbook/user_agent.md +0 -7
  183. data/docs/guides/error_handling.md +0 -53
  184. data/docs/guides/networking.md +0 -94
  185. data/docs/guides/performance.md +0 -130
  186. data/docs/guides/reliability.md +0 -41
  187. data/docs/guides/routing/steering.md +0 -30
  188. data/docs/reference/api/base.md +0 -48
  189. data/docs/reference/cli.md +0 -61
  190. data/docs/reference/configuration_keys.md +0 -43
  191. data/docs/reference/environment_variables.md +0 -83
  192. data/lib/wayfarer/cli/base.rb +0 -45
  193. data/lib/wayfarer/cli/generate.rb +0 -17
  194. data/lib/wayfarer/cli/job.rb +0 -56
  195. data/lib/wayfarer/cli/route.rb +0 -29
  196. data/lib/wayfarer/cli/runner.rb +0 -34
  197. data/lib/wayfarer/cli/templates/Gemfile.tt +0 -5
  198. data/lib/wayfarer/cli/templates/job.rb.tt +0 -10
  199. data/lib/wayfarer/config/capybara.rb +0 -10
  200. data/lib/wayfarer/config/ferrum.rb +0 -11
  201. data/lib/wayfarer/config/networking.rb +0 -29
  202. data/lib/wayfarer/config/redis.rb +0 -14
  203. data/lib/wayfarer/config/root.rb +0 -11
  204. data/lib/wayfarer/config/selenium.rb +0 -21
  205. data/lib/wayfarer/config/strconv.rb +0 -45
  206. data/lib/wayfarer/config/struct.rb +0 -72
  207. data/lib/wayfarer/middleware/fetch.rb +0 -56
  208. data/lib/wayfarer/redis/connection.rb +0 -13
  209. data/lib/wayfarer/redis/version.rb +0 -19
  210. data/lib/wayfarer/routing/router.rb +0 -28
  211. data/spec/base_spec.rb +0 -224
  212. data/spec/callbacks_spec.rb +0 -102
  213. data/spec/cli/generate_spec.rb +0 -39
  214. data/spec/cli/job_spec.rb +0 -78
  215. data/spec/config/capybara_spec.rb +0 -18
  216. data/spec/config/ferrum_spec.rb +0 -24
  217. data/spec/config/networking_spec.rb +0 -73
  218. data/spec/config/redis_spec.rb +0 -32
  219. data/spec/config/root_spec.rb +0 -31
  220. data/spec/config/selenium_spec.rb +0 -56
  221. data/spec/config/strconv_spec.rb +0 -58
  222. data/spec/config/struct_spec.rb +0 -66
  223. data/spec/fixtures/dummy_job.rb +0 -7
  224. data/spec/gc_spec.rb +0 -59
  225. data/spec/handler_spec.rb +0 -11
  226. data/spec/integration/callbacks_spec.rb +0 -85
  227. data/spec/integration/page_spec.rb +0 -62
  228. data/spec/integration/params_spec.rb +0 -56
  229. data/spec/integration/stage_spec.rb +0 -51
  230. data/spec/integration/steering_spec.rb +0 -57
  231. data/spec/middleware/dedup_spec.rb +0 -88
  232. data/spec/middleware/dispatch_spec.rb +0 -43
  233. data/spec/middleware/fetch_spec.rb +0 -155
  234. data/spec/middleware/normalize_spec.rb +0 -29
  235. data/spec/middleware/router_spec.rb +0 -105
  236. data/spec/middleware/stage_spec.rb +0 -62
  237. data/spec/networking/capybara_spec.rb +0 -12
  238. data/spec/networking/ferrum_spec.rb +0 -12
  239. data/spec/networking/http_spec.rb +0 -12
  240. data/spec/networking/selenium_spec.rb +0 -12
  241. data/spec/page_spec.rb +0 -47
  242. data/spec/parsing/xml_spec.rb +0 -25
  243. data/spec/redis/barrier_spec.rb +0 -78
  244. data/spec/redis/counter_spec.rb +0 -32
  245. data/spec/redis/version_spec.rb +0 -13
  246. data/spec/routing/integration_spec.rb +0 -110
  247. data/spec/routing/matchers/custom_spec.rb +0 -31
  248. data/spec/routing/matchers/host_spec.rb +0 -49
  249. data/spec/routing/matchers/path_spec.rb +0 -43
  250. data/spec/routing/matchers/query_spec.rb +0 -137
  251. data/spec/routing/matchers/scheme_spec.rb +0 -25
  252. data/spec/routing/matchers/suffix_spec.rb +0 -41
  253. data/spec/routing/matchers/uri_spec.rb +0 -27
  254. data/spec/routing/path_finder_spec.rb +0 -33
  255. data/spec/routing/root_route_spec.rb +0 -29
  256. data/spec/routing/route_spec.rb +0 -43
  257. data/spec/routing/router_spec.rb +0 -24
  258. data/spec/task_spec.rb +0 -34
  259. data/spec/{stringify_spec.rb → wayfarer/stringify_spec.rb} +2 -2
data/rake/release.rake ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "yaml"
5
+ require "bundler/gem_tasks"
6
+
7
+ namespace :release do
8
+ task :guard_versions do
9
+ gem_spec = Gem::Specification.load("wayfarer.gemspec")
10
+ gem_version = gem_spec.version.version
11
+ lib_version = Wayfarer::VERSION::STRING
12
+
13
+ raise "Gem version #{gem_version} deviates from library version #{lib_version}" unless gem_version == lib_version
14
+ end
15
+
16
+ task :guard_debug do
17
+ sh "git diff --exit-code"
18
+ sh "git diff-index --quiet --cached HEAD"
19
+ end
20
+ end
21
+
22
+ Rake::Task[:"release:rubygem_push"].enhance(%i[release:guard_versions])
23
+ Rake::Task[:"release:guard_clean"].enhance(%i[release:guard_debug])
data/rake/tests.rake ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/core/rake_task"
4
+
5
+ desc "Run all tests"
6
+ RSpec::Core::RakeTask.new(:test)
7
+
8
+ namespace :test do
9
+ desc "Run only isolated tests"
10
+ RSpec::Core::RakeTask.new :isolated do |task|
11
+ task.rspec_opts = %w[--tag ~selenium --tag ~ferrum --tag ~cli --tag ~redis]
12
+ end
13
+
14
+ RSpec::Core::RakeTask.new :integration do |task|
15
+ task.rspec_opts = %w[--tag redis --tag cli]
16
+ end
17
+
18
+ desc "Run only Selenium tests"
19
+ RSpec::Core::RakeTask.new :selenium do |task|
20
+ task.rspec_opts = %w[--tag selenium]
21
+ end
22
+
23
+ desc "Run only Ferrum tests"
24
+ RSpec::Core::RakeTask.new :ferrum do |task|
25
+ task.rspec_opts = %w[--tag ferrum]
26
+ end
27
+
28
+ desc "Run only CLI tests"
29
+ RSpec::Core::RakeTask.new :cli do |task|
30
+ task.rspec_opts = %w[--tag cli]
31
+ end
32
+ end
data/requirements.txt CHANGED
@@ -1 +1 @@
1
- mkdocs-material == 7.3.0
1
+ mkdocs-material == 9.6.12
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :job, class: ActiveJob::Base do
5
+ executions { 1 }
6
+ exception_executions { Object.new }
7
+ end
8
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  FactoryBot.define do
4
- factory :middleware, class: OpenStruct do
4
+ factory :middleware, class: Struct.new(:receiver) do
5
5
  receiver { -> {} }
6
6
 
7
7
  initialize_with do
8
- new(receiver: receiver).tap do |middleware|
8
+ new(receiver).tap do |middleware|
9
9
  middleware.define_singleton_method(:call) do |task, &block|
10
10
  receiver.call(task, &block)
11
11
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :path_finder, class: Wayfarer::Routing::PathFinder do
5
+ url { "https://example.com" }
6
+
7
+ initialize_with do
8
+ new(build(:task, :uri, url: url))
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :counter, class: Wayfarer::Redis::Counter do
5
+ task { build(:task, :redis_pool) }
6
+
7
+ initialize_with do
8
+ new(task)
9
+ end
10
+ end
11
+
12
+ factory :barrier, class: Wayfarer::Redis::Barrier do
13
+ task { build(:task, :redis_pool) }
14
+
15
+ initialize_with do
16
+ new(task)
17
+ end
18
+ end
19
+ end
@@ -2,11 +2,55 @@
2
2
 
3
3
  FactoryBot.define do
4
4
  factory :task, class: Wayfarer::Task do
5
- url { "https://example.com" }
5
+ url { test_app_path("/") }
6
6
  batch { "batch" }
7
7
 
8
+ transient do
9
+ job { nil }
10
+ controller { nil }
11
+ action { nil }
12
+ end
13
+
8
14
  initialize_with do
9
- new(url, batch)
15
+ new(url, batch).tap do |task|
16
+ task[:job] = job
17
+ task[:controller] = controller
18
+ task[:action] = action
19
+ end
20
+ end
21
+
22
+ trait :staged_urls do
23
+ after(:build) do |task|
24
+ task[:staged_urls] = SortedSet.new
25
+ end
26
+ end
27
+
28
+ trait :redis_pool do
29
+ after(:build) do |task|
30
+ task[:redis_pool] = Wayfarer::Redis::Pool.instance
31
+ end
32
+ end
33
+
34
+ trait :barrier do
35
+ redis_pool
36
+
37
+ after(:build) do |task|
38
+ task[:barrier] = Wayfarer::Redis::Barrier.new(task)
39
+ end
40
+ end
41
+
42
+ trait :uri do
43
+ after(:build) do |task|
44
+ task[:uri] = Addressable::URI.parse(task.url)
45
+ end
46
+ end
47
+
48
+ trait :normalized do
49
+ uri
50
+
51
+ after(:build) do |task|
52
+ task[:uri] = Wayfarer::URI::Normalization.canonical!(task[:uri])
53
+ end
10
54
  end
11
55
  end
12
56
  end
data/spec/spec_helpers.rb CHANGED
@@ -1,44 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/object/deep_dup"
4
+ require "capybara/cuprite"
3
5
  require "factory_bot"
6
+ require "puma"
4
7
  require "pry"
8
+ require "rake"
9
+ require "rspec-parameterized"
5
10
  require "sinatra"
6
- require "capybara/cuprite"
11
+ require "webrick"
7
12
 
8
13
  require_relative "../lib/wayfarer"
14
+
9
15
  require_relative "support/test_app"
16
+ require_relative "support/redis_helpers"
17
+ require_relative "support/active_job_helpers"
18
+ require_relative "support/integration_helpers"
10
19
 
11
20
  module SpecHelpers
12
- def test_app_path(path)
13
- File.join("http://", test_app_host, path)
21
+ WAYFARER_TEST_APP_PORT = ENV.fetch("WAYFARER_PORT", "9876").to_s
22
+
23
+ def ci?
24
+ ENV.key?("CI")
25
+ end
26
+
27
+ def test_redis_host
28
+ ci? ? "redis" : "localhost"
14
29
  end
15
30
 
16
31
  def test_app_host
17
- if ENV["CI"]
18
- "test:9876"
19
- else
20
- "localhost:9876"
21
- end
32
+ ci? ? "test" : "localhost"
22
33
  end
23
34
 
24
- def redis_host
25
- if ENV["CI"]
26
- "redis://redis:6379"
27
- else
28
- "redis://localhost:6379"
29
- end
35
+ def redis_url
36
+ "redis://#{test_redis_host}:6379/0"
30
37
  end
31
38
 
32
- def write_file(path, contents)
33
- FileUtils.mkdir_p(Pathname.new(path).dirname)
34
- IO.write(path, contents)
39
+ def test_app_path(path = "")
40
+ File.join("http://", "#{test_app_host}:#{WAYFARER_TEST_APP_PORT}", path)
35
41
  end
36
42
 
37
- # ActiveJob test helpers swallow errors
38
- Base = Class.new(Wayfarer::Base) do
39
- rescue_from(StandardError) do |e|
40
- raise e
41
- end
43
+ def test_app_hostname
44
+ test_app_host.split(":").first
45
+ end
46
+
47
+ def write_file(path, contents)
48
+ FileUtils.mkdir_p(Pathname.new(path).dirname)
49
+ File.write(path, contents)
42
50
  end
43
51
  end
44
52
 
@@ -46,52 +54,47 @@ RSpec.configure do |config|
46
54
  config.include(FactoryBot::Syntax::Methods)
47
55
  config.include(ActiveJob::TestHelper)
48
56
  config.include(SpecHelpers)
57
+ config.include(ActiveJobTestHelper)
58
+ config.include(IntegrationHelpers)
49
59
 
50
- config.before(:suite) do
51
- FactoryBot.find_definitions
60
+ # The shared context enables a global `let(:redis)` declaration
61
+ config.include_context "with Redis", :redis
52
62
 
53
- mutex = Mutex.new
54
- cvar = ConditionVariable.new
63
+ config.before :suite do
64
+ Wayfarer::Logging.logger = Logger.new($stdout)
55
65
 
56
- Thread.new do
57
- Rack::Handler::WEBrick.run(TestApp,
58
- Host: "0.0.0.0",
59
- Port: 9876,
60
- Logger: WEBrick::Log.new("/dev/null"),
61
- AccessLog: [],
62
- StartCallback: proc { cvar.signal })
63
- end
66
+ FactoryBot.find_definitions
67
+ FactoryBot::SyntaxRunner.include(SpecHelpers)
64
68
 
65
- mutex.lock
66
- cvar.wait(mutex)
69
+ Support::TestApp.start!(SpecHelpers::WAYFARER_TEST_APP_PORT)
67
70
  end
68
71
 
69
72
  config.before do
70
- Wayfarer.config = Wayfarer::Config::Root.new
71
- Wayfarer.config.redis.url = redis_host
73
+ Wayfarer.config = Wayfarer::DEFAULT_CONFIG.deep_dup
74
+ Wayfarer.config[:redis][:url] = redis_url
72
75
 
73
- ::Redis.new(url: redis_host).flushall
74
-
75
- ActiveJob::Base.queue_adapter = :test
76
76
  ActiveJob::Base.logger = Logger.new(nil)
77
+ ActiveJob::Base.queue_adapter = :test
77
78
  ActiveJob::Base.queue_adapter.enqueued_jobs.clear
78
79
  ActiveJob::Base.queue_adapter.performed_jobs.clear
79
80
 
80
- if ENV["CI"]
81
- # For unknown reasons, Wayfarer::Networking::Ferrum#renew can take a very
82
- # long time to instantiate a new ::Ferrum::Browser and requires the 60s
83
- # timeout. TODO: Figure out what's going on
84
- Wayfarer.config.ferrum.options = { url: "http://chrome:3000", timeout: 120 }
85
- Wayfarer.config.selenium.driver = :firefox
86
- Wayfarer.config.selenium.options = { url: "http://firefox:4444" }
87
- Wayfarer.config.selenium.client_timeout = 10
81
+ if ENV.key?("CI")
82
+ Wayfarer.config[:ferrum][:options] = { url: "http://chrome:3000", timeout: 120 }
83
+
84
+ Wayfarer.config[:selenium][:driver] = :remote
85
+ Wayfarer.config[:selenium][:options] = {
86
+ url: "http://firefox:4444",
87
+ options: Selenium::WebDriver::Options.firefox
88
+ }
88
89
  end
89
90
 
90
91
  # TODO: Undo side-effect
91
92
  Capybara.register_driver(:cuprite) do |app|
92
- Capybara::Cuprite::Driver.new(app, Wayfarer.config.ferrum.options)
93
+ Capybara::Cuprite::Driver.new(app, Wayfarer.config.dig(:ferrum, :options))
93
94
  end
94
- Wayfarer.config.capybara.driver = :cuprite
95
+ Wayfarer.config[:capybara][:driver] = :cuprite
96
+
97
+ Wayfarer::Networking::Pool.finalizer = ->(_pool) {}
95
98
  end
96
99
 
97
100
  config.around(cli: true) do |example|
@@ -99,6 +102,7 @@ RSpec.configure do |config|
99
102
  tmp = Dir.mktmpdir
100
103
  Dir.chdir(tmp)
101
104
  example.run
105
+ ensure
102
106
  Dir.chdir(origin)
103
107
  FileUtils.rm_r(tmp)
104
108
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJobTestHelper
4
+ # perform_enqueued_jobs expects assert_equal to be defined
5
+ def assert_equal(expected, actual, _)
6
+ expect(actual).to eq(expected)
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IntegrationHelpers
4
+ def mock_job!(symbol)
5
+ mock!(symbol) do
6
+ Class.new(ActiveJob::Base).include(Wayfarer::Base)
7
+ end
8
+ end
9
+
10
+ def mock_handler!(symbol)
11
+ mock!(symbol) do
12
+ Class.new.include(Wayfarer::Handler)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def mock!(symbol, &block)
19
+ stub_const(symbol.to_s.camelize, block.call)
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_context "with Redis", :redis do
4
+ let(:redis) { Redis.new(url: redis_url) }
5
+
6
+ before do
7
+ redis.flushall
8
+ end
9
+ end
@@ -1,52 +1,81 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class TestApp < Sinatra::Base
4
- set :root, File.dirname(__FILE__)
5
- set :public_folder, -> { File.join(root, "static") }
3
+ module Support
4
+ class TestApp < Sinatra::Base
5
+ def self.start!(port)
6
+ mutex = Mutex.new
7
+ cvar = ConditionVariable.new
6
8
 
7
- get "/status_code/:code" do
8
- status params[:code]
9
- end
9
+ Thread.new do
10
+ Rackup::Handler::WEBrick.run(
11
+ TestApp,
12
+ Host: "0.0.0.0",
13
+ Port: port,
14
+ Logger: WEBrick::Log.new(File::NULL),
15
+ AccessLog: [],
16
+ StartCallback: proc { cvar.signal }
17
+ )
18
+ end
10
19
 
11
- get "/headers/:header" do
12
- request.env[params[:header]]
13
- end
20
+ mutex.lock
21
+ cvar.wait(mutex)
22
+ end
14
23
 
15
- get "/hello_world" do
16
- headers "hello" => "world"
17
- "Hello world!"
18
- end
24
+ set :root, File.dirname(__FILE__)
25
+ set :public_folder, -> { File.join(root, "static") }
19
26
 
20
- get "/body/:content" do
21
- params[:content]
22
- end
27
+ get "/status_code/:code" do
28
+ status params[:code]
29
+ end
23
30
 
24
- get "/redirect_loop" do
25
- redirect to "/redirect_loop"
26
- end
31
+ get "/headers/:header" do
32
+ request.env[params[:header]]
33
+ end
27
34
 
28
- get "/redirect" do
29
- n = params[:times].to_i
30
- n.zero? ? "You arrived!" : (redirect to "/redirect?times=#{n - 1}")
31
- end
35
+ get "/response_header/:key/:val" do
36
+ headers params[:key] => params[:val]
37
+ end
32
38
 
33
- get "/malformed_redirect" do
34
- redirect to "hptt://bro.ken"
35
- end
39
+ get "/response_header/Content-Type/*" do
40
+ content_type params[:splat].first
41
+ end
36
42
 
37
- get "/json/:file" do
38
- content_type "application/json"
39
- send_file(static_file("json/#{params[:file]}"))
40
- end
43
+ get "/hello_world" do
44
+ headers "hello" => "world"
45
+ "Hello world!"
46
+ end
41
47
 
42
- get "/xml/:file" do
43
- content_type "application/xml"
44
- send_file(static_file("xml/#{params[:file]}"))
45
- end
48
+ get "/body/:content" do
49
+ params[:content]
50
+ end
51
+
52
+ get "/redirect_loop" do
53
+ redirect to "/redirect_loop"
54
+ end
55
+
56
+ get "/redirect" do
57
+ n = params[:times].to_i
58
+ n.zero? ? "You arrived!" : (redirect to "/redirect?times=#{n - 1}")
59
+ end
60
+
61
+ get "/malformed_redirect" do
62
+ redirect to "hptt://bro.ken"
63
+ end
64
+
65
+ get "/json/:file" do
66
+ content_type "application/json"
67
+ send_file(static_file("json/#{params[:file]}"))
68
+ end
69
+
70
+ get "/xml/:file" do
71
+ content_type "application/xml"
72
+ send_file(static_file("xml/#{params[:file]}"))
73
+ end
46
74
 
47
- private
75
+ private
48
76
 
49
- def static_file(file_path)
50
- File.expand_path(file_path, settings.public_folder)
77
+ def static_file(file_path)
78
+ File.expand_path(file_path, settings.public_folder)
79
+ end
51
80
  end
52
81
  end