webwatchr 0.0.2

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.
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/ruby
2
+ require "fileutils"
3
+ require "logger"
4
+ require_relative "../lib/webwatchr/site"
5
+ require_relative "./helpers"
6
+ require "tmpdir"
7
+ require "test/unit"
8
+
9
+ class BaseWebrickTest < Test::Unit::TestCase
10
+ require "webrick"
11
+
12
+ TEST_CONFIG = {
13
+ wwwroot: File.join(File.dirname(__FILE__), "www-root"),
14
+ wwwport: 8001,
15
+ content_is_string_file: "content_is_string.html",
16
+ content_is_array_file: "content_is_array.html"
17
+ }.freeze
18
+
19
+ class TestFileHandler < WEBrick::HTTPServlet::FileHandler
20
+ def do_GET(req, res) # rubocop:disable Metrics/MethodName
21
+ res.status = 200
22
+ res["Content-Encoding"] = "utf-8"
23
+ res["Content-Type"] = "text/html; charset=utf-8"
24
+ res.body = File.open(File.join(TEST_CONFIG[:wwwroot], req.path)).read()
25
+ end
26
+ end
27
+
28
+ def restart_webrick()
29
+ @webrick = WEBrick::HTTPServer.new(
30
+ AccessLog: [],
31
+ Logger: WEBrick::Log.new("/dev/null", 7),
32
+ Port: TEST_CONFIG[:wwwport]
33
+ )
34
+ @webrick.mount("/", TestFileHandler, TEST_CONFIG[:wwwroot])
35
+
36
+ @serv_thread = Thread.new do
37
+ @webrick.start
38
+ end
39
+ end
40
+
41
+ def setup
42
+ @workdir = Dir.mktmpdir
43
+ @logger_test_io = StringIO.new()
44
+ MyLog.instance.configure(@logger_test_io, nil, Logger::DEBUG)
45
+ restart_webrick()
46
+ end
47
+
48
+ def teardown()
49
+ @webrick.stop
50
+ @serv_thread.join
51
+ [TEST_CONFIG[:content_is_string_file], TEST_CONFIG[:content_is_array_file]].each do |tf|
52
+ File.open(File.join(TEST_CONFIG[:wwwroot], tf), "w") do |f|
53
+ f.puts ""
54
+ end
55
+ end
56
+ FileUtils.remove_entry_secure(@workdir)
57
+ end
58
+ end
59
+
60
+ class TestSimpleStringSite < BaseWebrickTest
61
+ class TestStringSite < Site::SimpleString
62
+ def initialize
63
+ super()
64
+ @wait = 3600
65
+ end
66
+
67
+ def get_content()
68
+ return ResultObject.new(@parsed_content.css("div.content").text)
69
+ end
70
+ end
71
+
72
+ def test_content_is_string
73
+ content_html = "👌 👌 👌 💯 💯 💯 💯 -KYop-R11Iqo.mp"
74
+ whole_html = Site::HTML_HEADER.dup
75
+ whole_html += "<title>test</title><div class='content'>#{content_html}</div>"
76
+ File.open(File.join(TEST_CONFIG[:wwwroot], TEST_CONFIG[:content_is_string_file]), "w") do |f|
77
+ f.write whole_html
78
+ end
79
+ url = "http://localhost:#{TEST_CONFIG[:wwwport]}/#{TEST_CONFIG[:content_is_string_file]}"
80
+ wait = 10 * 60
81
+
82
+ c = TestStringSite.new
83
+ c.url = url
84
+ a = TestAlerter.new()
85
+ c.alerters = [a]
86
+ assert { c.load_state_file() == {} }
87
+ assert { c.should_update?(-9_999_999_999_999) }
88
+ assert { c.should_update?((Time.now() - wait + 30).to_i) == false }
89
+ html = c.fetch_url(url)
90
+ assert { whole_html == html }
91
+ assert { c.parse_noko(html).css("title").text == "test" }
92
+ cache_dir = File.join(@workdir, "cache")
93
+ last_dir = File.join(@workdir, ".lasts")
94
+ FileUtils.mkdir_p(cache_dir)
95
+ FileUtils.mkdir_p(last_dir)
96
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
97
+ assert { c.state_file.end_with?("last-localhost-2182cd5c8685baed48f692ed72d7a89f") }
98
+ expected_error = "DEBUG -- TestSimpleStringSite::TestStringSite: Alerting new stuff"
99
+ last_error = @logger_test_io.string.split("\n")[-1]
100
+ assert { last_error.end_with?(expected_error) }
101
+ first_pass_content = Site::HTML_HEADER + content_html
102
+ assert { c.content.to_html == content_html }
103
+ assert { c.generate_html_content == first_pass_content }
104
+ assert { a.result == c.content }
105
+
106
+ File.open(File.join(TEST_CONFIG[:wwwroot], TEST_CONFIG[:content_is_string_file]), "w+") do |f|
107
+ f.write whole_html.gsub("</div>", " new ! </div>")
108
+ end
109
+ c = TestStringSite.new
110
+ c.url = url
111
+ cache_dir = File.join(@workdir, "cache")
112
+ last_dir = File.join(@workdir, ".lasts")
113
+ FileUtils.mkdir_p(cache_dir)
114
+ FileUtils.mkdir_p(last_dir)
115
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
116
+ c.comment = "lol"
117
+ expected_error = "INFO -- TestSimpleStringSite::TestStringSite: Too soon to update #{url}"
118
+ last_error = @logger_test_io.string.split("\n")[-1]
119
+ assert { last_error.end_with?(expected_error) }
120
+ assert { c.content.nil? }
121
+ assert { c.generate_html_content.nil? }
122
+ assert { c.name == url }
123
+
124
+ c.every = 0
125
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
126
+ expected_error = "DEBUG -- TestSimpleStringSite::TestStringSite: Alerting new stuff"
127
+ last_error = @logger_test_io.string.split("\n")[-1]
128
+ assert { last_error.end_with?(expected_error) }
129
+ assert { c.content.to_html == "#{content_html} new ! " }
130
+ assert { c.generate_html_content == "#{first_pass_content} new ! " }
131
+ assert { c.name == url }
132
+ result_last = JSON.parse(File.read(c.state_file), create_additions: true)
133
+ result_last.delete("time")
134
+ assert { result_last["url"] == url }
135
+ assert { result_last["content"].message == "#{content_html} new ! " }
136
+ assert { result_last["wait"] == 0 }
137
+ end
138
+ end
139
+
140
+ class TestArraySites < BaseWebrickTest
141
+ class TestArraySite < Site::Articles
142
+ def initialize
143
+ super()
144
+ @wait = 3600
145
+ end
146
+
147
+ def get_content()
148
+ res = []
149
+ @parsed_content.css("div").each do |x|
150
+ a, b = x.text.split("-").map(&:strip)
151
+ add_article({ "id" => a, "url" => a, "title" => b })
152
+ end
153
+ return res
154
+ end
155
+ end
156
+
157
+ def test_content_is_array
158
+ whole_html = "#{Site::HTML_HEADER.dup}<title>test</title>👌 👌 👌 💯 💯 💯 💯 -KYop-R11Iqo.mp4<div> lol - lilo</div> <div> fi - fu</div>"
159
+ File.open(File.join(TEST_CONFIG[:wwwroot], TEST_CONFIG[:content_is_array_file]), "w") do |f|
160
+ f.write whole_html
161
+ end
162
+ url = "http://localhost:#{TEST_CONFIG[:wwwport]}/#{TEST_CONFIG[:content_is_array_file]}"
163
+ wait = 10 * 60
164
+
165
+ c = TestArraySite.new
166
+ c.url = url
167
+ a = TestAlerter.new()
168
+ c.alerters = [a]
169
+ assert { c.load_state_file() == {} }
170
+ assert { c.should_update?(-9_999_999_999_999) }
171
+ assert { !c.should_update?((Time.now() - wait + 30).to_i) }
172
+ html = c.fetch_url(url)
173
+ assert { html == whole_html }
174
+ assert { c.parse_noko(html).css("title").text == "test" }
175
+
176
+ # First full run, Get 2 things
177
+ cache_dir = File.join(@workdir, "cache")
178
+ last_dir = File.join(@workdir, ".lasts")
179
+ FileUtils.mkdir_p(cache_dir)
180
+ FileUtils.mkdir_p(last_dir)
181
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
182
+ assert { c.state_file.end_with?("last-localhost-35e711989b197f20f3d4936e91a2c079") }
183
+ expected_error = "DEBUG -- TestArraySites::TestArraySite: Alerting new stuff"
184
+ last_error = @logger_test_io.string.split("\n")[-1].strip()
185
+ assert { last_error.end_with?(expected_error) }
186
+ expected_html = Site::HTML_HEADER.dup + [
187
+ "<ul style='list-style-type: none;'>",
188
+ "<li id='lol'><a href='lol'>lilo</a></li>",
189
+ "<li id='fi'><a href='fi'>fu</a></li>",
190
+ "</ul>"
191
+ ].join("\n")
192
+ c.content.each { |x| x.delete('_timestamp') }
193
+ assert {
194
+ c.content == [
195
+ { "id" => "lol", "url" => "lol", "title" => "lilo" },
196
+ { "id" => "fi", "url" => "fi", "title" => "fu" }
197
+ ]
198
+ }
199
+ assert { c.generate_html_content == expected_html }
200
+
201
+ result = ""
202
+
203
+ File.open(File.join(TEST_CONFIG[:wwwroot], TEST_CONFIG[:content_is_array_file]), "a+") do |f|
204
+ f.write "<div>new! - new </div>"
205
+ end
206
+ c = TestArraySite.new
207
+ c.url = url
208
+ a = TestAlerter.new()
209
+ c.alerters = [a]
210
+ # Second run don't d anything because we shouldn't rerun
211
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
212
+ expected_error = "INFO -- TestArraySites::TestArraySite: Too soon to update #{url}"
213
+ last_error = @logger_test_io.string.split("\n")[-1]
214
+ assert { last_error.end_with?(expected_error) }
215
+ assert { result == "" }
216
+
217
+ result = ""
218
+
219
+ c.content.each { |x| x.delete('_timestamp') }
220
+
221
+ c.every = 0
222
+ # This time we set new things, and wait is 0 so we are good to go
223
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
224
+ expected_error = "DEBUG -- TestArraySites::TestArraySite: Alerting new stuff"
225
+ last_error = @logger_test_io.string.split("\n")[-1]
226
+ assert { last_error.end_with?(expected_error) }
227
+ expected_html = Site::HTML_HEADER.dup + [
228
+ "<ul style='list-style-type: none;'>",
229
+ "<li id='new!'><a href='new!'>new</a></li>",
230
+ "</ul>"
231
+ ].join("\n")
232
+
233
+ c.content.each { |x| x.delete('_timestamp') }
234
+ assert { c.content == [{ "id" => "new!", "url" => "new!", "title" => "new" }] }
235
+ assert { c.generate_html_content == expected_html }
236
+ expected_last = { "url" => "http://localhost:#{TEST_CONFIG[:wwwport]}/#{TEST_CONFIG[:content_is_array_file]}",
237
+ "previous_content" => [{ "id" => "lol", "url" => "lol", "title" => "lilo" },
238
+ { "id" => "fi", "url" => "fi", "title" => "fu" }],
239
+ "wait" => 0,
240
+ "content" => [{ "id" => "lol", "title" => "lilo", "url" => "lol" },
241
+ { "id" => "fi", "title" => "fu", "url" => "fi" },
242
+ { "id" => "new!", "title" => "new", "url" => "new!" }] }
243
+ result_last = JSON.parse(File.read(c.state_file))
244
+ result_last.delete("time")
245
+ result_last["content"].each do |item|
246
+ item.delete("_timestamp")
247
+ end
248
+ result_last["previous_content"].each do |item|
249
+ item.delete("_timestamp")
250
+ end
251
+ assert { expected_last == result_last }
252
+
253
+ result = ""
254
+
255
+ c = TestArraySite.new
256
+ c.url = url
257
+ a = TestAlerter.new()
258
+ c.alerters = [a]
259
+ c.every = 0
260
+ # Now, we don't call the alert Proc because we have no new things
261
+ c.update(cache_dir: cache_dir, last_dir: last_dir)
262
+ expected_error = "INFO -- TestArraySites::TestArraySite: Nothing new for #{url}"
263
+ last_error = @logger_test_io.string.split("\n")[-1]
264
+ assert { last_error.end_with?(expected_error) }
265
+ expected_html = Site::HTML_HEADER.dup + [
266
+ "<ul style=\"list-style-type: none;\">",
267
+ "</ul>"
268
+ ].join("\n")
269
+ assert { result == "" }
270
+ end
271
+ end
data/webwatchr.gemspec ADDED
@@ -0,0 +1,12 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "webwatchr"
3
+ s.version = "0.0.2"
4
+ s.summary = "Scrapes stuff and tells you of updates."
5
+ s.description = "Scrapes stuff and tells you of updates. Exciting!"
6
+ s.authors = ["Renzo"]
7
+ s.email = "webwatchr-gem@renzokuken.eu"
8
+ s.files = Dir['README.md', 'tests/**.*', 'lib/**/*', 'Rakefile', 'Gemfile', 'LICENSE', 'webwatchr.gemspec']
9
+ s.homepage = "https://github.com/conchyliculture/webwatchr"
10
+ s.license = "GPL-3.0-or-later"
11
+ s.required_ruby_version = ">=2.5.0"
12
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: webwatchr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Renzo
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Scrapes stuff and tells you of updates. Exciting!
13
+ email: webwatchr-gem@renzokuken.eu
14
+ executables: []
15
+ extensions: []
16
+ extra_rdoc_files: []
17
+ files:
18
+ - Gemfile
19
+ - LICENSE
20
+ - README.md
21
+ - Rakefile
22
+ - lib/sites/bandcamp.rb
23
+ - lib/sites/bsky.rb
24
+ - lib/sites/postch.rb
25
+ - lib/sites/songkick.rb
26
+ - lib/webwatchr.rb
27
+ - lib/webwatchr/alerting.rb
28
+ - lib/webwatchr/base.rb
29
+ - lib/webwatchr/logger.rb
30
+ - lib/webwatchr/main.rb
31
+ - lib/webwatchr/site.rb
32
+ - tests/helpers.rb
33
+ - tests/infra_test.rb
34
+ - webwatchr.gemspec
35
+ homepage: https://github.com/conchyliculture/webwatchr
36
+ licenses:
37
+ - GPL-3.0-or-later
38
+ metadata: {}
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 2.5.0
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubygems_version: 3.6.7
54
+ specification_version: 4
55
+ summary: Scrapes stuff and tells you of updates.
56
+ test_files: []