watchdoge 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31dedfc4a4c2e9534672ab388d89afeccb56e9855b5e14e9c454f9b4b0750670
4
- data.tar.gz: c91210715bedf6187b55e543ff95f82a4390457bd9a4c83026c36d1ab130175b
3
+ metadata.gz: db9eab410f530c1dd00de8bfb39a4cfaa86d3e41aa86105d776c47e8c68ad9cb
4
+ data.tar.gz: 3196f93d3121f1aaafe6a4dfea5fc702dfbe54c4a985dfdd6b4f08abc3e515af
5
5
  SHA512:
6
- metadata.gz: aead7efe871204a654be431a18eacbd5eb1b22e299f0f2eb6d941022d58826fb0cb5024623dff704758558a07a2531c6d3e825409a0f5d4c74b66b5115ee29b4
7
- data.tar.gz: e255c5c965a8a3dcaa8709a762a07127d9aa6850b3f06ecacfb67dac9accca785fd4a84e48fd53bb0988b738a27b0a29a6ca06a714f1e39dd26e3fe3201f2a00
6
+ metadata.gz: ef68aed278dc48dd7eac239a9c91bbaf532b010f4bb28f4c32ddbd3c57d3dd271a26e7c087e86bf2d7b64abe37dc73a2c51c1990e3a73882ce41f05bdbc9f2ea
7
+ data.tar.gz: a9d02b67e9534ccf26047f4eb260b738251a68a92971fa7333689220dc13e1c4b089c36b0d507c950543cc3fbeff5d7adc3beb3602c32ecb373102fa868e7197
@@ -0,0 +1,35 @@
1
+ require 'pry'
2
+ require 'net_http_ssl_fix'
3
+
4
+ require 'chunky_png'
5
+ require 'json'
6
+ require 'net/http'
7
+ require 'net/http/post/multipart'
8
+ require 'uri'
9
+
10
+ module WatchDoge
11
+ module Notification
12
+ class Base
13
+ def initialize opt
14
+ @message_queue = []
15
+ end
16
+
17
+ def push message
18
+ @message_queue << message
19
+ end
20
+
21
+ def flush
22
+ @message_queue.each do |message|
23
+ case message
24
+ when String
25
+ puts message
26
+ when ChunkyPNG::Image
27
+ File.write 'image.png', message.to_blob
28
+ when WatchDoge::PixelTest
29
+ File.write 'image.png', message.diff.to_blob
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -9,40 +9,47 @@ require 'uri'
9
9
 
10
10
  module WatchDoge
11
11
  module Notification
12
- class GitlabRepo
12
+ class GitlabRepo < WatchDoge::Notification::Base
13
13
  def initialize opt
14
+ super
15
+
14
16
  @host = opt[:host] || ENV['CI_API_V4_URL']
15
17
  @project_id = opt[:project_id] || ENV['CI_PROJECT_ID']
16
18
  @source_branch = opt[:source_branch] || ENV['CI_COMMIT_REF_NAME']
17
19
 
18
20
  @private_token = opt[:private_token]
19
-
20
- @message_queue = []
21
- end
22
-
23
- def push message
24
- @message_queue << message
25
21
  end
26
22
 
27
23
  def flush
28
- @message_queue.each do |message|
29
- iid = get_latest_request_iid
30
-
31
- return if iid.nil?
32
-
33
- case message
34
- when String
35
- post_discussion request_iid: iid, message: message
36
- when ChunkyPNG::Image
37
- image_blob = message.to_blob
38
- res = upload_image image_blob
39
- image_link = "![image](#{ENV['CI_PROJECT_URL']}#{res['url']})"
40
- post_discussion request_iid: iid, message: image_link
41
-
42
- # TODO: should add WatchDoge::Diff as pair of before/after iamges
43
- # when WatchDoge::Diff
24
+ iid = get_latest_request_iid
25
+
26
+ @message_queue = [] if iid.nil?
27
+
28
+ table = markdown_table do |table_context|
29
+ @message_queue.each do |message|
30
+ case message
31
+ when String
32
+ post_discussion request_iid: iid, message: message
33
+ when ChunkyPNG::Image
34
+ upload_link = upload_image message
35
+ link = md_img_link upload_link
36
+
37
+ post_discussion request_iid: iid, message: link
38
+ when WatchDoge::PixelTest
39
+ before = md_img_link upload_image(message.before)
40
+ after = md_img_link upload_image(message.after)
41
+ diff = md_img_link upload_image(message.diff)
42
+
43
+ table_context << markdown_table_row(before, after, diff)
44
+ end
44
45
  end
46
+
47
+ table_context
45
48
  end
49
+
50
+ @message_queue = []
51
+
52
+ post_discussion request_iid: iid, message: table
46
53
  end
47
54
 
48
55
  def post_discussion request_iid:, message:
@@ -54,11 +61,11 @@ module WatchDoge
54
61
  "PRIVATE-TOKEN": @private_token
55
62
  end
56
63
 
57
- def upload_image blob
64
+ def upload_image image
58
65
  uri = project_uri "/uploads"
59
66
 
60
67
  req = Net::HTTP::Post::Multipart.new uri.path, {
61
- file: UploadIO.new(StringIO.new(blob), 'image/png', 'image.png')
68
+ file: UploadIO.new(StringIO.new(image.to_blob), 'image/png', 'image.png')
62
69
  }
63
70
 
64
71
  req.add_field("PRIVATE-TOKEN", @private_token)
@@ -67,7 +74,7 @@ module WatchDoge
67
74
  res = http.request(req).body
68
75
  end
69
76
 
70
- JSON.parse(res)
77
+ JSON.parse(res)['url']
71
78
  end
72
79
 
73
80
  def get_latest_request_iid
@@ -87,6 +94,10 @@ module WatchDoge
87
94
 
88
95
  private
89
96
 
97
+ def md_img_link link
98
+ "![image](#{ENV['CI_PROJECT_URL']}#{link})"
99
+ end
100
+
90
101
  # markdown_table do |context|
91
102
  def markdown_table
92
103
  "<table>
@@ -99,6 +110,14 @@ module WatchDoge
99
110
  </table>"
100
111
  end
101
112
 
113
+ def markdown_table_row before, after, diff
114
+ "<tr>
115
+ <td>#{before}</td>
116
+ <td>#{after}</td>
117
+ <td>#{diff}</td>
118
+ </tr>"
119
+ end
120
+
102
121
  def project_uri path
103
122
  URI(@host + "/projects/#{@project_id}#{path}")
104
123
  end
@@ -8,15 +8,11 @@ module WatchDoge
8
8
  module Notification
9
9
  class Mattermost
10
10
  def initialize args
11
+ super
12
+
11
13
  @host = args[:host]
12
14
  @channel_id = args[:channel_id]
13
15
  @auth_token = args[:auth_token]
14
-
15
- @message_queue = []
16
- end
17
-
18
- def push message
19
- @message_queue << message
20
16
  end
21
17
 
22
18
  def flush
@@ -26,6 +22,8 @@ module WatchDoge
26
22
  post matter_most_meta(message)
27
23
  when ChunkyPNG::Image
28
24
  post_file matter_most_meta(message)
25
+ when WatchDoge::PixelTest
26
+ post_file matter_most_meta(message.diff)
29
27
  end
30
28
  end
31
29
  end
@@ -1,19 +1,10 @@
1
- require 'chunky_png'
2
- require 'json'
3
- require 'net/http'
4
- require 'uri'
5
-
6
1
  module WatchDoge
7
2
  module Notification
8
3
  class SlackWebhook
9
4
  def initialize opt
10
- @incoming_url = opt[:incoming_url]
11
-
12
- @message_queue = []
13
- end
5
+ super
14
6
 
15
- def push message
16
- @message_queue << message
7
+ @incoming_url = opt[:incoming_url]
17
8
  end
18
9
 
19
10
  def flush
@@ -36,6 +27,14 @@ module WatchDoge
36
27
  when ChunkyPNG::Image
37
28
  data = ['data:image/png;base64,', message.to_blob].pack('A*m').gsub(/\n/, '')
38
29
 
30
+ {
31
+ attachments: [{
32
+ image_url: data
33
+ }]
34
+ }
35
+ when WatchDoge::PixelTest
36
+ data = ['data:image/png;base64,', message.diff.to_blob].pack('A*m').gsub(/\n/, '')
37
+
39
38
  {
40
39
  attachments: [{
41
40
  image_url: data
@@ -21,6 +21,8 @@
21
21
  # end
22
22
 
23
23
  # built-in sources
24
+ require 'watchdoge/notification/base'
25
+
24
26
  require 'watchdoge/notification/slack_webhook'
25
27
  require 'watchdoge/notification/mattermost'
26
28
  require 'watchdoge/notification/gitlab_repo'
@@ -51,7 +53,9 @@ module WatchDoge
51
53
  def sources
52
54
  @sources ||= WatchDoge.configuration.notifications
53
55
 
54
- raise "can't find notification sources in configuration" if @sources.empty?
56
+ @sources = {
57
+ base: {}
58
+ } if @sources.empty?
55
59
 
56
60
  @sources.each do |klass_sym, source_args|
57
61
  sources_map[klass_sym] ||=
@@ -0,0 +1,61 @@
1
+ # generating diff image of two input image
2
+
3
+ # usage:
4
+ # diff_image = WatchDoge::PixelTest.diff(chunky_png_image, another_chunky_png_image)
5
+ # WatchDoge::PixelTest.new diff_image, before:
6
+
7
+ # spec:
8
+ # 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
9
+ # 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
10
+
11
+ # todo: should improve testing boundary for more accurate diff imagenot.
12
+
13
+ module WatchDoge
14
+ class PixelTest
15
+ def self.diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
16
+ return nil if input_image.pixels.hash == reference_image.pixels.hash
17
+
18
+ mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
19
+
20
+ dup_input_image = input_image.dup
21
+
22
+ input_image.height.times do |y|
23
+ pixels = input_image.row(y)
24
+
25
+ if y >= reference_image.height
26
+ pixels.each_with_index do |pixel, x|
27
+ dup_input_image.compose_pixel(x, y, mask_color)
28
+ end
29
+ else
30
+ reference_pixels = reference_image.row(y)
31
+
32
+ next if (pixels.hash == reference_pixels.hash)
33
+
34
+ pixels.each_with_index do |pixel, x|
35
+ if pixels[x] != reference_pixels[x]
36
+ dup_input_image.compose_pixel(x, y, reference_pixels[x])
37
+ dup_input_image.compose_pixel(x, y, mask_color)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ dup_input_image
44
+ end
45
+
46
+ attr_reader :diff
47
+ attr_reader :before
48
+ attr_reader :after
49
+
50
+ def initialize input, reference
51
+ @before = reference
52
+ @after = input
53
+
54
+ @diff = self.class.diff input, reference
55
+ end
56
+
57
+ def diff?
58
+ @diff
59
+ end
60
+ end
61
+ end
@@ -63,15 +63,10 @@ module WatchDoge
63
63
  when :regression
64
64
  puts " -> compare reference images on worker #{@worker}"
65
65
  reference_image = WatchDoge::Regression::Utils.load_png self.reference_image
66
- cycle_image = WatchDoge::Regression::Utils.load_png @worker.screenshot.png
67
- diff = WatchDoge::ImageDiff.diff(cycle_image, reference_image)
68
- if diff
69
- if ENV['WATCHDOGE_DEBUG']
70
- WatchDoge::Notification.push cycle_image
71
- WatchDoge::Notification.push reference_image
72
- end
73
- WatchDoge::Notification.push diff
74
- end
66
+ input_image = WatchDoge::Regression::Utils.load_png @worker.screenshot.png
67
+ pixel_test = WatchDoge::PixelTest.new(input_image, reference_image)
68
+
69
+ WatchDoge::Notification.push pixel_test if pixel_test.diff?
75
70
  end
76
71
  end
77
72
 
@@ -32,6 +32,7 @@ module WatchDoge
32
32
  end
33
33
 
34
34
  WatchDoge.hooks.after_regression.each { |t| t.call }
35
+ WatchDoge::Notification.flush
35
36
  end
36
37
  end
37
38
 
@@ -1,4 +1,4 @@
1
1
  # Version of WatchDoge
2
2
  module WatchDoge
3
- VERSION = '0.1.8'
3
+ VERSION = '0.1.9'
4
4
  end
data/lib/watchdoge.rb CHANGED
@@ -4,7 +4,7 @@ require 'watchdoge/configuration'
4
4
  require 'watchdoge/cookie_pool'
5
5
  require 'watchdoge/worker'
6
6
  require 'watchdoge/notification'
7
- require 'watchdoge/image_diff'
7
+ require 'watchdoge/pixel_test'
8
8
  require 'watchdoge/regression'
9
9
  require 'watchdoge/rails/railtie' if defined?(Rails)
10
10
  require 'watchdoge/rails/generator' if defined?(Rails)
data/watchdoge.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'watchdoge'
3
- s.version = '0.1.8'
3
+ s.version = '0.1.9'
4
4
  s.date = '2019-07-22'
5
5
  s.summary = "dogi"
6
6
  s.description = "WatchDoge is Ruby on Rails friendly frontend regression test tool"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watchdoge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shen Lee
@@ -114,11 +114,12 @@ files:
114
114
  - lib/watchdoge.rb
115
115
  - lib/watchdoge/configuration.rb
116
116
  - lib/watchdoge/cookie_pool.rb
117
- - lib/watchdoge/image_diff.rb
118
117
  - lib/watchdoge/notification.rb
118
+ - lib/watchdoge/notification/base.rb
119
119
  - lib/watchdoge/notification/gitlab_repo.rb
120
120
  - lib/watchdoge/notification/mattermost.rb
121
121
  - lib/watchdoge/notification/slack_webhook.rb
122
+ - lib/watchdoge/pixel_test.rb
122
123
  - lib/watchdoge/rails/generator.rb
123
124
  - lib/watchdoge/rails/railtie.rb
124
125
  - lib/watchdoge/regression.rb
@@ -1,47 +0,0 @@
1
- # generating diff image of two input image
2
-
3
- # usage:
4
- # diff_image = WatchDoge::ImageDiff.diff(chunky_png_image, another_chunky_png_image)
5
-
6
- # spec:
7
- # 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
8
- # 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
9
-
10
- # todo: should improve testing boundary for more accurate diff imagenot.
11
-
12
- module WatchDoge
13
- module ImageDiff
14
- class << self
15
- def diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
16
- return nil if input_image.pixels.hash == reference_image.pixels.hash
17
-
18
- mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
19
-
20
- dup_input_image = input_image.dup
21
-
22
- input_image.height.times do |y|
23
- pixels = input_image.row(y)
24
-
25
- if y >= reference_image.height
26
- pixels.each_with_index do |pixel, x|
27
- dup_input_image.compose_pixel(x, y, mask_color)
28
- end
29
- else
30
- reference_pixels = reference_image.row(y)
31
-
32
- next if (pixels.hash == reference_pixels.hash)
33
-
34
- pixels.each_with_index do |pixel, x|
35
- if pixels[x] != reference_pixels[x]
36
- dup_input_image.compose_pixel(x, y, reference_pixels[x])
37
- dup_input_image.compose_pixel(x, y, mask_color)
38
- end
39
- end
40
- end
41
- end
42
-
43
- dup_input_image
44
- end
45
- end
46
- end
47
- end