watchdoge 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/lib/watchdoge/configuration.rb +28 -0
- data/lib/watchdoge/cookie_pool.rb +25 -0
- data/lib/watchdoge/image_diff.rb +32 -0
- data/lib/watchdoge/install.rb +15 -0
- data/lib/watchdoge/notification/slack.rb +40 -0
- data/lib/watchdoge/notification.rb +28 -0
- data/lib/watchdoge/version.rb +3 -0
- data/lib/watchdoge/worker.rb +118 -0
- data/lib/watchdoge.rb +25 -0
- data/watchdoge.gemspec +19 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dc87007d94c7fcac5e1eafccc71c3aae806adf2b3e7448a1f65e126bb10e049b
|
4
|
+
data.tar.gz: 1e194cbde4a75ecd82f365bff1be0e736c07b92e5555491e32ab20bda7a1412a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e27a802f2ea1a8b79d7ddf9638f3af28bacc90cbdf9a060d48e42c646ff334aae9431e0b898ef6c23d8311db2af06826edff0b321f393f3d652f8d4927cd639a
|
7
|
+
data.tar.gz: 50bd1bc2d8c3e21deb6e8bb112d2c1f68f3d518017d55be020617fd938dae623a41b99b89f46f0a55cec83e24b7d40783303a50d5a2cd71b155ecbde718c26aa
|
data/.gitignore
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'watir'
|
2
|
+
|
3
|
+
module WatchDoge
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :base_dir
|
6
|
+
attr_accessor :web_drivers_dir
|
7
|
+
attr_accessor :engine
|
8
|
+
attr_accessor :cookie_pool
|
9
|
+
attr_accessor :notifications
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@base_dir = File.expand_path(File.dirname(__FILE__) + '/..')
|
13
|
+
|
14
|
+
@web_drivers_dir = @base_dir + "/.webdrivers"
|
15
|
+
|
16
|
+
# cuurently using local fs, probably support NoSQL also maybe?
|
17
|
+
@cookie_pool = @base_dir + '/.doge_cookie'
|
18
|
+
|
19
|
+
@engine = Watir::Browser
|
20
|
+
|
21
|
+
@notifications = {
|
22
|
+
# slack: {
|
23
|
+
# incoming_url: SLACK_WEBHOOK
|
24
|
+
# }
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module WatchDoge
|
5
|
+
module CookiePool
|
6
|
+
class << self
|
7
|
+
def source uuid, uri = nil
|
8
|
+
suffix = "_#{Digest::MD5.hexdigest(uri.to_s)[0..5]}" if uri
|
9
|
+
|
10
|
+
"#{WatchDoge.configuration.cookie_pool}/#{uuid}#{suffix}"
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO: implement these two methods return Cookie object in future.
|
14
|
+
# def save uuid, json
|
15
|
+
# File.write source(uuid), json
|
16
|
+
# end
|
17
|
+
|
18
|
+
# def load uuid
|
19
|
+
# return "" unless File.exist? source(uuid)
|
20
|
+
|
21
|
+
# JSON.parse File.read(source(uuid))
|
22
|
+
# end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module WatchDoge
|
2
|
+
module ImageDiff
|
3
|
+
OPACITY = 0.6
|
4
|
+
HIGHLIGHT_COLOR = "#F163FF#{(OPACITY * 256).to_i.to_s(16).upcase}"
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def diff input_image, golden_image
|
8
|
+
return nil if input_image.pixels.hash == golden_image.pixels.hash
|
9
|
+
|
10
|
+
input_image.height.times do |y|
|
11
|
+
pixels = input_image.row(y)
|
12
|
+
|
13
|
+
if y >= golden_image.height
|
14
|
+
pixels.each_with_index do |pixel, x|
|
15
|
+
input_image.compose_pixel(x, y, HIGHLIGHT_COLOR)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
golden_pixels = golden_image.row(y)
|
19
|
+
|
20
|
+
next if (pixels.hash == golden_pixels.hash)
|
21
|
+
|
22
|
+
pixels.each_with_index do |pixel, x|
|
23
|
+
input_image.compose_pixel(x, y, HIGHLIGHT_COLOR) if pixels[x] != golden_pixels[x]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
input_image
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'net_http_ssl_fix'
|
2
|
+
require 'webdrivers'
|
3
|
+
|
4
|
+
module WatchDoge
|
5
|
+
class << self
|
6
|
+
def install
|
7
|
+
Webdrivers.install_dir = configuration.web_drivers_dir
|
8
|
+
|
9
|
+
# TODO: Support other browser maybe?
|
10
|
+
Webdrivers::Geckodriver.update
|
11
|
+
|
12
|
+
Dir.mkdir configuration.cookie_pool unless File.directory? configuration.cookie_pool
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'chunky_png'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module WatchDoge
|
7
|
+
module Notification
|
8
|
+
class Slack
|
9
|
+
def initialize opt
|
10
|
+
@incoming_url = opt[:incoming_url]
|
11
|
+
end
|
12
|
+
|
13
|
+
def push message
|
14
|
+
body = _slack_body(message).to_json
|
15
|
+
Net::HTTP.post URI(@incoming_url),
|
16
|
+
body,
|
17
|
+
"Content-Type" => "application/json"
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def _slack_body message
|
23
|
+
case message
|
24
|
+
when String
|
25
|
+
{
|
26
|
+
text: message
|
27
|
+
}
|
28
|
+
when ChunkyPNG::Image
|
29
|
+
data = ['data:image/png;base64,', message.to_blob].pack('A*m').gsub(/\n/, '')
|
30
|
+
|
31
|
+
{
|
32
|
+
attachments: [{
|
33
|
+
image_url: data
|
34
|
+
}]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module WatchDoge
|
2
|
+
module Notification
|
3
|
+
Dir["#{File.expand_path File.dirname(__FILE__)}/notification/*.rb"].each {|file| require file }
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def push message
|
7
|
+
sources = WatchDoge.configuration.notifications
|
8
|
+
|
9
|
+
raise "can't find notification sources in configuration" if sources.empty?
|
10
|
+
|
11
|
+
sources.each do |source_sym, source_args|
|
12
|
+
source_class = get_source_class source_sym
|
13
|
+
source = source_class.new source_args
|
14
|
+
source.push message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def get_source_class source_sym
|
21
|
+
case source_sym
|
22
|
+
when :slack
|
23
|
+
WatchDoge::Notification::Slack
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module WatchDoge
|
2
|
+
module PDFUtil
|
3
|
+
def pdf_screenshot
|
4
|
+
# no such thing as on_loaded for gecko pdf-viewer
|
5
|
+
sleep 3
|
6
|
+
|
7
|
+
firefox_pdf_viewer_id = 'viewer'
|
8
|
+
firefox_scaler_id = 'scaleSelect'
|
9
|
+
scale_factor = '0.75'
|
10
|
+
|
11
|
+
#resize to 75%
|
12
|
+
@core.select({id: firefox_scaler_id}).select(scale_factor)
|
13
|
+
|
14
|
+
fullpage_screenshot({id: firefox_pdf_viewer_id})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Worker
|
19
|
+
include WatchDoge::PDFUtil
|
20
|
+
|
21
|
+
def initialize uuid, opt={}
|
22
|
+
_before_initialize
|
23
|
+
|
24
|
+
@uuid = uuid
|
25
|
+
|
26
|
+
default_opt = {
|
27
|
+
width: 1024,
|
28
|
+
height: 768,
|
29
|
+
headless: true
|
30
|
+
}.merge(opt)
|
31
|
+
|
32
|
+
@core = WatchDoge.configuration.engine.new :firefox, default_opt
|
33
|
+
|
34
|
+
# for generate uri hash
|
35
|
+
@landed_page = nil
|
36
|
+
|
37
|
+
# flag that cookie is loaded
|
38
|
+
@cookie_loaded = false
|
39
|
+
|
40
|
+
@width = default_opt[:width]
|
41
|
+
@height = default_opt[:height]
|
42
|
+
|
43
|
+
# initilize width/height
|
44
|
+
@core.window.resize_to @width, @height
|
45
|
+
|
46
|
+
_after_initialize
|
47
|
+
end
|
48
|
+
|
49
|
+
def fullpage_screenshot **kwargs
|
50
|
+
_resize_by_document(kwargs) do
|
51
|
+
return @core.screenshot
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def close
|
56
|
+
_save_cookie
|
57
|
+
@core.close
|
58
|
+
end
|
59
|
+
|
60
|
+
def goto uri
|
61
|
+
@core.goto uri
|
62
|
+
|
63
|
+
@landed_page = uri
|
64
|
+
|
65
|
+
_load_cookie unless _cookie_loaded?
|
66
|
+
|
67
|
+
@core.refresh
|
68
|
+
end
|
69
|
+
|
70
|
+
# for dev only
|
71
|
+
def core
|
72
|
+
@core
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
# callbacks before/after init
|
77
|
+
def _before_initialize
|
78
|
+
Selenium::WebDriver::Firefox::Service.driver_path = WatchDoge.configuration.web_drivers_dir + "/geckodriver"
|
79
|
+
end
|
80
|
+
def _after_initialize
|
81
|
+
end
|
82
|
+
|
83
|
+
# for cookie load/save
|
84
|
+
def _cookie_loaded?
|
85
|
+
@cookie_loaded
|
86
|
+
end
|
87
|
+
def _save_cookie
|
88
|
+
@core.cookies.save WatchDoge::CookiePool.source(@uuid, @landed_page)
|
89
|
+
end
|
90
|
+
def _load_cookie
|
91
|
+
source = WatchDoge::CookiePool.source(@uuid, @landed_page)
|
92
|
+
return unless File.exist? source
|
93
|
+
|
94
|
+
@core.cookies.load source
|
95
|
+
@cookie_loaded = true
|
96
|
+
end
|
97
|
+
|
98
|
+
def _resize_by_document **kwargs
|
99
|
+
target =
|
100
|
+
if kwargs.empty?
|
101
|
+
@core.body
|
102
|
+
else
|
103
|
+
@core.element(**kwargs)
|
104
|
+
end
|
105
|
+
|
106
|
+
@core.window.resize_to [target.width, 5000].min, [target.height, 20000].min
|
107
|
+
yield
|
108
|
+
@core.window.resize_to @width, @height
|
109
|
+
end
|
110
|
+
|
111
|
+
# try delegate all methods to @core
|
112
|
+
def method_missing(method_name, *args)
|
113
|
+
result = @core.__send__(method_name, *args)
|
114
|
+
|
115
|
+
result
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/watchdoge.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'watchdoge/install'
|
3
|
+
require 'watchdoge/version'
|
4
|
+
require 'watchdoge/configuration'
|
5
|
+
require 'watchdoge/cookie_pool'
|
6
|
+
require 'watchdoge/worker'
|
7
|
+
require 'watchdoge/notification'
|
8
|
+
require 'watchdoge/image_diff'
|
9
|
+
|
10
|
+
module WatchDoge
|
11
|
+
class << self
|
12
|
+
def base_dir
|
13
|
+
configuration.base_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure(&block)
|
17
|
+
yield(configuration)
|
18
|
+
configuration
|
19
|
+
end
|
20
|
+
|
21
|
+
def configuration
|
22
|
+
@_configuration ||= Configuration.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/watchdoge.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'watchdoge'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2019-07-22'
|
5
|
+
s.summary = "dogi"
|
6
|
+
s.description = "A collection of web test tools"
|
7
|
+
s.authors = ["Shen Lee"]
|
8
|
+
s.email = 'no-reply@gmail.com'
|
9
|
+
s.files = ["lib/watchdoge.rb"]
|
10
|
+
s.license = 'MIT'
|
11
|
+
|
12
|
+
s.files = `git ls-files`.split($/)
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
s.add_dependency "chunky_png", "~> 1.3", "> 1.3.10"
|
16
|
+
s.add_dependency "net_http_ssl_fix", "~> 0.0.10"
|
17
|
+
s.add_dependency "webdrivers", "~> 4.1", "> 4.1.0"
|
18
|
+
s.add_dependency "watir", "~> 6.16", "> 6.16.0"
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: watchdoge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shen Lee
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-07-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: chunky_png
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.10
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- - ">"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.3.10
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: net_http_ssl_fix
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.0.10
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.0.10
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: webdrivers
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 4.1.0
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '4.1'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 4.1.0
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '4.1'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: watir
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 6.16.0
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '6.16'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 6.16.0
|
84
|
+
- - "~>"
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '6.16'
|
87
|
+
description: A collection of web test tools
|
88
|
+
email: no-reply@gmail.com
|
89
|
+
executables: []
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- ".gitignore"
|
94
|
+
- lib/watchdoge.rb
|
95
|
+
- lib/watchdoge/configuration.rb
|
96
|
+
- lib/watchdoge/cookie_pool.rb
|
97
|
+
- lib/watchdoge/image_diff.rb
|
98
|
+
- lib/watchdoge/install.rb
|
99
|
+
- lib/watchdoge/notification.rb
|
100
|
+
- lib/watchdoge/notification/slack.rb
|
101
|
+
- lib/watchdoge/version.rb
|
102
|
+
- lib/watchdoge/worker.rb
|
103
|
+
- watchdoge.gemspec
|
104
|
+
homepage:
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubygems_version: 3.0.3
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: dogi
|
127
|
+
test_files: []
|