wayfarer 0.0.3

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 (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rbenv-gemsets +1 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +21 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +5 -0
  8. data/.yardopts +3 -0
  9. data/Changelog.md +10 -0
  10. data/Gemfile +11 -0
  11. data/LICENSE +19 -0
  12. data/README.md +21 -0
  13. data/Rakefile +114 -0
  14. data/benchmark/frontiers.rb +143 -0
  15. data/bin/wayfarer +116 -0
  16. data/docs/.gitignore +2 -0
  17. data/docs/_config.yml +15 -0
  18. data/docs/_includes/base.html +7 -0
  19. data/docs/_includes/head.html +10 -0
  20. data/docs/_includes/navigation.html +187 -0
  21. data/docs/_layouts/default.html +42 -0
  22. data/docs/_sass/base.scss +439 -0
  23. data/docs/_sass/variables.scss +24 -0
  24. data/docs/_sass/vendor/bourbon/_bourbon-deprecate.scss +19 -0
  25. data/docs/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss +425 -0
  26. data/docs/_sass/vendor/bourbon/_bourbon.scss +90 -0
  27. data/docs/_sass/vendor/bourbon/addons/_border-color.scss +29 -0
  28. data/docs/_sass/vendor/bourbon/addons/_border-radius.scss +48 -0
  29. data/docs/_sass/vendor/bourbon/addons/_border-style.scss +28 -0
  30. data/docs/_sass/vendor/bourbon/addons/_border-width.scss +28 -0
  31. data/docs/_sass/vendor/bourbon/addons/_buttons.scss +69 -0
  32. data/docs/_sass/vendor/bourbon/addons/_clearfix.scss +25 -0
  33. data/docs/_sass/vendor/bourbon/addons/_ellipsis.scss +30 -0
  34. data/docs/_sass/vendor/bourbon/addons/_font-stacks.scss +31 -0
  35. data/docs/_sass/vendor/bourbon/addons/_hide-text.scss +27 -0
  36. data/docs/_sass/vendor/bourbon/addons/_margin.scss +29 -0
  37. data/docs/_sass/vendor/bourbon/addons/_padding.scss +29 -0
  38. data/docs/_sass/vendor/bourbon/addons/_position.scss +51 -0
  39. data/docs/_sass/vendor/bourbon/addons/_prefixer.scss +66 -0
  40. data/docs/_sass/vendor/bourbon/addons/_retina-image.scss +27 -0
  41. data/docs/_sass/vendor/bourbon/addons/_size.scss +56 -0
  42. data/docs/_sass/vendor/bourbon/addons/_text-inputs.scss +118 -0
  43. data/docs/_sass/vendor/bourbon/addons/_timing-functions.scss +34 -0
  44. data/docs/_sass/vendor/bourbon/addons/_triangle.scss +63 -0
  45. data/docs/_sass/vendor/bourbon/addons/_word-wrap.scss +29 -0
  46. data/docs/_sass/vendor/bourbon/css3/_animation.scss +61 -0
  47. data/docs/_sass/vendor/bourbon/css3/_appearance.scss +5 -0
  48. data/docs/_sass/vendor/bourbon/css3/_backface-visibility.scss +5 -0
  49. data/docs/_sass/vendor/bourbon/css3/_background-image.scss +44 -0
  50. data/docs/_sass/vendor/bourbon/css3/_background.scss +57 -0
  51. data/docs/_sass/vendor/bourbon/css3/_border-image.scss +61 -0
  52. data/docs/_sass/vendor/bourbon/css3/_calc.scss +6 -0
  53. data/docs/_sass/vendor/bourbon/css3/_columns.scss +67 -0
  54. data/docs/_sass/vendor/bourbon/css3/_filter.scss +6 -0
  55. data/docs/_sass/vendor/bourbon/css3/_flex-box.scss +327 -0
  56. data/docs/_sass/vendor/bourbon/css3/_font-face.scss +29 -0
  57. data/docs/_sass/vendor/bourbon/css3/_font-feature-settings.scss +6 -0
  58. data/docs/_sass/vendor/bourbon/css3/_hidpi-media-query.scss +12 -0
  59. data/docs/_sass/vendor/bourbon/css3/_hyphens.scss +6 -0
  60. data/docs/_sass/vendor/bourbon/css3/_image-rendering.scss +15 -0
  61. data/docs/_sass/vendor/bourbon/css3/_keyframes.scss +38 -0
  62. data/docs/_sass/vendor/bourbon/css3/_linear-gradient.scss +40 -0
  63. data/docs/_sass/vendor/bourbon/css3/_perspective.scss +12 -0
  64. data/docs/_sass/vendor/bourbon/css3/_placeholder.scss +10 -0
  65. data/docs/_sass/vendor/bourbon/css3/_radial-gradient.scss +40 -0
  66. data/docs/_sass/vendor/bourbon/css3/_selection.scss +44 -0
  67. data/docs/_sass/vendor/bourbon/css3/_text-decoration.scss +27 -0
  68. data/docs/_sass/vendor/bourbon/css3/_transform.scss +21 -0
  69. data/docs/_sass/vendor/bourbon/css3/_transition.scss +81 -0
  70. data/docs/_sass/vendor/bourbon/css3/_user-select.scss +5 -0
  71. data/docs/_sass/vendor/bourbon/functions/_assign-inputs.scss +16 -0
  72. data/docs/_sass/vendor/bourbon/functions/_contains-falsy.scss +25 -0
  73. data/docs/_sass/vendor/bourbon/functions/_contains.scss +31 -0
  74. data/docs/_sass/vendor/bourbon/functions/_is-length.scss +16 -0
  75. data/docs/_sass/vendor/bourbon/functions/_is-light.scss +26 -0
  76. data/docs/_sass/vendor/bourbon/functions/_is-number.scss +16 -0
  77. data/docs/_sass/vendor/bourbon/functions/_is-size.scss +23 -0
  78. data/docs/_sass/vendor/bourbon/functions/_modular-scale.scss +74 -0
  79. data/docs/_sass/vendor/bourbon/functions/_px-to-em.scss +24 -0
  80. data/docs/_sass/vendor/bourbon/functions/_px-to-rem.scss +26 -0
  81. data/docs/_sass/vendor/bourbon/functions/_shade.scss +24 -0
  82. data/docs/_sass/vendor/bourbon/functions/_strip-units.scss +22 -0
  83. data/docs/_sass/vendor/bourbon/functions/_tint.scss +24 -0
  84. data/docs/_sass/vendor/bourbon/functions/_transition-property-name.scss +37 -0
  85. data/docs/_sass/vendor/bourbon/functions/_unpack.scss +32 -0
  86. data/docs/_sass/vendor/bourbon/helpers/_convert-units.scss +26 -0
  87. data/docs/_sass/vendor/bourbon/helpers/_directional-values.scss +108 -0
  88. data/docs/_sass/vendor/bourbon/helpers/_font-source-declaration.scss +53 -0
  89. data/docs/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss +24 -0
  90. data/docs/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss +35 -0
  91. data/docs/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss +51 -0
  92. data/docs/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss +77 -0
  93. data/docs/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss +41 -0
  94. data/docs/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss +74 -0
  95. data/docs/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss +55 -0
  96. data/docs/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss +28 -0
  97. data/docs/_sass/vendor/bourbon/helpers/_render-gradients.scss +31 -0
  98. data/docs/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss +15 -0
  99. data/docs/_sass/vendor/bourbon/helpers/_str-to-num.scss +55 -0
  100. data/docs/_sass/vendor/bourbon/settings/_asset-pipeline.scss +7 -0
  101. data/docs/_sass/vendor/bourbon/settings/_deprecation-warnings.scss +8 -0
  102. data/docs/_sass/vendor/bourbon/settings/_prefixer.scss +9 -0
  103. data/docs/_sass/vendor/bourbon/settings/_px-to-em.scss +1 -0
  104. data/docs/_sass/vendor/neat/_neat-helpers.scss +11 -0
  105. data/docs/_sass/vendor/neat/_neat.scss +23 -0
  106. data/docs/_sass/vendor/neat/functions/_new-breakpoint.scss +49 -0
  107. data/docs/_sass/vendor/neat/functions/_private.scss +114 -0
  108. data/docs/_sass/vendor/neat/grid/_box-sizing.scss +15 -0
  109. data/docs/_sass/vendor/neat/grid/_direction-context.scss +33 -0
  110. data/docs/_sass/vendor/neat/grid/_display-context.scss +28 -0
  111. data/docs/_sass/vendor/neat/grid/_fill-parent.scss +22 -0
  112. data/docs/_sass/vendor/neat/grid/_media.scss +92 -0
  113. data/docs/_sass/vendor/neat/grid/_omega.scss +87 -0
  114. data/docs/_sass/vendor/neat/grid/_outer-container.scss +34 -0
  115. data/docs/_sass/vendor/neat/grid/_pad.scss +25 -0
  116. data/docs/_sass/vendor/neat/grid/_private.scss +35 -0
  117. data/docs/_sass/vendor/neat/grid/_row.scss +52 -0
  118. data/docs/_sass/vendor/neat/grid/_shift.scss +50 -0
  119. data/docs/_sass/vendor/neat/grid/_span-columns.scss +94 -0
  120. data/docs/_sass/vendor/neat/grid/_to-deprecate.scss +97 -0
  121. data/docs/_sass/vendor/neat/grid/_visual-grid.scss +42 -0
  122. data/docs/_sass/vendor/neat/mixins/_clearfix.scss +25 -0
  123. data/docs/_sass/vendor/neat/settings/_disable-warnings.scss +13 -0
  124. data/docs/_sass/vendor/neat/settings/_grid.scss +51 -0
  125. data/docs/_sass/vendor/neat/settings/_visual-grid.scss +27 -0
  126. data/docs/_sass/vendor/normalize-3.0.2.scss +427 -0
  127. data/docs/_sass/vendor/pygments.scss +356 -0
  128. data/docs/automating_browsers/capybara.md +70 -0
  129. data/docs/css/screen.scss +7 -0
  130. data/docs/guides/callbacks.md +45 -0
  131. data/docs/guides/cli.md +52 -0
  132. data/docs/guides/configuration.md +184 -0
  133. data/docs/guides/error_handling.md +46 -0
  134. data/docs/guides/frontiers.md +93 -0
  135. data/docs/guides/halting.md +23 -0
  136. data/docs/guides/job_queues.md +26 -0
  137. data/docs/guides/locals.md +36 -0
  138. data/docs/guides/logging.md +22 -0
  139. data/docs/guides/page_objects.md +67 -0
  140. data/docs/guides/peeking.md +46 -0
  141. data/docs/guides/selenium_capybara.md +100 -0
  142. data/docs/guides/tutorial.md +452 -0
  143. data/docs/index.md +82 -0
  144. data/docs/js/navigation.js +11 -0
  145. data/docs/misc/contributing.md +20 -0
  146. data/docs/misc/testing.md +11 -0
  147. data/docs/recipes/authentication.md +23 -0
  148. data/docs/recipes/csv.md +29 -0
  149. data/docs/recipes/javascript.md +20 -0
  150. data/docs/recipes/multiple_uris.md +18 -0
  151. data/docs/recipes/screenshots.md +20 -0
  152. data/docs/routing/custom_rules.md +16 -0
  153. data/docs/routing/filetypes_rules.md +21 -0
  154. data/docs/routing/host_rules.md +24 -0
  155. data/docs/routing/path_rules.md +33 -0
  156. data/docs/routing/protocol_rules.md +17 -0
  157. data/docs/routing/query_rules.md +69 -0
  158. data/docs/routing/routes.md +96 -0
  159. data/docs/routing/uri_rules.md +18 -0
  160. data/examples/collect_github_issues.rb +65 -0
  161. data/examples/find_foobar_on_wikipedia.rb +23 -0
  162. data/lib/wayfarer/configuration.rb +86 -0
  163. data/lib/wayfarer/crawl.rb +79 -0
  164. data/lib/wayfarer/crawl_observer.rb +103 -0
  165. data/lib/wayfarer/dispatcher.rb +104 -0
  166. data/lib/wayfarer/finders.rb +61 -0
  167. data/lib/wayfarer/frontiers/frontier.rb +79 -0
  168. data/lib/wayfarer/frontiers/memory_bloomfilter.rb +32 -0
  169. data/lib/wayfarer/frontiers/memory_frontier.rb +76 -0
  170. data/lib/wayfarer/frontiers/memory_trie_frontier.rb +39 -0
  171. data/lib/wayfarer/frontiers/normalize_uris.rb +48 -0
  172. data/lib/wayfarer/frontiers/redis_bloomfilter.rb +34 -0
  173. data/lib/wayfarer/frontiers/redis_frontier.rb +83 -0
  174. data/lib/wayfarer/http_adapters/adapter_pool.rb +62 -0
  175. data/lib/wayfarer/http_adapters/net_http_adapter.rb +77 -0
  176. data/lib/wayfarer/http_adapters/selenium_adapter.rb +80 -0
  177. data/lib/wayfarer/job.rb +211 -0
  178. data/lib/wayfarer/locals.rb +40 -0
  179. data/lib/wayfarer/page.rb +94 -0
  180. data/lib/wayfarer/parsers/json_parser.rb +20 -0
  181. data/lib/wayfarer/parsers/xml_parser.rb +27 -0
  182. data/lib/wayfarer/processor.rb +103 -0
  183. data/lib/wayfarer/routing/custom_rule.rb +21 -0
  184. data/lib/wayfarer/routing/filetypes_rule.rb +20 -0
  185. data/lib/wayfarer/routing/host_rule.rb +19 -0
  186. data/lib/wayfarer/routing/path_rule.rb +54 -0
  187. data/lib/wayfarer/routing/protocol_rule.rb +21 -0
  188. data/lib/wayfarer/routing/query_rule.rb +59 -0
  189. data/lib/wayfarer/routing/router.rb +71 -0
  190. data/lib/wayfarer/routing/rule.rb +114 -0
  191. data/lib/wayfarer/routing/uri_rule.rb +21 -0
  192. data/lib/wayfarer.rb +68 -0
  193. data/spec/configuration_spec.rb +26 -0
  194. data/spec/crawl_spec.rb +48 -0
  195. data/spec/finders_spec.rb +49 -0
  196. data/spec/frontiers/memory_bloomfilter_spec.rb +6 -0
  197. data/spec/frontiers/memory_frontier_spec.rb +6 -0
  198. data/spec/frontiers/memory_trie_frontier_spec.rb +6 -0
  199. data/spec/frontiers/normalize_uris_spec.rb +59 -0
  200. data/spec/frontiers/redis_bloomfilter_spec.rb +6 -0
  201. data/spec/frontiers/redis_frontier_spec.rb +6 -0
  202. data/spec/http_adapters/adapter_pool_spec.rb +33 -0
  203. data/spec/http_adapters/net_http_adapter_spec.rb +83 -0
  204. data/spec/http_adapters/selenium_adapter_spec.rb +53 -0
  205. data/spec/integration/callbacks_spec.rb +42 -0
  206. data/spec/integration/locals_spec.rb +106 -0
  207. data/spec/integration/peeking_spec.rb +61 -0
  208. data/spec/job_spec.rb +122 -0
  209. data/spec/page_spec.rb +38 -0
  210. data/spec/parsers/json_parser_spec.rb +30 -0
  211. data/spec/parsers/xml_parser_spec.rb +24 -0
  212. data/spec/processor_spec.rb +31 -0
  213. data/spec/routing/custom_rule_spec.rb +26 -0
  214. data/spec/routing/filetypes_rule_spec.rb +40 -0
  215. data/spec/routing/host_rule_spec.rb +48 -0
  216. data/spec/routing/path_rule_spec.rb +66 -0
  217. data/spec/routing/protocol_rule_spec.rb +26 -0
  218. data/spec/routing/query_rule_spec.rb +124 -0
  219. data/spec/routing/router_spec.rb +67 -0
  220. data/spec/routing/rule_spec.rb +251 -0
  221. data/spec/routing/uri_rule_spec.rb +24 -0
  222. data/spec/shared/frontier.rb +96 -0
  223. data/spec/spec_helpers.rb +62 -0
  224. data/spec/wayfarer_spec.rb +24 -0
  225. data/support/static/finders.html +38 -0
  226. data/support/static/graph/details/a.html +10 -0
  227. data/support/static/graph/details/b.html +10 -0
  228. data/support/static/graph/index.html +20 -0
  229. data/support/static/json/dummy.json +13 -0
  230. data/support/static/links/links.html +28 -0
  231. data/support/static/xml/dummy.xml +120 -0
  232. data/support/test_app.rb +45 -0
  233. data/wayfarer-jruby.gemspec +49 -0
  234. data/wayfarer.gemspec +53 -0
  235. metadata +697 -0
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::HTTPAdapters::SeleniumAdapter, selenium: true do
5
+ subject(:adapter) { Wayfarer::HTTPAdapters::SeleniumAdapter.new }
6
+ after { adapter.free }
7
+
8
+ describe "#fetch" do
9
+ it "returns a Page" do
10
+ uri = URI("http://0.0.0.0:9876/hello_world")
11
+ page = adapter.fetch(uri)
12
+ expect(page).to be_a Page
13
+ end
14
+
15
+ it "sets the correct URI" do
16
+ uri = URI("http://0.0.0.0:9876/status_code/404")
17
+ page = adapter.fetch(uri)
18
+ expect(page.uri.to_s).to eq "http://0.0.0.0:9876/status_code/404"
19
+ end
20
+
21
+ it "retrieves the correct HTTP status code" do
22
+ uri = URI("http://0.0.0.0:9876/status_code/404")
23
+ page = adapter.fetch(uri)
24
+ expect(page.status_code).to be 404
25
+ end
26
+
27
+ it "retrieves the correct response body" do
28
+ uri = URI("http://0.0.0.0:9876/hello_world")
29
+ page = adapter.fetch(uri)
30
+ expect(page.body).to match /Hello world!/
31
+ end
32
+
33
+ it "retrieves the correct response headers" do
34
+ uri = test_app("/hello_world")
35
+ page = adapter.fetch(uri)
36
+ expect(page.headers["hello"]).to eq ["world"]
37
+ end
38
+
39
+ context "when response is a redirect" do
40
+ it "follows the redirect" do
41
+ uri = test_app("/redirect?times=3")
42
+ page = adapter.fetch(uri)
43
+ expect(page.uri.to_s).to eq test_app("/redirect?times=0").to_s
44
+ end
45
+
46
+ context "when encountering a redirect loop" do
47
+ it "returns `nil` as HTTP status code" do
48
+ pending; fail
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer, integration: true do
5
+ describe "Callbacks" do
6
+ subject(:job) do
7
+ Class.new(Wayfarer::Job) do
8
+ config.reraise_exceptions = true
9
+ end
10
+ end
11
+
12
+ describe "ActiveJob-inherited callbacks" do
13
+ they "fire" do
14
+ job.class_eval do
15
+ before_perform { fail }
16
+ end
17
+
18
+ expect {
19
+ job.perform_now
20
+ }.to raise_error
21
+ end
22
+ end
23
+
24
+ describe "Own callbacks" do
25
+ describe "::before_crawl" do
26
+ it "fires" do
27
+ job.class_eval { before_crawl { fail } }
28
+
29
+ expect { job.perform_now }.to raise_error
30
+ end
31
+ end
32
+
33
+ describe "::after_crawl" do
34
+ it "fires" do
35
+ job.class_eval { after_crawl { fail } }
36
+
37
+ expect { job.perform_now }.to raise_error
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer, integration: true do
5
+ describe "Locals" do
6
+ subject(:job) do
7
+ Class.new(Wayfarer::Job) do
8
+ config.reraise_exceptions = true
9
+ end
10
+ end
11
+
12
+ describe "Initial local values" do
13
+ let(:entry) { test_app("/hello_world") }
14
+
15
+ they "do not change" do
16
+ job.class_eval do
17
+ route.path "/hello_world", to: :foobar
18
+
19
+ let(:foo) { {} }
20
+
21
+ def foobar
22
+ foo[:bar] = :qux
23
+ end
24
+ end
25
+
26
+ expect {
27
+ job.perform_now(entry)
28
+ }.not_to change { job.locals[:foo] }
29
+ end
30
+
31
+ context "when declared with ::let" do
32
+ they "get replaced with thread-safe counterparts" do
33
+ job.class_eval do
34
+ route.path "/hello_world", to: :foobar
35
+
36
+ let(:hash) { {} }
37
+ let(:array) { [] }
38
+ let(:fixnum) { 123 }
39
+ let(:tru) { true }
40
+ let(:fuls) { false }
41
+
42
+ def foobar
43
+ fail unless hash.is_a? Concurrent::Hash
44
+ fail unless array.is_a? Concurrent::Array
45
+ fail unless fixnum.is_a? Concurrent::AtomicFixnum
46
+ fail unless tru.is_a? Concurrent::AtomicBoolean
47
+ fail unless fuls.is_a? Concurrent::AtomicBoolean
48
+ end
49
+ end
50
+
51
+ expect {
52
+ job.perform_now(entry)
53
+ }.not_to raise_error
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "Locals" do
59
+ let(:entry) { test_app("/graph/index.html") }
60
+
61
+ they "can be mutated within actions" do
62
+ job.class_eval do
63
+ route.path "/graph/index.html", to: :index
64
+ route.path "/graph/details/a.html", to: :detail
65
+
66
+ let(:hash) { {} }
67
+
68
+ def index
69
+ hash[:foo] = 42
70
+ stage page.links
71
+ end
72
+
73
+ def detail
74
+ fail unless hash[:foo] == 42
75
+ end
76
+ end
77
+
78
+ expect {
79
+ job.perform_now(entry)
80
+ }.not_to raise_error
81
+ end
82
+
83
+ they "are accessible within callbacks" do
84
+ job.class_eval do
85
+ route.path "/graph/index.html", to: :index
86
+
87
+ let(:hash) { { foo: :bar} }
88
+
89
+ before_crawl do
90
+ fail unless hash[:foo] == :bar
91
+ end
92
+
93
+ after_crawl do
94
+ fail unless hash[:foo] == :qux
95
+ end
96
+
97
+ def index
98
+ hash[:foo] = :qux
99
+ end
100
+ end
101
+
102
+ expect { job.perform_now(entry) }.not_to raise_error
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer, integration: true do
5
+ subject(:job) do
6
+ Class.new(Wayfarer::Job) do
7
+ config.reraise_exceptions = true
8
+ end
9
+ end
10
+
11
+ let(:entry) { test_app("/graph/index.html") }
12
+
13
+ describe "Peeking" do
14
+ it "works" do
15
+ job.class_eval do
16
+ route.path "/graph/index.html", to: :index
17
+ route.path "/graph/details/a.html", to: :detail
18
+
19
+ def index
20
+ peek = yield "http://localhost:9876/graph/details/a.html"
21
+ fail unless peek == :ok
22
+ end
23
+
24
+ def detail
25
+ :ok
26
+ end
27
+ end
28
+
29
+ expect {
30
+ job.perform_now(entry)
31
+ }.not_to raise_error
32
+ end
33
+ end
34
+
35
+ describe "Recursive peeking" do
36
+ it "does not work" do
37
+ job.class_eval do
38
+ route.path "/graph/index.html", to: :index
39
+ route.path "/graph/details/a.html", to: :a
40
+ route.path "/graph/details/a.html", to: :b
41
+
42
+ def index
43
+ peek = yield "http://localhost:9876/graph/details/a.html"
44
+ fail unless peek == :ok
45
+ end
46
+
47
+ def a
48
+ yield "http://localhost:9876/graph/details/b.html" or :ok
49
+ end
50
+
51
+ def b
52
+ yield "http://localhost:9876/graph/details/a.html"
53
+ end
54
+ end
55
+
56
+ expect {
57
+ job.perform_now(entry)
58
+ }.not_to raise_error
59
+ end
60
+ end
61
+ end
data/spec/job_spec.rb ADDED
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Job do
5
+ subject(:job) { Class.new(Wayfarer::Job) }
6
+
7
+ describe "::prepare" do
8
+ it "copies the router" do
9
+ job.class_eval do
10
+ route.host "example.com", to: :foobar
11
+ end
12
+
13
+ prepared_job = job.prepare
14
+
15
+ expect(prepared_job.router).not_to be job.router
16
+
17
+ uri = URI("http://example.com")
18
+ expect(prepared_job.router.routes?(uri)).to be true
19
+ end
20
+
21
+ it "copies locals" do
22
+ job.class_eval do
23
+ let(:foo) { { bar: :qux } }
24
+ let(:baz) { 42 }
25
+ end
26
+
27
+ prepared_job = job.prepare
28
+
29
+ expect(prepared_job.locals).not_to be job.locals
30
+
31
+ expect(prepared_job.locals[:foo]).to be_a Concurrent::Hash
32
+ expect(prepared_job.locals[:baz]).to be_a Concurrent::AtomicFixnum
33
+ end
34
+
35
+ it "defines instance accessors for locals" do
36
+ job.class_eval do
37
+ let(:foo) { { bar: :qux } }
38
+ let(:baz) { 42 }
39
+ end
40
+
41
+ prepared_job = job.prepare
42
+
43
+ expect(prepared_job).to respond_to(:foo)
44
+ expect(prepared_job).to respond_to(:baz)
45
+ end
46
+ end
47
+
48
+ describe "::config" do
49
+ it "allows manipulating the configuration" do
50
+ expect {
51
+ job.config { |c| c.http_adapter = :selenium }
52
+ }.to change { job.config.http_adapter }.to(:selenium)
53
+ end
54
+
55
+ it "does not manipulate the global configuration" do
56
+ expect {
57
+ job.config { |c| c.http_adapter = :selenium }
58
+ }.not_to change { Wayfarer.config.http_adapter }
59
+ end
60
+ end
61
+
62
+ describe "#halt" do
63
+ it "sets the halting flag" do
64
+ job_instance = job.new
65
+
66
+ expect {
67
+ job_instance.send(:halt)
68
+ }.to change { job_instance.halts? }.from(false).to(true)
69
+ end
70
+ end
71
+
72
+ describe "#stage" do
73
+ it "stages URIs" do
74
+ job_instance = job.new
75
+ job_instance.page = Page.new(uri: URI("https://yahoo.com/qux"))
76
+
77
+ uris = %w(
78
+ http://google.com
79
+ http://example.com
80
+ )
81
+
82
+ expected = uris.map { |u| URI(u) }
83
+
84
+ expect {
85
+ job_instance.send(:stage, *uris)
86
+ }.to change { job_instance.staged_uris }.from([]).to(expected)
87
+ end
88
+
89
+ it "expands relative URIs" do
90
+ job_instance = job.new
91
+ job_instance.page = Page.new(uri: URI("https://yahoo.com/qux"))
92
+
93
+ uris = %w(
94
+ /foo/bar
95
+ bar/qux.html
96
+ barfoo
97
+ )
98
+
99
+ expected = %w(
100
+ https://yahoo.com/qux/foo/bar
101
+ https://yahoo.com/qux/bar/qux.html
102
+ https://yahoo.com/qux/barfoo
103
+ ).map { |u| URI(u) }
104
+
105
+ expect {
106
+ job_instance.send(:stage, *uris)
107
+ }.to change { job_instance.staged_uris }.from([]).to(expected)
108
+ end
109
+
110
+ context "with non-HTTP(s) URIs" do
111
+ it "ignores them and does not raise an exception" do
112
+ job_instance = job.new
113
+
114
+ expect {
115
+ job_instance.send(:stage, "ftp://example.com")
116
+ }.not_to raise_error
117
+
118
+ expect(job_instance.staged_uris).to be_empty
119
+ end
120
+ end
121
+ end
122
+ end
data/spec/page_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Page do
5
+ subject(:page) { fetch_page(test_app("/links/links.html")) }
6
+
7
+ describe "#doc" do
8
+ context "when Content-Type is HTML" do
9
+ it "returns a Nokogiri::HTML::Document" do
10
+ expect(page.doc).to be_a Nokogiri::HTML::Document
11
+ end
12
+ end
13
+
14
+ context "when Content-Type is XML" do
15
+ subject(:page) { fetch_page(test_app("/xml/dummy.xml")) }
16
+
17
+ it "returns a Nokogiri::XML::Document" do
18
+ expect(page.doc).to be_a Nokogiri::XML::Document
19
+ end
20
+ end
21
+
22
+ context "when Content-Type is JSON" do
23
+ subject(:page) { fetch_page(test_app("/json/dummy.json")) }
24
+
25
+ it "returns a Hash" do
26
+ expect(page.doc).to be_a Hash
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "Forwarding" do
32
+ it "forwards calls to Pismo", mri_only: true do
33
+ Pismo::Document::ATTRIBUTE_METHODS.each do |method|
34
+ expect(page).to respond_to(method)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Parsers::JSONParser do
5
+ subject(:parser) { Parsers::JSONParser }
6
+
7
+ describe ".parse" do
8
+ it "returns a Hash" do
9
+ json_str = <<-json
10
+ {
11
+ "id": 1,
12
+ "name": "Foo",
13
+ "price": 123,
14
+ "tags": [
15
+ "Bar",
16
+ "Eek"
17
+ ],
18
+ "stock": {
19
+ "warehouse": 300,
20
+ "retail": 20
21
+ }
22
+ }
23
+ json
24
+
25
+ doc = parser.parse(json_str)
26
+
27
+ expect(doc).to be_a Hash
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Parsers::XMLParser do
5
+ subject(:parser) { Parsers::XMLParser }
6
+
7
+ describe ".parse_html" do
8
+ it "returns a Nokogiri::HTML::Document" do
9
+ html_str = "<span>Foobar</span>"
10
+ doc = parser.parse_html(html_str)
11
+
12
+ expect(doc).to be_a Nokogiri::HTML::Document
13
+ end
14
+ end
15
+
16
+ describe ".parse_xml" do
17
+ it "returns a Nokogiri::XML::Document" do
18
+ xml_str = "<barqux>Foobar</barqux>"
19
+ doc = parser.parse_xml(xml_str)
20
+
21
+ expect(doc).to be_a Nokogiri::XML::Document
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Processor do
5
+ let(:job) { Class.new(Wayfarer::Job) }
6
+ let(:frontier) { Frontiers::MemoryFrontier.new(job.config) }
7
+ let(:dispatcher) { Dispatcher.new(job) }
8
+ subject(:processor) { Processor.new(job, frontier, dispatcher) }
9
+
10
+ describe "#halt!" do
11
+ it "sets a halting flag" do
12
+ processor.halt!
13
+ expect(processor).to be_halted
14
+ end
15
+ end
16
+
17
+ describe "#halted?" do
18
+ context "when not halted" do
19
+ it "returns false" do
20
+ expect(processor.halted?).to be false
21
+ end
22
+ end
23
+
24
+ context "when halted" do
25
+ it "returns true" do
26
+ processor.halt!
27
+ expect(processor.halted?).to be true
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::CustomRule do
5
+ let(:uri) { URI("http://example.com") }
6
+
7
+ describe "#matches?" do
8
+ context "with a block" do
9
+ context "when block is truthy" do
10
+ subject(:rule) { CustomRule.new -> (uri) { uri.is_a?(URI) } }
11
+
12
+ it "returns true" do
13
+ expect(rule.matches?(uri)).to be true
14
+ end
15
+ end
16
+
17
+ context "when block is fals-y" do
18
+ subject(:rule) { CustomRule.new -> (_) { false } }
19
+
20
+ it "returns true" do
21
+ expect(rule.matches?(uri)).to be false
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::FiletypesRule do
5
+ subject(:rule) { FiletypesRule.new([:png, :js]) }
6
+
7
+ describe "#matches?" do
8
+ context "with matching URI" do
9
+ it "returns true" do
10
+ uris = %w(
11
+ http://example.com/foo.png
12
+ https://example.com/a/b.png/c.png
13
+ http://example.com/foobar.html.png
14
+ https://example.com/foo.png/bar.png
15
+ ).map { |u| URI(u) }
16
+
17
+ uris.each do |uri|
18
+ expect(rule.matches?(uri)).to be true
19
+ end
20
+ end
21
+ end
22
+
23
+ context "with mismatching URI" do
24
+ it "returns false" do
25
+ uris = %w(
26
+ http://example.png
27
+ http://example.com.png
28
+ https://example.com/a/b.png/c
29
+ http://example.com.html
30
+ http://example.com/foobar.html
31
+ https://example.com/foo.png/bar.png.html
32
+ ).map { |u| URI(u) }
33
+
34
+ uris.each do |uri|
35
+ expect(rule.matches?(uri)).to be false
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::HostRule do
5
+ subject(:rule) { HostRule.new(str_or_regexp) }
6
+
7
+ describe "#matches?" do
8
+ describe "String matching" do
9
+ let(:str_or_regexp) { "example.com" }
10
+
11
+ context "with matching URI" do
12
+ let(:uri) { URI("http://example.com/foo/bar") }
13
+
14
+ it "returns true" do
15
+ expect(rule.matches?(uri)).to be true
16
+ end
17
+ end
18
+
19
+ context "with mismatching URI" do
20
+ let(:uri) { URI("http://google.com/bar/qux") }
21
+
22
+ it "returns false" do
23
+ expect(rule.matches?(uri)).to be false
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "RegExp matching" do
29
+ let(:str_or_regexp) { /example.com/ }
30
+
31
+ context "with matching URI" do
32
+ let(:uri) { URI("http://sub.example.com") }
33
+
34
+ it "returns true" do
35
+ expect(rule.matches?(uri)).to be true
36
+ end
37
+ end
38
+
39
+ context "with mismatching URI" do
40
+ let(:uri) { URI("http://example.sub.com") }
41
+
42
+ it "returns false" do
43
+ expect(rule.matches?(uri)).to be false
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helpers"
3
+
4
+ describe Wayfarer::Routing::PathRule, mri: true do
5
+ describe "#matches?" do
6
+ context "with a string" do
7
+ subject(:rule) { PathRule.new("/{alpha}/{beta}") }
8
+
9
+ context "with matching URI" do
10
+ let(:uri) { URI("http://example.com/foo/bar") }
11
+
12
+ it "returns true" do
13
+ expect(rule.matches?(uri)).to be true
14
+ end
15
+ end
16
+
17
+ context "with mismatching URI" do
18
+ let(:uri) { URI("http://example.com/foo") }
19
+
20
+ it "returns false" do
21
+ expect(rule.matches?(uri)).to be false
22
+ end
23
+ end
24
+ end
25
+
26
+ context "with a RegExp" do
27
+ subject(:rule) { PathRule.new(/\/(\w+)\/(\w+)/) }
28
+
29
+ context "with matching URI" do
30
+ let(:uri) { URI("http://example.com/foo/bar") }
31
+
32
+ it "returns true" do
33
+ expect(rule.matches?(uri)).to be true
34
+ end
35
+ end
36
+
37
+ context "with mismatching URI" do
38
+ let(:uri) { URI("http://example.com/foo") }
39
+
40
+ it "returns false" do
41
+ expect(rule.matches?(uri)).to be false
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "#params" do
48
+ context "with a string" do
49
+ subject(:rule) { PathRule.new("/{alpha}/{beta}") }
50
+
51
+ it "returns the correct parameters" do
52
+ uri = URI("http://example.com/foo/bar")
53
+ expect(rule.params(uri)).to eq("alpha" => "foo", "beta" => "bar")
54
+ end
55
+ end
56
+
57
+ context "with a RegExp" do
58
+ subject(:rule) { PathRule.new(/\/(\w+)\/(\w+)/) }
59
+
60
+ it "returns the correct parameters" do
61
+ uri = URI("http://example.com/foo/bar")
62
+ expect(rule.params(uri)).to eq("0" => "foo", "1" => "bar")
63
+ end
64
+ end
65
+ end
66
+ end