github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/email/lore/parse_test.go (about) 1 // Copyright 2023 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package lore 5 6 import ( 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/google/go-cmp/cmp" 13 "github.com/google/syzkaller/dashboard/dashapi" 14 "github.com/google/syzkaller/pkg/email" 15 ) 16 17 func TestThreadsCollection(t *testing.T) { 18 messages := []string{ 19 // <A-Base> <-- <A-Child-1> <-- <A-Child-1-1>. 20 `Date: Sun, 7 May 2017 19:54:00 -0700 21 Subject: Thread A 22 Message-ID: <A-Base> 23 From: UserA <a@user.com> 24 Content-Type: text/plain 25 26 27 Some text`, 28 `Date: Sun, 7 May 2017 19:55:00 -0700 29 Subject: Re: Thread A 30 Message-ID: <A-Child-1> 31 From: UserB <b@user.com> 32 To: UserA <a@user.com> 33 Content-Type: text/plain 34 In-Reply-To: <A-Base> 35 36 37 Some reply`, 38 `Date: Sun, 7 May 2017 19:56:00 -0700 39 Subject: Re: Re: Thread A 40 Message-ID: <A-Child-1-1> 41 From: UserC <c@user.com> 42 To: UserA <a@user.com>, UserB <b@user.com> 43 Content-Type: text/plain 44 In-Reply-To: <A-Child-1> 45 46 47 Some reply (2)`, 48 // <Bug> with two children: <Bug-Reply1>, <Bug-Reply2>. 49 `Date: Sun, 7 May 2017 19:57:00 -0700 50 Subject: [syzbot] Some bug 51 Message-ID: <Bug> 52 From: syzbot <syzbot+4564456@bar.com> 53 Content-Type: text/plain 54 55 56 Bug report`, 57 `Date: Sun, 7 May 2017 19:58:00 -0700 58 Subject: Re: [syzbot] Some bug 59 Message-ID: <Bug-Reply1> 60 From: UserC <c@user.com> 61 To: syzbot <syzbot+4564456@bar.com> 62 In-Reply-To: <Bug> 63 Content-Type: text/plain 64 65 66 Bug report reply`, 67 `Date: Sun, 7 May 2017 19:58:01 -0700 68 Subject: Re: [syzbot] Some bug 69 Message-ID: <Bug-Reply2> 70 From: UserD <d@user.com> 71 To: syzbot <syzbot+4564456@bar.com> 72 In-Reply-To: <Bug>B 73 Content-Type: text/plain 74 75 76 Bug report reply 2`, 77 // And one PATCH without replies. 78 `Date: Sun, 7 May 2017 19:58:01 -0700 79 Subject: [PATCH] Some bug fixed 80 Message-ID: <Patch> 81 From: UserE <e@user.com> 82 Cc: syzbot <syzbot+12345@bar.com> 83 Content-Type: text/plain 84 85 86 Patch`, 87 // An orphaned reply from a human. 88 `Date: Sun, 7 May 2017 19:57:00 -0700 89 Subject: Another bug discussion 90 In-Reply-To: <Unknown> 91 Message-ID: <Sub-Discussion> 92 From: person@email.com 93 Cc: syzbot <syzbot+4564456@bar.com> 94 Content-Type: text/plain 95 96 97 Bug report`, 98 // An orphaned reply from a bot. 99 `Date: Sun, 7 May 2017 19:57:00 -0700 100 Subject: Re: [syzbot] Some bug 3 101 In-Reply-To: <Unknown> 102 Message-ID: <Sub-Discussion-Bot> 103 From: syzbot+4564456@bar.com 104 To: all@email.com 105 Content-Type: text/plain 106 107 108 Bug report`, 109 } 110 111 zone := time.FixedZone("", -7*60*60) 112 expected := map[string]*Thread{ 113 "<A-Base>": { 114 Subject: "Thread A", 115 MessageID: "<A-Base>", 116 Type: dashapi.DiscussionMention, 117 Messages: []*email.Email{ 118 { 119 MessageID: "<A-Base>", 120 Subject: "Thread A", 121 Date: time.Date(2017, time.May, 7, 19, 54, 0, 0, zone), 122 Author: "a@user.com", 123 Cc: []string{"a@user.com"}, 124 }, 125 { 126 MessageID: "<A-Child-1>", 127 Subject: "Re: Thread A", 128 Date: time.Date(2017, time.May, 7, 19, 55, 0, 0, zone), 129 Author: "b@user.com", 130 Cc: []string{"a@user.com", "b@user.com"}, 131 InReplyTo: "<A-Base>", 132 }, 133 { 134 MessageID: "<A-Child-1-1>", 135 Subject: "Re: Re: Thread A", 136 Date: time.Date(2017, time.May, 7, 19, 56, 0, 0, zone), 137 Author: "c@user.com", 138 Cc: []string{"a@user.com", "b@user.com", "c@user.com"}, 139 InReplyTo: "<A-Child-1>", 140 }, 141 }, 142 }, 143 "<Bug>": { 144 Subject: "[syzbot] Some bug", 145 MessageID: "<Bug>", 146 Type: dashapi.DiscussionReport, 147 BugIDs: []string{"4564456"}, 148 Messages: []*email.Email{ 149 { 150 MessageID: "<Bug>", 151 BugIDs: []string{"4564456"}, 152 Subject: "[syzbot] Some bug", 153 Date: time.Date(2017, time.May, 7, 19, 57, 0, 0, zone), 154 Author: "syzbot@bar.com", 155 OwnEmail: true, 156 }, 157 { 158 MessageID: "<Bug-Reply1>", 159 BugIDs: []string{"4564456"}, 160 Subject: "Re: [syzbot] Some bug", 161 Date: time.Date(2017, time.May, 7, 19, 58, 0, 0, zone), 162 Author: "c@user.com", 163 Cc: []string{"c@user.com"}, 164 InReplyTo: "<Bug>", 165 }, 166 { 167 MessageID: "<Bug-Reply2>", 168 BugIDs: []string{"4564456"}, 169 Subject: "Re: [syzbot] Some bug", 170 Date: time.Date(2017, time.May, 7, 19, 58, 1, 0, zone), 171 Author: "d@user.com", 172 Cc: []string{"d@user.com"}, 173 InReplyTo: "<Bug>", 174 }, 175 }, 176 }, 177 "<Patch>": { 178 Subject: "[PATCH] Some bug fixed", 179 MessageID: "<Patch>", 180 Type: dashapi.DiscussionPatch, 181 BugIDs: []string{"12345"}, 182 Messages: []*email.Email{ 183 { 184 MessageID: "<Patch>", 185 BugIDs: []string{"12345"}, 186 Subject: "[PATCH] Some bug fixed", 187 Date: time.Date(2017, time.May, 7, 19, 58, 1, 0, zone), 188 Author: "e@user.com", 189 Cc: []string{"e@user.com"}, 190 }, 191 }, 192 }, 193 "<Sub-Discussion>": { 194 Subject: "Another bug discussion", 195 MessageID: "<Sub-Discussion>", 196 Type: dashapi.DiscussionMention, 197 BugIDs: []string{"4564456"}, 198 Messages: []*email.Email{ 199 { 200 MessageID: "<Sub-Discussion>", 201 InReplyTo: "<Unknown>", 202 Date: time.Date(2017, time.May, 7, 19, 57, 0, 0, zone), 203 BugIDs: []string{"4564456"}, 204 Cc: []string{"person@email.com"}, 205 Subject: "Another bug discussion", 206 Author: "person@email.com", 207 }, 208 }, 209 }, 210 "<Sub-Discussion-Bot>": nil, 211 } 212 213 emails := []*email.Email{} 214 for _, m := range messages { 215 msg, err := email.Parse(strings.NewReader(m), []string{"syzbot@bar.com"}, 216 []string{}, []string{"bar.com"}) 217 if err != nil { 218 t.Fatal(err) 219 } 220 msg.Body = "" 221 emails = append(emails, msg) 222 } 223 224 threads := Threads(emails) 225 got := map[string]*Thread{} 226 227 for _, d := range threads { 228 sort.Slice(d.Messages, func(i, j int) bool { 229 return d.Messages[i].Date.Before(d.Messages[j].Date) 230 }) 231 got[d.MessageID] = d 232 } 233 234 for key, val := range expected { 235 if diff := cmp.Diff(val, got[key]); diff != "" { 236 t.Fatalf("%s: %s", key, diff) 237 } 238 } 239 240 if len(threads) > len(expected) { 241 t.Fatalf("expected %d threads, got %d", len(expected), len(threads)) 242 } 243 } 244 245 func TestDiscussionType(t *testing.T) { 246 tests := []struct { 247 msg *email.Email 248 ret dashapi.DiscussionType 249 }{ 250 { 251 msg: &email.Email{ 252 Subject: "[PATCH] Bla-bla", 253 }, 254 ret: dashapi.DiscussionPatch, 255 }, 256 { 257 msg: &email.Email{ 258 Subject: "[patch v3] Bla-bla", 259 }, 260 ret: dashapi.DiscussionPatch, 261 }, 262 { 263 msg: &email.Email{ 264 Subject: "[RFC PATCH] Bla-bla", 265 }, 266 ret: dashapi.DiscussionPatch, 267 }, 268 { 269 msg: &email.Email{ 270 Subject: "[RESEND PATCH] Bla-bla", 271 }, 272 ret: dashapi.DiscussionPatch, 273 }, 274 { 275 msg: &email.Email{ 276 Subject: "[syzbot] Monthly ext4 report", 277 OwnEmail: true, 278 }, 279 ret: dashapi.DiscussionReminder, 280 }, 281 { 282 msg: &email.Email{ 283 Subject: "[syzbot] WARNING in abcd", 284 OwnEmail: true, 285 }, 286 ret: dashapi.DiscussionReport, 287 }, 288 { 289 msg: &email.Email{ 290 Subject: "Some human-reported bug", 291 }, 292 ret: dashapi.DiscussionMention, 293 }, 294 } 295 for _, test := range tests { 296 got := DiscussionType(test.msg) 297 if got != test.ret { 298 t.Fatalf("expected %v got %v for %v", test.ret, got, test.msg) 299 } 300 } 301 }