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  }