lazylead 0.5.2 → 0.7.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +7 -2
  3. data/.docker/Dockerfile +17 -6
  4. data/.rubocop.yml +102 -1
  5. data/.simplecov +1 -1
  6. data/Guardfile +1 -1
  7. data/Rakefile +6 -3
  8. data/bin/lazylead +3 -1
  9. data/lazylead.gemspec +31 -26
  10. data/lib/lazylead/cc.rb +21 -20
  11. data/lib/lazylead/cli/app.rb +8 -3
  12. data/lib/lazylead/confluence.rb +9 -2
  13. data/lib/lazylead/email.rb +0 -20
  14. data/lib/lazylead/exchange.rb +16 -28
  15. data/lib/lazylead/model.rb +31 -16
  16. data/lib/lazylead/opts.rb +65 -2
  17. data/lib/lazylead/postman.rb +13 -17
  18. data/lib/lazylead/salt.rb +1 -0
  19. data/lib/lazylead/system/jira.rb +30 -6
  20. data/lib/lazylead/task/accuracy/accuracy.rb +10 -14
  21. data/lib/lazylead/task/accuracy/attachment.rb +2 -6
  22. data/lib/lazylead/task/accuracy/logs.rb +9 -5
  23. data/lib/lazylead/task/accuracy/onlyll.rb +147 -0
  24. data/lib/lazylead/task/accuracy/records.rb +1 -1
  25. data/lib/lazylead/task/accuracy/servers.rb +16 -7
  26. data/lib/lazylead/task/accuracy/stacktrace.rb +50 -10
  27. data/lib/lazylead/task/accuracy/testcase.rb +16 -9
  28. data/lib/lazylead/task/assignment.rb +96 -0
  29. data/lib/lazylead/task/fix_version.rb +6 -0
  30. data/lib/lazylead/task/propagate_down.rb +1 -1
  31. data/lib/lazylead/task/svn/diff.rb +77 -0
  32. data/lib/lazylead/task/svn/grep.rb +139 -0
  33. data/lib/lazylead/task/svn/touch.rb +99 -0
  34. data/lib/lazylead/version.rb +1 -1
  35. data/lib/messages/illegal_assignee_change.erb +123 -0
  36. data/lib/messages/illegal_fixversion_change.erb +8 -0
  37. data/lib/messages/only_ll.erb +107 -0
  38. data/lib/messages/svn_diff.erb +110 -0
  39. data/lib/messages/{svn_log.erb → svn_diff_attachment.erb} +19 -9
  40. data/lib/messages/svn_grep.erb +114 -0
  41. data/test/lazylead/cc_test.rb +1 -0
  42. data/test/lazylead/model_test.rb +20 -0
  43. data/test/lazylead/opts_test.rb +47 -0
  44. data/test/lazylead/postman_test.rb +8 -5
  45. data/test/lazylead/smoke_test.rb +13 -0
  46. data/test/lazylead/smtp_test.rb +1 -4
  47. data/test/lazylead/system/jira_test.rb +6 -7
  48. data/test/lazylead/task/accuracy/attachment_test.rb +1 -1
  49. data/test/lazylead/task/accuracy/logs_test.rb +62 -2
  50. data/test/lazylead/task/accuracy/onlyll_test.rb +138 -0
  51. data/test/lazylead/task/accuracy/servers_test.rb +2 -2
  52. data/test/lazylead/task/accuracy/stacktrace_test.rb +227 -0
  53. data/test/lazylead/task/accuracy/testcase_test.rb +39 -0
  54. data/test/lazylead/task/assignment_test.rb +53 -0
  55. data/test/lazylead/task/duedate_test.rb +3 -10
  56. data/test/lazylead/task/fix_version_test.rb +1 -0
  57. data/test/lazylead/task/propagate_down_test.rb +4 -3
  58. data/test/lazylead/task/savepoint_test.rb +9 -6
  59. data/test/lazylead/task/svn/diff_test.rb +97 -0
  60. data/test/lazylead/task/svn/grep_test.rb +103 -0
  61. data/test/lazylead/task/{touch_test.rb → svn/touch_test.rb} +7 -34
  62. data/test/test.rb +7 -8
  63. data/upgrades/sqlite/999.testdata.sql +3 -1
  64. metadata +141 -55
  65. data/lib/lazylead/task/touch.rb +0 -119
@@ -66,5 +66,52 @@ module Lazylead
66
66
  test "except keys" do
67
67
  assert_equal 1, Opts.new("one" => "1", "two" => "2").except("one").size
68
68
  end
69
+
70
+ test "attachment is blank" do
71
+ assert_empty Opts.new("attachments" => "").msg_attachments
72
+ end
73
+
74
+ test "attachment is nil" do
75
+ assert_empty Opts.new("attachments" => nil).msg_attachments
76
+ end
77
+
78
+ test "attachment is absent" do
79
+ assert_empty Opts.new({}).msg_attachments
80
+ end
81
+
82
+ test "attachment is present" do
83
+ assert_equal %w[readme.md],
84
+ Opts.new("attachments" => "readme.md").msg_attachments
85
+ end
86
+
87
+ test "attachments are present" do
88
+ assert_equal %w[readme.md license.txt],
89
+ Opts.new("attachments" => "readme.md,license.txt")
90
+ .msg_attachments
91
+ end
92
+
93
+ test "attachments are present as symbol" do
94
+ assert_equal %w[readme.md license.txt],
95
+ Opts.new(attachments: " readme.md , license.txt ")
96
+ .msg_attachments
97
+ end
98
+
99
+ test "attachments is present as array" do
100
+ assert_equal %w[readme.md license.txt],
101
+ Opts.new(attachments: %w[readme.md license.txt])
102
+ .msg_attachments
103
+ end
104
+
105
+ test "value has numeric value" do
106
+ assert Opts.new("key" => "1").numeric? "key"
107
+ end
108
+
109
+ test "text value is not a numeric" do
110
+ refute Opts.new("key" => "val").numeric? "key"
111
+ end
112
+
113
+ test "nil is not a numeric" do
114
+ refute Opts.new("key" => nil).numeric? "key"
115
+ end
69
116
  end
70
117
  end
@@ -24,6 +24,7 @@
24
24
 
25
25
  require_relative "../test"
26
26
  require_relative "../../lib/lazylead/log"
27
+ require_relative "../../lib/lazylead/opts"
27
28
  require_relative "../../lib/lazylead/salt"
28
29
  require_relative "../../lib/lazylead/smtp"
29
30
  require_relative "../../lib/lazylead/postman"
@@ -46,11 +47,13 @@ module Lazylead
46
47
  smtp_pass: ENV["LL_SMTP_PASS"]
47
48
  ).enable
48
49
  Postman.new.send(
49
- "to" => ENV["LL_SMTP_TO"],
50
- "from" => ENV["LL_SMTP_FROM"],
51
- "attachments" => ["readme.md"],
52
- "subject" => "[LL] Attachments",
53
- "template" => "lib/messages/savepoint.erb"
50
+ Opts.new(
51
+ "to" => ENV["LL_SMTP_TO"],
52
+ "from" => ENV["LL_SMTP_FROM"],
53
+ "attachments" => ["readme.md"],
54
+ "subject" => "[LL] Attachments",
55
+ "template" => "lib/messages/savepoint.erb"
56
+ )
54
57
  )
55
58
  end
56
59
  end
@@ -22,6 +22,8 @@
22
22
  # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
23
  # OR OTHER DEALINGS IN THE SOFTWARE.
24
24
 
25
+ require "inifile"
26
+ require "tempfile"
25
27
  require_relative "../test"
26
28
 
27
29
  module Lazylead
@@ -34,5 +36,16 @@ module Lazylead
34
36
  test "ENV has no key" do
35
37
  refute env? "c"
36
38
  end
39
+ test "ini file found" do
40
+ Tempfile.create do |f|
41
+ f << "EnvTest=value"
42
+ f.flush
43
+ IniFile.new(filename: f).each { |_, k, v| ENV[k] = v }
44
+ assert_equal "value", ENV["EnvTest"]
45
+ end
46
+ end
47
+ test "ini file not found" do
48
+ assert_empty IniFile.new(filename: "absent.ini").to_h
49
+ end
37
50
  end
38
51
  end
@@ -38,10 +38,7 @@ module Lazylead
38
38
  subject "The fake!"
39
39
  body "Fake body"
40
40
  end
41
- assert_equal 1,
42
- Mail::TestMailer.deliveries
43
- .filter { |m| m.subject.eql? "The fake!" }
44
- .length
41
+ assert_equal(1, Mail::TestMailer.deliveries.count { |m| m.subject.eql? "The fake!" })
45
42
  end
46
43
 
47
44
  # @todo #43/DEV email-related properties should be exported to the CI env
@@ -142,13 +142,6 @@ module Lazylead
142
142
  assert_equal "Hi there!", issue.comment[:body]
143
143
  end
144
144
 
145
- test "search by limit in 1 issue" do
146
- assert_equal 1,
147
- NoAuthJira.new("https://jira.spring.io")
148
- .issues("key in (DATAJDBC-480, DATAJDBC-500)", max_results: "1")
149
- .size
150
- end
151
-
152
145
  test "description is correct" do
153
146
  assert_words %w[DATACMNS-1639\ moved\ entity\ instantiators],
154
147
  NoAuthJira.new("https://jira.spring.io")
@@ -186,5 +179,11 @@ module Lazylead
186
179
  .labels,
187
180
  "Spring"
188
181
  end
182
+
183
+ test "bulk search in few iterations" do
184
+ assert NoAuthJira.new("https://jira.spring.io")
185
+ .issues("key>DATAJDBC-500")
186
+ .size >= 118
187
+ end
189
188
  end
190
189
  end
@@ -34,7 +34,7 @@ module Lazylead
34
34
  super "", 0, ""
35
35
  end
36
36
 
37
- def matching(attach)
37
+ def matches?(attach)
38
38
  "ConfigServerLogWithException.txt".eql? attach.attrs["filename"]
39
39
  end
40
40
  end
@@ -63,12 +63,72 @@ module Lazylead
63
63
  )
64
64
  end
65
65
 
66
- test "log file size less than 10KB" do
66
+ test "log file size less than 5KB" do
67
67
  refute Logs.new.passed(
68
68
  OpenStruct.new(
69
69
  attachments: [
70
70
  OpenStruct.new(
71
- attrs: { "size" => 10_000, "filename" => "catalina.log" }
71
+ attrs: { "size" => 5000, "filename" => "catalina.log" }
72
+ )
73
+ ]
74
+ )
75
+ )
76
+ end
77
+
78
+ test "rotated log file is present" do
79
+ assert Logs.new.passed(
80
+ OpenStruct.new(
81
+ attachments: [
82
+ OpenStruct.new(
83
+ attrs: { "size" => 10_241, "filename" => "catalina.log111" }
84
+ )
85
+ ]
86
+ )
87
+ )
88
+ end
89
+
90
+ test "log txt file is present" do
91
+ assert Logs.new.passed(
92
+ OpenStruct.new(
93
+ attachments: [
94
+ OpenStruct.new(
95
+ attrs: { "size" => 10_241, "filename" => "catalina.txt" }
96
+ )
97
+ ]
98
+ )
99
+ )
100
+ end
101
+
102
+ test "zip log file is present" do
103
+ assert Logs.new.passed(
104
+ OpenStruct.new(
105
+ attachments: [
106
+ OpenStruct.new(
107
+ attrs: { "size" => 10_241, "filename" => "catalina.log.zip" }
108
+ )
109
+ ]
110
+ )
111
+ )
112
+ end
113
+
114
+ test "gz log file is present" do
115
+ assert Logs.new.passed(
116
+ OpenStruct.new(
117
+ attachments: [
118
+ OpenStruct.new(
119
+ attrs: { "size" => 10_241, "filename" => "catalina.log.gz" }
120
+ )
121
+ ]
122
+ )
123
+ )
124
+ end
125
+
126
+ test "tar gz log file is present" do
127
+ assert Logs.new.passed(
128
+ OpenStruct.new(
129
+ attachments: [
130
+ OpenStruct.new(
131
+ attrs: { "size" => 10_241, "filename" => "catalina.log.tar.gz" }
72
132
  )
73
133
  ]
74
134
  )
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License
4
+ #
5
+ # Copyright (c) 2019-2020 Yurii Dubinka
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"),
9
+ # to deal in the Software without restriction, including without limitation
10
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
+ # and/or sell copies of the Software, and to permit persons to whom
12
+ # the Software is furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included
15
+ # in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
23
+ # OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ require_relative "../../../test"
26
+ require_relative "../../../../lib/lazylead/opts"
27
+ require_relative "../../../../lib/lazylead/smtp"
28
+ require_relative "../../../../lib/lazylead/postman"
29
+ require_relative "../../../../lib/lazylead/system/jira"
30
+ require_relative "../../../../lib/lazylead/task/accuracy/onlyll"
31
+
32
+ module Lazylead
33
+ class OnlyLLTest < Lazylead::Test
34
+ # In current tests the grid label is 'PullRequest'.
35
+ # The default grid labels are 0%, 10%, 20%, etc., the reason why
36
+ # 'PullRequest' label is used here as we don't have 0%, 10%, etc.
37
+ # on https://jira.spring.io.
38
+ test "grid label found" do
39
+ assert Labels.new(
40
+ NoAuthJira.new("https://jira.spring.io").issues("key=XD-3725").first,
41
+ Opts.new("grid" => "PullRequest, ,")
42
+ ).exists?
43
+ end
44
+
45
+ test "grid label set by ll" do
46
+ assert Labels.new(
47
+ NoAuthJira.new("https://jira.spring.io")
48
+ .issues("key=XD-3725", expand: "changelog")
49
+ .first,
50
+ Opts.new("grid" => "PullRequest", "author" => "grussell")
51
+ ).valid?
52
+ end
53
+
54
+ test "email notification" do
55
+ Lazylead::Smtp.new.enable
56
+ Lazylead::Task::OnlyLL.new.run(
57
+ NoAuthJira.new("https://jira.spring.io"),
58
+ Postman.new,
59
+ Opts.new(
60
+ "from" => "ll@fake.com",
61
+ "to" => "lead@fake.com",
62
+ "grid" => "PullRequest",
63
+ "author" => "LL",
64
+ "jql" => "key=XD-3725",
65
+ "max_results" => 200,
66
+ "subject" => "[LL] Only",
67
+ "fields" => "priority,summary,reporter,labels",
68
+ "template" => "lib/messages/only_ll.erb"
69
+ )
70
+ )
71
+ assert_email "[LL] Only",
72
+ %w[XD-3725 Blocker EmbeddedHeadersMessageConverter]
73
+ end
74
+
75
+ test "detect score" do
76
+ assert_equal "PullRequest",
77
+ Labels.new(
78
+ NoAuthJira.new("https://jira.spring.io")
79
+ .issues("key=XD-3725", expand: "changelog")
80
+ .first,
81
+ Opts.new(
82
+ "grid" => "PullRequest",
83
+ "author" => "grussell"
84
+ )
85
+ ).score
86
+ end
87
+
88
+ test "multiple scores in the same ticket" do
89
+ assert_equal "10%",
90
+ Labels.new(
91
+ Struct.new(:key) do
92
+ def history
93
+ [{ "id" => "287906", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:12:35.853+0000", "items" => [{ "field" => "Fix Version", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "15424", "toString" => "1.3.1" }] }, { "id" => "287913", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:14:34.085+0000", "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "Y LL" }] }, { "id" => "287915", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:19:36.118+0000", "items" => [{ "field" => "Sprint", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => "106", "toString" => "Sprint 64" }] }, { "id" => "287916", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-17T18:19:36.162+0000", "items" => [{ "field" => "Rank", "fieldtype" => "custom", "from" => "", "fromString" => "", "to" => "", "toString" => "Ranked higher" }] }, { "id" => "287921", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:30:47.508+0000", "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "10000", "fromString" => "To Do", "to" => "3", "toString" => "In Progress" }] }, { "id" => "287922", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=ll", "name" => "ll", "key" => "ll", "emailAddress" => "ll at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/0037f772e271b0d90bd62361768cb820?d=mm&s=32" }, "displayName" => "Y LL", "active" => true, "timeZone" => "America/New_York" }, "created" => "2015-12-17T18:31:54.137+0000", "items" => [{ "field" => "Pull Request URL", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "https://github.com/spring-projects/spring-xd/pull/1872" }, { "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "10% 20%" }] }, { "id" => "288214", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-25T00:16:09.649+0000", "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "3", "fromString" => "In Progress", "to" => "10006", "toString" => "In PR" }] }, { "id" => "288215", "author" => { "self" => "https://jira.spring.io/rest/api/2/user?username=sy", "name" => "sy", "key" => "sy", "emailAddress" => "san at pivotal dot io", "avatarUrls" => { "48x48" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=48", "24x24" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=24", "16x16" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=16", "32x32" => "https://www.gravatar.com/avatar/f0373ebca801ca4b2746732b451f497c?d=mm&s=32" }, "displayName" => "sy an", "active" => true, "timeZone" => "America/Los_Angeles" }, "created" => "2015-12-25T00:16:17.499+0000", "items" => [{ "field" => "Actual Story Points", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "1" }, { "field" => "resolution", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "8", "toString" => "Complete" }, { "field" => "status", "fieldtype" => "jira", "from" => "10006", "fromString" => "In PR", "to" => "10001", "toString" => "Done" }] }]
94
+ end
95
+ end.new("XD-3725"),
96
+ Opts.new("grid" => "10%,20%,30%", "author" => "ll")
97
+ ).score
98
+ end
99
+
100
+ test "sort of percents" do
101
+ assert_equal %w[10% 20% 30%], %w[30% 10% 20%].sort
102
+ end
103
+
104
+ test "ensure that violators found" do
105
+ assert_equal "Aron set 40%",
106
+ Labels.new(
107
+ Struct.new(:key) do
108
+ def history
109
+ [
110
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Fix Version", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "15424", "toString" => "1.3.1" }] },
111
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "ll" }] },
112
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Sprint", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => "106", "toString" => "Sprint 64" }] },
113
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Rank", "fieldtype" => "custom", "from" => "", "fromString" => "", "to" => "", "toString" => "Ranked higher" }] },
114
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "10000", "fromString" => "To Do", "to" => "3", "toString" => "In Progress" }] },
115
+ { "author" => { "name" => "ll", "key" => "ll", "displayName" => "L L" }, "items" => [{ "field" => "assignee", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "ll", "toString" => "ll" }, { "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "20%" }] },
116
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "Actual Story Points", "fieldtype" => "custom", "from" => nil, "fromString" => nil, "to" => nil, "toString" => "1" }, { "field" => "resolution", "fieldtype" => "jira", "from" => nil, "fromString" => nil, "to" => "8", "toString" => "Complete" }, { "field" => "status", "fieldtype" => "jira", "from" => "10006", "fromString" => "In PR", "to" => "10001", "toString" => "Done" }] },
117
+ { "author" => { "name" => "ap", "key" => "ap", "displayName" => "Aron" }, "items" => [{ "field" => "labels", "fieldtype" => "jira", "from" => nil, "fromString" => "", "to" => nil, "toString" => "abc 40%" }] },
118
+ { "author" => { "name" => "sy", "key" => "sy", "displayName" => "S N" }, "items" => [{ "field" => "status", "fieldtype" => "jira", "from" => "3", "fromString" => "In Progress", "to" => "10006", "toString" => "In PR" }] }
119
+ ]
120
+ end
121
+ end.new("XD-3725"),
122
+ Opts.new("grid" => "10%,20%,30%,40%", "author" => "ll")
123
+ ).violators.first
124
+ end
125
+
126
+ test "violators should consider already existing LL grid labels" do
127
+ assert_equal "Aron set 40%",
128
+ Labels.new(
129
+ Struct.new(:key) do
130
+ def history
131
+ [{ "author" => { "name" => "ap", "key" => "ap", "displayName" => "Aron" }, "items" => [{ "field" => "labels", "fromString" => "0%", "toString" => "0% abc 40%" }] }]
132
+ end
133
+ end.new("XD-3725"),
134
+ Opts.new("grid" => "10%,20%,30%,40%", "author" => "ll")
135
+ ).violators.first
136
+ end
137
+ end
138
+ end
@@ -42,7 +42,7 @@ module Lazylead
42
42
  end
43
43
 
44
44
  test "url to failed entity found in description" do
45
- assert Servers.new(envs: [%r{(http|https):\/\/\w+\:\d+\/.{10,}}]).passed(
45
+ assert Servers.new(envs: [%r{(http|https)://\w+:\d+/.{10,}}]).passed(
46
46
  Task.new(
47
47
  "1. Open the dedicated app
48
48
  2. Click on https://server:6900/object?id=2000
@@ -53,7 +53,7 @@ module Lazylead
53
53
  end
54
54
 
55
55
  test "url to failed entity not present in description" do
56
- refute Servers.new(envs: [%r{(http|https):\/\/\w+\:\d+\/.{10,}}]).passed(
56
+ refute Servers.new(envs: [%r{(http|https)://\w+:\d+/.{10,}}]).passed(
57
57
  Task.new(
58
58
  "1. Open the dedicated app
59
59
  2. Click on https://server:6900/
@@ -57,6 +57,36 @@ module Lazylead
57
57
  )
58
58
  end
59
59
 
60
+ test "java stacktrace is found in uppercase" do
61
+ assert Stacktrace.new.passed(
62
+ OpenStruct.new(
63
+ description: "
64
+ XXXXXX env: http://xxxx.xxx.com:00000/
65
+ WL log [^clust1.log]
66
+ http://xxx.xxx.com/display/xxx/SQLException+No+more+data+to+read+from+socket
67
+
68
+ During call we found in clust1.log the following error
69
+ {NoFoRmAt}
70
+ at xxx.xxx.xxx.xxx.wrapper.XxxXxxXxxxXxx.xxxxXxxxXxxx(XxxXxxXxxxXxx.java:233)
71
+ at xxx.xxx.xxx.xxx.wrapper.XxxXxxXxxxXxx.xxxxXxxxXxxx(XxxXxxXxxxXxx.java:343)
72
+ ... 318 more
73
+ Caused by: javax.transaction.TransactionRolledbackException: EJB Exception: ; nested exception is:
74
+ javax.ejb.TransactionRolledbackLocalException: EJB Exception:
75
+ at weblogic.utils.StackTraceDisabled.unknownMethod()
76
+ Caused by: javax.ejb.TransactionRolledbackLocalException: EJB Exception:
77
+ ... 1 more
78
+ Caused by: javax.ejb.EJBException: java.sql.SQLRecoverableException: No more data to read from socket
79
+ ... 1 more
80
+ Caused by: java.sql.SQLRecoverableException: No more data to read from socket
81
+ ... 1 more
82
+ {NoFoRmAt}
83
+
84
+ The investigation is required.
85
+ More details here: XXXXX-xxxxxx"
86
+ )
87
+ )
88
+ end
89
+
60
90
  test "stacktrace is found" do
61
91
  assert Stacktrace.new.passed(
62
92
  OpenStruct.new(
@@ -95,6 +125,14 @@ module Lazylead
95
125
  )
96
126
  end
97
127
 
128
+ test "exception is found" do
129
+ assert Stacktrace.new.passed(
130
+ OpenStruct.new(
131
+ description: "{noformat}sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target{noformat}"
132
+ )
133
+ )
134
+ end
135
+
98
136
  test "ORA error is found" do
99
137
  assert Stacktrace.new.passed(
100
138
  OpenStruct.new(
@@ -109,5 +147,194 @@ module Lazylead
109
147
  )
110
148
  )
111
149
  end
150
+
151
+ test "ORA error is found in uppercase" do
152
+ assert Stacktrace.new.passed(
153
+ OpenStruct.new(
154
+ description: "
155
+ {NOFORMAT}
156
+ @XXXX/xxx/xxx/xxxx_xxx_xxxxx_xxx_xx.sql
157
+ ORA-02291: 1 integrity constraint (XXX_XXX_XXX.XX_xxx) violated - xx xxx not found for xx_xx=xx xxxxx_xx=XXXXXXX xxxxx=XXXXXXXX xxx_xx=xxx xx_xxx=xxxx.xxx.xxx.xxxxx.xxx.xxx.xxxxx
158
+ XXXX-xxx-xxxx: xxxxx xxxxx Xxxxx xxxx Xxxx
159
+ {NOFORMAT}
160
+
161
+ XXXX - XXX_XXX.X.XXXX.XXXX.XXXX.XxxxxxXX.X_xxxXXXXXX"
162
+ )
163
+ )
164
+ end
165
+
166
+ test "java error is found in code section" do
167
+ assert Stacktrace.new.passed(
168
+ OpenStruct.new(
169
+ description: "
170
+ asdfasdfasdf
171
+ {code:java}texta-line1
172
+ ;texta-line2{code}
173
+ asdjf;asdjfa;sdjf
174
+ as;djf;asdjf
175
+ {code}javax.servlet.ServletException: Something went wrong
176
+ at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
177
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
178
+ at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
179
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
180
+ at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
181
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
182
+ at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
183
+ at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
184
+ at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
185
+ at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
186
+ at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
187
+ at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
188
+ at org.mortbay.jetty.Server.handle(Server.java:326)
189
+ at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
190
+ at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
191
+ at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
192
+ at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
193
+ at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
194
+ at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
195
+ at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
196
+ Caused by: com.example.myproject.MyProjectServletException
197
+ at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
198
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
199
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
200
+ at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
201
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
202
+ at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
203
+ ... 27 more
204
+ Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
205
+ at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
206
+ at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
207
+ at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
208
+ at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
209
+ at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
210
+ at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
211
+ at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
212
+ at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
213
+ at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
214
+ at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
215
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
216
+ at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
217
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
218
+ at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
219
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
220
+ at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
221
+ at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
222
+ at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
223
+ at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
224
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
225
+ at java.lang.reflect.Method.invoke(Method.java:597)
226
+ at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
227
+ at $Proxy19.save(Unknown Source)
228
+ at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
229
+ at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
230
+ ... 32 more
231
+ Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
232
+ at org.hsqldb.jdbc.Util.throwError(Unknown Source)
233
+ at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
234
+ at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
235
+ at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
236
+ ... 54 more{code}
237
+ asdfasdfasdf{code:sql}select 1 from dual {code}what?
238
+ "
239
+ )
240
+ )
241
+ end
242
+
243
+ test "java error is found in code section in uppercase" do
244
+ assert Stacktrace.new.passed(
245
+ OpenStruct.new(
246
+ description: "
247
+ {CODE}javax.servlet.ServletException: Something went wrong
248
+ at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
249
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
250
+ at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
251
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
252
+ at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
253
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
254
+ at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
255
+ at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
256
+ at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
257
+ at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
258
+ at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
259
+ at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
260
+ at org.mortbay.jetty.Server.handle(Server.java:326)
261
+ at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
262
+ at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
263
+ at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
264
+ at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
265
+ at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
266
+ at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
267
+ at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
268
+ Caused by: com.example.myproject.MyProjectServletException
269
+ at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
270
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
271
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
272
+ at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
273
+ at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
274
+ at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
275
+ ... 27 more
276
+ Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
277
+ at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
278
+ at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
279
+ at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
280
+ at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
281
+ at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
282
+ at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
283
+ at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
284
+ at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
285
+ at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
286
+ at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
287
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
288
+ at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
289
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
290
+ at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
291
+ at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
292
+ at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
293
+ at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
294
+ at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
295
+ at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
296
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
297
+ at java.lang.reflect.Method.invoke(Method.java:597)
298
+ at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
299
+ at $Proxy19.save(Unknown Source)
300
+ at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
301
+ at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
302
+ ... 32 more
303
+ Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
304
+ at org.hsqldb.jdbc.Util.throwError(Unknown Source)
305
+ at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
306
+ at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
307
+ at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
308
+ ... 54 more{CODE}
309
+ "
310
+ )
311
+ )
312
+ end
313
+
314
+ test "java error is found in colored code section in uppercase" do
315
+ assert Stacktrace.new.passed(
316
+ OpenStruct.new(
317
+ description: "
318
+ {CODE:red}
319
+ Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
320
+ at org.hsqldb.jdbc.Util.throwError(Unknown Source)
321
+ at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
322
+ at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
323
+ at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
324
+ ... 54 more{CODE}
325
+ "
326
+ )
327
+ )
328
+ end
329
+
330
+ test "pair detected" do
331
+ assert_equal [[1, 4]],
332
+ Stacktrace.new.pairs(%w[aa tag bb cc tag dd], "tag")
333
+ end
334
+
335
+ test "proper pair detected" do
336
+ assert_equal [[1, 4]],
337
+ Stacktrace.new.pairs(%w[aa tag bb cc tag dd tag], "tag")
338
+ end
112
339
  end
113
340
  end