github.com/spline-fu/mattermost-server@v4.10.10+incompatible/app/notification_test.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	"github.com/mattermost/mattermost-server/model"
    13  	"github.com/mattermost/mattermost-server/utils"
    14  )
    15  
    16  func TestSendNotifications(t *testing.T) {
    17  	th := Setup().InitBasic()
    18  	defer th.TearDown()
    19  
    20  	th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel)
    21  
    22  	post1, err := th.App.CreatePostMissingChannel(&model.Post{
    23  		UserId:    th.BasicUser.Id,
    24  		ChannelId: th.BasicChannel.Id,
    25  		Message:   "@" + th.BasicUser2.Username,
    26  		Type:      model.POST_ADD_TO_CHANNEL,
    27  		Props:     map[string]interface{}{model.POST_PROPS_ADDED_USER_ID: "junk"},
    28  	}, true)
    29  
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	mentions, err := th.App.SendNotifications(post1, th.BasicTeam, th.BasicChannel, th.BasicUser, nil)
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	} else if mentions == nil {
    38  		t.Log(mentions)
    39  		t.Fatal("user should have been mentioned")
    40  	} else if !utils.StringInSlice(th.BasicUser2.Id, mentions) {
    41  		t.Log(mentions)
    42  		t.Fatal("user should have been mentioned")
    43  	}
    44  
    45  	dm, err := th.App.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	post2, err := th.App.CreatePostMissingChannel(&model.Post{
    51  		UserId:    th.BasicUser.Id,
    52  		ChannelId: dm.Id,
    53  		Message:   "dm message",
    54  	}, true)
    55  
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	_, err = th.App.SendNotifications(post2, th.BasicTeam, dm, th.BasicUser, nil)
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	th.App.UpdateActive(th.BasicUser2, false)
    66  	th.App.InvalidateAllCaches()
    67  
    68  	post3, err := th.App.CreatePostMissingChannel(&model.Post{
    69  		UserId:    th.BasicUser.Id,
    70  		ChannelId: dm.Id,
    71  		Message:   "dm message",
    72  	}, true)
    73  
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	_, err = th.App.SendNotifications(post3, th.BasicTeam, dm, th.BasicUser, nil)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  }
    83  
    84  func TestGetExplicitMentions(t *testing.T) {
    85  	id1 := model.NewId()
    86  	id2 := model.NewId()
    87  	id3 := model.NewId()
    88  
    89  	for name, tc := range map[string]struct {
    90  		Message  string
    91  		Keywords map[string][]string
    92  		Expected *ExplicitMentions
    93  	}{
    94  		"Nobody": {
    95  			Message:  "this is a message",
    96  			Keywords: map[string][]string{},
    97  			Expected: &ExplicitMentions{},
    98  		},
    99  		"NonexistentUser": {
   100  			Message: "this is a message for @user",
   101  			Expected: &ExplicitMentions{
   102  				OtherPotentialMentions: []string{"user"},
   103  			},
   104  		},
   105  		"OnePerson": {
   106  			Message:  "this is a message for @user",
   107  			Keywords: map[string][]string{"@user": {id1}},
   108  			Expected: &ExplicitMentions{
   109  				MentionedUserIds: map[string]bool{
   110  					id1: true,
   111  				},
   112  			},
   113  		},
   114  		"OnePersonWithPeriodAtEndOfUsername": {
   115  			Message:  "this is a message for @user.name.",
   116  			Keywords: map[string][]string{"@user.name.": {id1}},
   117  			Expected: &ExplicitMentions{
   118  				MentionedUserIds: map[string]bool{
   119  					id1: true,
   120  				},
   121  			},
   122  		},
   123  		"OnePersonWithPeriodAtEndOfUsernameButNotSimilarName": {
   124  			Message:  "this is a message for @user.name.",
   125  			Keywords: map[string][]string{"@user.name.": {id1}, "@user.name": {id2}},
   126  			Expected: &ExplicitMentions{
   127  				MentionedUserIds: map[string]bool{
   128  					id1: true,
   129  				},
   130  			},
   131  		},
   132  		"OnePersonAtEndOfSentence": {
   133  			Message:  "this is a message for @user.",
   134  			Keywords: map[string][]string{"@user": {id1}},
   135  			Expected: &ExplicitMentions{
   136  				MentionedUserIds: map[string]bool{
   137  					id1: true,
   138  				},
   139  			},
   140  		},
   141  		"OnePersonWithoutAtMention": {
   142  			Message:  "this is a message for @user",
   143  			Keywords: map[string][]string{"this": {id1}},
   144  			Expected: &ExplicitMentions{
   145  				MentionedUserIds: map[string]bool{
   146  					id1: true,
   147  				},
   148  				OtherPotentialMentions: []string{"user"},
   149  			},
   150  		},
   151  		"OnePersonWithColonAtEnd": {
   152  			Message:  "this is a message for @user:",
   153  			Keywords: map[string][]string{"this": {id1}},
   154  			Expected: &ExplicitMentions{
   155  				MentionedUserIds: map[string]bool{
   156  					id1: true,
   157  				},
   158  				OtherPotentialMentions: []string{"user"},
   159  			},
   160  		},
   161  		"MultiplePeopleWithOneWord": {
   162  			Message:  "this is a message for @user",
   163  			Keywords: map[string][]string{"@user": {id1, id2}},
   164  			Expected: &ExplicitMentions{
   165  				MentionedUserIds: map[string]bool{
   166  					id1: true,
   167  					id2: true,
   168  				},
   169  			},
   170  		},
   171  		"OneOfMultiplePeople": {
   172  			Message:  "this is a message for @user",
   173  			Keywords: map[string][]string{"@user": {id1}, "@mention": {id2}},
   174  			Expected: &ExplicitMentions{
   175  				MentionedUserIds: map[string]bool{
   176  					id1: true,
   177  				},
   178  			},
   179  		},
   180  		"MultiplePeopleWithMultipleWords": {
   181  			Message:  "this is an @mention for @user",
   182  			Keywords: map[string][]string{"@user": {id1}, "@mention": {id2}},
   183  			Expected: &ExplicitMentions{
   184  				MentionedUserIds: map[string]bool{
   185  					id1: true,
   186  					id2: true,
   187  				},
   188  			},
   189  		},
   190  		"Channel": {
   191  			Message:  "this is an message for @channel",
   192  			Keywords: map[string][]string{"@channel": {id1, id2}},
   193  			Expected: &ExplicitMentions{
   194  				MentionedUserIds: map[string]bool{
   195  					id1: true,
   196  					id2: true,
   197  				},
   198  				ChannelMentioned: true,
   199  			},
   200  		},
   201  
   202  		"ChannelWithColonAtEnd": {
   203  			Message:  "this is a message for @channel:",
   204  			Keywords: map[string][]string{"@channel": {id1, id2}},
   205  			Expected: &ExplicitMentions{
   206  				MentionedUserIds: map[string]bool{
   207  					id1: true,
   208  					id2: true,
   209  				},
   210  				ChannelMentioned: true,
   211  			},
   212  		},
   213  		"CapitalizedChannel": {
   214  			Message:  "this is an message for @cHaNNeL",
   215  			Keywords: map[string][]string{"@channel": {id1, id2}},
   216  			Expected: &ExplicitMentions{
   217  				MentionedUserIds: map[string]bool{
   218  					id1: true,
   219  					id2: true,
   220  				},
   221  				ChannelMentioned: true,
   222  			},
   223  		},
   224  		"All": {
   225  			Message:  "this is an message for @all",
   226  			Keywords: map[string][]string{"@all": {id1, id2}},
   227  			Expected: &ExplicitMentions{
   228  				MentionedUserIds: map[string]bool{
   229  					id1: true,
   230  					id2: true,
   231  				},
   232  				AllMentioned: true,
   233  			},
   234  		},
   235  		"AllWithColonAtEnd": {
   236  			Message:  "this is a message for @all:",
   237  			Keywords: map[string][]string{"@all": {id1, id2}},
   238  			Expected: &ExplicitMentions{
   239  				MentionedUserIds: map[string]bool{
   240  					id1: true,
   241  					id2: true,
   242  				},
   243  				AllMentioned: true,
   244  			},
   245  		},
   246  		"CapitalizedAll": {
   247  			Message:  "this is an message for @ALL",
   248  			Keywords: map[string][]string{"@all": {id1, id2}},
   249  			Expected: &ExplicitMentions{
   250  				MentionedUserIds: map[string]bool{
   251  					id1: true,
   252  					id2: true,
   253  				},
   254  				AllMentioned: true,
   255  			},
   256  		},
   257  		"UserWithPeriod": {
   258  			Message:  "user.period doesn't complicate things at all by including periods in their username",
   259  			Keywords: map[string][]string{"user.period": {id1}, "user": {id2}},
   260  			Expected: &ExplicitMentions{
   261  				MentionedUserIds: map[string]bool{
   262  					id1: true,
   263  				},
   264  			},
   265  		},
   266  		"AtUserWithColonAtEnd": {
   267  			Message:  "this is a message for @user:",
   268  			Keywords: map[string][]string{"@user": {id1}},
   269  			Expected: &ExplicitMentions{
   270  				MentionedUserIds: map[string]bool{
   271  					id1: true,
   272  				},
   273  			},
   274  		},
   275  		"AtUserWithPeriodAtEndOfSentence": {
   276  			Message:  "this is a message for @user.period.",
   277  			Keywords: map[string][]string{"@user.period": {id1}},
   278  			Expected: &ExplicitMentions{
   279  				MentionedUserIds: map[string]bool{
   280  					id1: true,
   281  				},
   282  			},
   283  		},
   284  		"UserWithPeriodAtEndOfSentence": {
   285  			Message:  "this is a message for user.period.",
   286  			Keywords: map[string][]string{"user.period": {id1}},
   287  			Expected: &ExplicitMentions{
   288  				MentionedUserIds: map[string]bool{
   289  					id1: true,
   290  				},
   291  			},
   292  		},
   293  		"UserWithColonAtEnd": {
   294  			Message:  "this is a message for user:",
   295  			Keywords: map[string][]string{"user": {id1}},
   296  			Expected: &ExplicitMentions{
   297  				MentionedUserIds: map[string]bool{
   298  					id1: true,
   299  				},
   300  			},
   301  		},
   302  		"PotentialOutOfChannelUser": {
   303  			Message:  "this is an message for @potential and @user",
   304  			Keywords: map[string][]string{"@user": {id1}},
   305  			Expected: &ExplicitMentions{
   306  				MentionedUserIds: map[string]bool{
   307  					id1: true,
   308  				},
   309  				OtherPotentialMentions: []string{"potential"},
   310  			},
   311  		},
   312  		"PotentialOutOfChannelUserWithPeriod": {
   313  			Message: "this is an message for @potential.user",
   314  			Expected: &ExplicitMentions{
   315  				OtherPotentialMentions: []string{"potential.user"},
   316  			},
   317  		},
   318  		"InlineCode": {
   319  			Message:  "`this shouldn't mention @channel at all`",
   320  			Keywords: map[string][]string{},
   321  			Expected: &ExplicitMentions{},
   322  		},
   323  		"FencedCodeBlock": {
   324  			Message:  "```\nthis shouldn't mention @channel at all\n```",
   325  			Keywords: map[string][]string{},
   326  			Expected: &ExplicitMentions{},
   327  		},
   328  		"Emphasis": {
   329  			Message:  "*@aaa @bbb @ccc*",
   330  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   331  			Expected: &ExplicitMentions{
   332  				MentionedUserIds: map[string]bool{
   333  					id1: true,
   334  					id2: true,
   335  					id3: true,
   336  				},
   337  			},
   338  		},
   339  		"StrongEmphasis": {
   340  			Message:  "**@aaa @bbb @ccc**",
   341  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   342  			Expected: &ExplicitMentions{
   343  				MentionedUserIds: map[string]bool{
   344  					id1: true,
   345  					id2: true,
   346  					id3: true,
   347  				},
   348  			},
   349  		},
   350  		"Strikethrough": {
   351  			Message:  "~~@aaa @bbb @ccc~~",
   352  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   353  			Expected: &ExplicitMentions{
   354  				MentionedUserIds: map[string]bool{
   355  					id1: true,
   356  					id2: true,
   357  					id3: true,
   358  				},
   359  			},
   360  		},
   361  		"Heading": {
   362  			Message:  "### @aaa",
   363  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   364  			Expected: &ExplicitMentions{
   365  				MentionedUserIds: map[string]bool{
   366  					id1: true,
   367  				},
   368  			},
   369  		},
   370  		"BlockQuote": {
   371  			Message:  "> @aaa",
   372  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   373  			Expected: &ExplicitMentions{
   374  				MentionedUserIds: map[string]bool{
   375  					id1: true,
   376  				},
   377  			},
   378  		},
   379  		"Emoji": {
   380  			Message:  ":smile:",
   381  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   382  			Expected: &ExplicitMentions{},
   383  		},
   384  		"NotEmoji": {
   385  			Message:  "smile",
   386  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   387  			Expected: &ExplicitMentions{
   388  				MentionedUserIds: map[string]bool{
   389  					id1: true,
   390  				},
   391  			},
   392  		},
   393  		"UnclosedEmoji": {
   394  			Message:  ":smile",
   395  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   396  			Expected: &ExplicitMentions{
   397  				MentionedUserIds: map[string]bool{
   398  					id1: true,
   399  				},
   400  			},
   401  		},
   402  		"UnopenedEmoji": {
   403  			Message:  "smile:",
   404  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   405  			Expected: &ExplicitMentions{
   406  				MentionedUserIds: map[string]bool{
   407  					id1: true,
   408  				},
   409  			},
   410  		},
   411  		"IndentedCodeBlock": {
   412  			Message:  "    this shouldn't mention @channel at all",
   413  			Keywords: map[string][]string{},
   414  			Expected: &ExplicitMentions{},
   415  		},
   416  		"LinkTitle": {
   417  			Message:  `[foo](this "shouldn't mention @channel at all")`,
   418  			Keywords: map[string][]string{},
   419  			Expected: &ExplicitMentions{},
   420  		},
   421  		"MalformedInlineCode": {
   422  			Message:  "`this should mention @channel``",
   423  			Keywords: map[string][]string{},
   424  			Expected: &ExplicitMentions{
   425  				ChannelMentioned: true,
   426  			},
   427  		},
   428  
   429  		// The following tests cover cases where the message mentions @user.name, so we shouldn't assume that
   430  		// the user might be intending to mention some @user that isn't in the channel.
   431  		"Don't include potential mention that's part of an actual mention (without trailing period)": {
   432  			Message:  "this is an message for @user.name",
   433  			Keywords: map[string][]string{"@user.name": {id1}},
   434  			Expected: &ExplicitMentions{
   435  				MentionedUserIds: map[string]bool{
   436  					id1: true,
   437  				},
   438  			},
   439  		},
   440  		"Don't include potential mention that's part of an actual mention (with trailing period)": {
   441  			Message:  "this is an message for @user.name.",
   442  			Keywords: map[string][]string{"@user.name": {id1}},
   443  			Expected: &ExplicitMentions{
   444  				MentionedUserIds: map[string]bool{
   445  					id1: true,
   446  				},
   447  			},
   448  		},
   449  		"Don't include potential mention that's part of an actual mention (with multiple trailing periods)": {
   450  			Message:  "this is an message for @user.name...",
   451  			Keywords: map[string][]string{"@user.name": {id1}},
   452  			Expected: &ExplicitMentions{
   453  				MentionedUserIds: map[string]bool{
   454  					id1: true,
   455  				},
   456  			},
   457  		},
   458  		"Don't include potential mention that's part of an actual mention (containing and followed by multiple periods)": {
   459  			Message:  "this is an message for @user...name...",
   460  			Keywords: map[string][]string{"@user...name": {id1}},
   461  			Expected: &ExplicitMentions{
   462  				MentionedUserIds: map[string]bool{
   463  					id1: true,
   464  				},
   465  			},
   466  		},
   467  	} {
   468  		t.Run(name, func(t *testing.T) {
   469  			m := GetExplicitMentions(tc.Message, tc.Keywords)
   470  			if tc.Expected.MentionedUserIds == nil {
   471  				tc.Expected.MentionedUserIds = make(map[string]bool)
   472  			}
   473  			assert.EqualValues(t, tc.Expected, m)
   474  		})
   475  	}
   476  }
   477  
   478  func TestGetExplicitMentionsAtHere(t *testing.T) {
   479  	// test all the boundary cases that we know can break up terms (and those that we know won't)
   480  	cases := map[string]bool{
   481  		"":          false,
   482  		"here":      false,
   483  		"@here":     true,
   484  		" @here ":   true,
   485  		"\n@here\n": true,
   486  		"!@here!":   true,
   487  		"#@here#":   true,
   488  		"$@here$":   true,
   489  		"%@here%":   true,
   490  		"^@here^":   true,
   491  		"&@here&":   true,
   492  		"*@here*":   true,
   493  		"(@here(":   true,
   494  		")@here)":   true,
   495  		"-@here-":   true,
   496  		"_@here_":   false, // This case shouldn't mention since it would be mentioning "@here_"
   497  		"=@here=":   true,
   498  		"+@here+":   true,
   499  		"[@here[":   true,
   500  		"{@here{":   true,
   501  		"]@here]":   true,
   502  		"}@here}":   true,
   503  		"\\@here\\": true,
   504  		"|@here|":   true,
   505  		";@here;":   true,
   506  		"@here:":    true,
   507  		":@here:":   false, // This case shouldn't trigger a mention since it follows the format of reactions e.g. :word:
   508  		"'@here'":   true,
   509  		"\"@here\"": true,
   510  		",@here,":   true,
   511  		"<@here<":   true,
   512  		".@here.":   true,
   513  		">@here>":   true,
   514  		"/@here/":   true,
   515  		"?@here?":   true,
   516  		"`@here`":   false, // This case shouldn't mention since it's a code block
   517  		"~@here~":   true,
   518  		"@HERE":     true,
   519  		"@hERe":     true,
   520  	}
   521  
   522  	for message, shouldMention := range cases {
   523  		if m := GetExplicitMentions(message, nil); m.HereMentioned && !shouldMention {
   524  			t.Fatalf("shouldn't have mentioned @here with \"%v\"", message)
   525  		} else if !m.HereMentioned && shouldMention {
   526  			t.Fatalf("should've mentioned @here with \"%v\"", message)
   527  		}
   528  	}
   529  
   530  	// mentioning @here and someone
   531  	id := model.NewId()
   532  	if m := GetExplicitMentions("@here @user @potential", map[string][]string{"@user": {id}}); !m.HereMentioned {
   533  		t.Fatal("should've mentioned @here with \"@here @user\"")
   534  	} else if len(m.MentionedUserIds) != 1 || !m.MentionedUserIds[id] {
   535  		t.Fatal("should've mentioned @user with \"@here @user\"")
   536  	} else if len(m.OtherPotentialMentions) > 1 {
   537  		t.Fatal("should've potential mentions for @potential")
   538  	}
   539  }
   540  
   541  func TestGetMentionKeywords(t *testing.T) {
   542  	th := Setup()
   543  	defer th.TearDown()
   544  
   545  	// user with username or custom mentions enabled
   546  	user1 := &model.User{
   547  		Id:        model.NewId(),
   548  		FirstName: "First",
   549  		Username:  "User",
   550  		NotifyProps: map[string]string{
   551  			"mention_keys": "User,@User,MENTION",
   552  		},
   553  	}
   554  
   555  	profiles := map[string]*model.User{user1.Id: user1}
   556  	mentions := th.App.GetMentionKeywordsInChannel(profiles, true)
   557  	if len(mentions) != 3 {
   558  		t.Fatal("should've returned three mention keywords")
   559  	} else if ids, ok := mentions["user"]; !ok || ids[0] != user1.Id {
   560  		t.Fatal("should've returned mention key of user")
   561  	} else if ids, ok := mentions["@user"]; !ok || ids[0] != user1.Id {
   562  		t.Fatal("should've returned mention key of @user")
   563  	} else if ids, ok := mentions["mention"]; !ok || ids[0] != user1.Id {
   564  		t.Fatal("should've returned mention key of mention")
   565  	}
   566  
   567  	// user with first name mention enabled
   568  	user2 := &model.User{
   569  		Id:        model.NewId(),
   570  		FirstName: "First",
   571  		Username:  "User",
   572  		NotifyProps: map[string]string{
   573  			"first_name": "true",
   574  		},
   575  	}
   576  
   577  	profiles = map[string]*model.User{user2.Id: user2}
   578  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   579  	if len(mentions) != 2 {
   580  		t.Fatal("should've returned two mention keyword")
   581  	} else if ids, ok := mentions["First"]; !ok || ids[0] != user2.Id {
   582  		t.Fatal("should've returned mention key of First")
   583  	}
   584  
   585  	// user with @channel/@all mentions enabled
   586  	user3 := &model.User{
   587  		Id:        model.NewId(),
   588  		FirstName: "First",
   589  		Username:  "User",
   590  		NotifyProps: map[string]string{
   591  			"channel": "true",
   592  		},
   593  	}
   594  
   595  	profiles = map[string]*model.User{user3.Id: user3}
   596  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   597  	if len(mentions) != 3 {
   598  		t.Fatal("should've returned three mention keywords")
   599  	} else if ids, ok := mentions["@channel"]; !ok || ids[0] != user3.Id {
   600  		t.Fatal("should've returned mention key of @channel")
   601  	} else if ids, ok := mentions["@all"]; !ok || ids[0] != user3.Id {
   602  		t.Fatal("should've returned mention key of @all")
   603  	}
   604  
   605  	// user with all types of mentions enabled
   606  	user4 := &model.User{
   607  		Id:        model.NewId(),
   608  		FirstName: "First",
   609  		Username:  "User",
   610  		NotifyProps: map[string]string{
   611  			"mention_keys": "User,@User,MENTION",
   612  			"first_name":   "true",
   613  			"channel":      "true",
   614  		},
   615  	}
   616  
   617  	profiles = map[string]*model.User{user4.Id: user4}
   618  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   619  	if len(mentions) != 6 {
   620  		t.Fatal("should've returned six mention keywords")
   621  	} else if ids, ok := mentions["user"]; !ok || ids[0] != user4.Id {
   622  		t.Fatal("should've returned mention key of user")
   623  	} else if ids, ok := mentions["@user"]; !ok || ids[0] != user4.Id {
   624  		t.Fatal("should've returned mention key of @user")
   625  	} else if ids, ok := mentions["mention"]; !ok || ids[0] != user4.Id {
   626  		t.Fatal("should've returned mention key of mention")
   627  	} else if ids, ok := mentions["First"]; !ok || ids[0] != user4.Id {
   628  		t.Fatal("should've returned mention key of First")
   629  	} else if ids, ok := mentions["@channel"]; !ok || ids[0] != user4.Id {
   630  		t.Fatal("should've returned mention key of @channel")
   631  	} else if ids, ok := mentions["@all"]; !ok || ids[0] != user4.Id {
   632  		t.Fatal("should've returned mention key of @all")
   633  	}
   634  
   635  	dup_count := func(list []string) map[string]int {
   636  
   637  		duplicate_frequency := make(map[string]int)
   638  
   639  		for _, item := range list {
   640  			// check if the item/element exist in the duplicate_frequency map
   641  
   642  			_, exist := duplicate_frequency[item]
   643  
   644  			if exist {
   645  				duplicate_frequency[item] += 1 // increase counter by 1 if already in the map
   646  			} else {
   647  				duplicate_frequency[item] = 1 // else start counting from 1
   648  			}
   649  		}
   650  		return duplicate_frequency
   651  	}
   652  
   653  	// multiple users but no more than MaxNotificationsPerChannel
   654  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxNotificationsPerChannel = 4 })
   655  	profiles = map[string]*model.User{
   656  		user1.Id: user1,
   657  		user2.Id: user2,
   658  		user3.Id: user3,
   659  		user4.Id: user4,
   660  	}
   661  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   662  	if len(mentions) != 6 {
   663  		t.Fatal("should've returned six mention keywords")
   664  	} else if ids, ok := mentions["user"]; !ok || len(ids) != 2 || (ids[0] != user1.Id && ids[1] != user1.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   665  		t.Fatal("should've mentioned user1 and user4 with user")
   666  	} else if ids := dup_count(mentions["@user"]); len(ids) != 4 || (ids[user1.Id] != 2) || (ids[user4.Id] != 2) {
   667  		t.Fatal("should've mentioned user1 and user4 with @user")
   668  	} else if ids, ok := mentions["mention"]; !ok || len(ids) != 2 || (ids[0] != user1.Id && ids[1] != user1.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   669  		t.Fatal("should've mentioned user1 and user4 with mention")
   670  	} else if ids, ok := mentions["First"]; !ok || len(ids) != 2 || (ids[0] != user2.Id && ids[1] != user2.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   671  		t.Fatal("should've mentioned user2 and user4 with First")
   672  	} else if ids, ok := mentions["@channel"]; !ok || len(ids) != 2 || (ids[0] != user3.Id && ids[1] != user3.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   673  		t.Fatal("should've mentioned user3 and user4 with @channel")
   674  	} else if ids, ok := mentions["@all"]; !ok || len(ids) != 2 || (ids[0] != user3.Id && ids[1] != user3.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   675  		t.Fatal("should've mentioned user3 and user4 with @all")
   676  	}
   677  
   678  	// multiple users and more than MaxNotificationsPerChannel
   679  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxNotificationsPerChannel = 3 })
   680  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   681  	if len(mentions) != 4 {
   682  		t.Fatal("should've returned four mention keywords")
   683  	} else if _, ok := mentions["@channel"]; ok {
   684  		t.Fatal("should not have mentioned any user with @channel")
   685  	} else if _, ok := mentions["@all"]; ok {
   686  		t.Fatal("should not have mentioned any user with @all")
   687  	} else if _, ok := mentions["@here"]; ok {
   688  		t.Fatal("should not have mentioned any user with @here")
   689  	}
   690  
   691  	// no special mentions
   692  	profiles = map[string]*model.User{
   693  		user1.Id: user1,
   694  	}
   695  	mentions = th.App.GetMentionKeywordsInChannel(profiles, false)
   696  	if len(mentions) != 3 {
   697  		t.Fatal("should've returned three mention keywords")
   698  	} else if ids, ok := mentions["user"]; !ok || len(ids) != 1 || ids[0] != user1.Id {
   699  		t.Fatal("should've mentioned user1 with user")
   700  	} else if ids, ok := mentions["@user"]; !ok || len(ids) != 2 || ids[0] != user1.Id || ids[1] != user1.Id {
   701  		t.Fatal("should've mentioned user1 twice with @user")
   702  	} else if ids, ok := mentions["mention"]; !ok || len(ids) != 1 || ids[0] != user1.Id {
   703  		t.Fatal("should've mentioned user1 with mention")
   704  	} else if _, ok := mentions["First"]; ok {
   705  		t.Fatal("should not have mentioned user1 with First")
   706  	} else if _, ok := mentions["@channel"]; ok {
   707  		t.Fatal("should not have mentioned any user with @channel")
   708  	} else if _, ok := mentions["@all"]; ok {
   709  		t.Fatal("should not have mentioned any user with @all")
   710  	} else if _, ok := mentions["@here"]; ok {
   711  		t.Fatal("should not have mentioned any user with @here")
   712  	}
   713  }
   714  
   715  func TestDoesNotifyPropsAllowPushNotification(t *testing.T) {
   716  	userNotifyProps := make(map[string]string)
   717  	channelNotifyProps := make(map[string]string)
   718  
   719  	user := &model.User{Id: model.NewId(), Email: "unit@test.com"}
   720  
   721  	post := &model.Post{UserId: user.Id, ChannelId: model.NewId()}
   722  
   723  	// When the post is a System Message
   724  	systemPost := &model.Post{UserId: user.Id, Type: model.POST_JOIN_CHANNEL}
   725  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   726  	user.NotifyProps = userNotifyProps
   727  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, systemPost, false) {
   728  		t.Fatal("Should have returned false")
   729  	}
   730  
   731  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, systemPost, true) {
   732  		t.Fatal("Should have returned false")
   733  	}
   734  
   735  	// When default is ALL and no channel props is set
   736  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   737  		t.Fatal("Should have returned true")
   738  	}
   739  
   740  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   741  		t.Fatal("Should have returned true")
   742  	}
   743  
   744  	// When default is MENTION and no channel props is set
   745  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   746  	user.NotifyProps = userNotifyProps
   747  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   748  		t.Fatal("Should have returned false")
   749  	}
   750  
   751  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   752  		t.Fatal("Should have returned true")
   753  	}
   754  
   755  	// When default is NONE and no channel props is set
   756  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   757  	user.NotifyProps = userNotifyProps
   758  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   759  		t.Fatal("Should have returned false")
   760  	}
   761  
   762  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   763  		t.Fatal("Should have returned false")
   764  	}
   765  
   766  	// WHEN default is ALL and channel is DEFAULT
   767  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   768  	user.NotifyProps = userNotifyProps
   769  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   770  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   771  		t.Fatal("Should have returned true")
   772  	}
   773  
   774  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   775  		t.Fatal("Should have returned true")
   776  	}
   777  
   778  	// WHEN default is MENTION and channel is DEFAULT
   779  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   780  	user.NotifyProps = userNotifyProps
   781  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   782  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   783  		t.Fatal("Should have returned false")
   784  	}
   785  
   786  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   787  		t.Fatal("Should have returned true")
   788  	}
   789  
   790  	// WHEN default is NONE and channel is DEFAULT
   791  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   792  	user.NotifyProps = userNotifyProps
   793  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   794  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   795  		t.Fatal("Should have returned false")
   796  	}
   797  
   798  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   799  		t.Fatal("Should have returned false")
   800  	}
   801  
   802  	// WHEN default is ALL and channel is ALL
   803  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   804  	user.NotifyProps = userNotifyProps
   805  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   806  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   807  		t.Fatal("Should have returned true")
   808  	}
   809  
   810  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   811  		t.Fatal("Should have returned true")
   812  	}
   813  
   814  	// WHEN default is MENTION and channel is ALL
   815  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   816  	user.NotifyProps = userNotifyProps
   817  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   818  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   819  		t.Fatal("Should have returned true")
   820  	}
   821  
   822  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   823  		t.Fatal("Should have returned true")
   824  	}
   825  
   826  	// WHEN default is NONE and channel is ALL
   827  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   828  	user.NotifyProps = userNotifyProps
   829  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   830  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   831  		t.Fatal("Should have returned true")
   832  	}
   833  
   834  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   835  		t.Fatal("Should have returned true")
   836  	}
   837  
   838  	// WHEN default is ALL and channel is MENTION
   839  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   840  	user.NotifyProps = userNotifyProps
   841  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   842  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   843  		t.Fatal("Should have returned false")
   844  	}
   845  
   846  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   847  		t.Fatal("Should have returned true")
   848  	}
   849  
   850  	// WHEN default is MENTION and channel is MENTION
   851  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   852  	user.NotifyProps = userNotifyProps
   853  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   854  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   855  		t.Fatal("Should have returned false")
   856  	}
   857  
   858  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   859  		t.Fatal("Should have returned true")
   860  	}
   861  
   862  	// WHEN default is NONE and channel is MENTION
   863  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   864  	user.NotifyProps = userNotifyProps
   865  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   866  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   867  		t.Fatal("Should have returned false")
   868  	}
   869  
   870  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   871  		t.Fatal("Should have returned true")
   872  	}
   873  
   874  	// WHEN default is ALL and channel is NONE
   875  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   876  	user.NotifyProps = userNotifyProps
   877  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   878  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   879  		t.Fatal("Should have returned false")
   880  	}
   881  
   882  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   883  		t.Fatal("Should have returned false")
   884  	}
   885  
   886  	// WHEN default is MENTION and channel is NONE
   887  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   888  	user.NotifyProps = userNotifyProps
   889  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   890  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   891  		t.Fatal("Should have returned false")
   892  	}
   893  
   894  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   895  		t.Fatal("Should have returned false")
   896  	}
   897  
   898  	// WHEN default is NONE and channel is NONE
   899  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   900  	user.NotifyProps = userNotifyProps
   901  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   902  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   903  		t.Fatal("Should have returned false")
   904  	}
   905  
   906  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   907  		t.Fatal("Should have returned false")
   908  	}
   909  
   910  	// WHEN default is ALL and channel is MUTED
   911  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   912  	user.NotifyProps = userNotifyProps
   913  	channelNotifyProps[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION
   914  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   915  		t.Fatal("Should have returned false")
   916  	}
   917  }
   918  
   919  func TestDoesStatusAllowPushNotification(t *testing.T) {
   920  	userNotifyProps := make(map[string]string)
   921  	userId := model.NewId()
   922  	channelId := model.NewId()
   923  
   924  	offline := &model.Status{UserId: userId, Status: model.STATUS_OFFLINE, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
   925  	away := &model.Status{UserId: userId, Status: model.STATUS_AWAY, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
   926  	online := &model.Status{UserId: userId, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
   927  	dnd := &model.Status{UserId: userId, Status: model.STATUS_DND, Manual: true, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
   928  
   929  	userNotifyProps["push_status"] = model.STATUS_ONLINE
   930  	// WHEN props is ONLINE and user is offline
   931  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
   932  		t.Fatal("Should have been true")
   933  	}
   934  
   935  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
   936  		t.Fatal("Should have been true")
   937  	}
   938  
   939  	// WHEN props is ONLINE and user is away
   940  	if !DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
   941  		t.Fatal("Should have been true")
   942  	}
   943  
   944  	if !DoesStatusAllowPushNotification(userNotifyProps, away, "") {
   945  		t.Fatal("Should have been true")
   946  	}
   947  
   948  	// WHEN props is ONLINE and user is online
   949  	if !DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
   950  		t.Fatal("Should have been true")
   951  	}
   952  
   953  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
   954  		t.Fatal("Should have been false")
   955  	}
   956  
   957  	// WHEN props is ONLINE and user is dnd
   958  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
   959  		t.Fatal("Should have been false")
   960  	}
   961  
   962  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
   963  		t.Fatal("Should have been false")
   964  	}
   965  
   966  	userNotifyProps["push_status"] = model.STATUS_AWAY
   967  	// WHEN props is AWAY and user is offline
   968  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
   969  		t.Fatal("Should have been true")
   970  	}
   971  
   972  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
   973  		t.Fatal("Should have been true")
   974  	}
   975  
   976  	// WHEN props is AWAY and user is away
   977  	if !DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
   978  		t.Fatal("Should have been true")
   979  	}
   980  
   981  	if !DoesStatusAllowPushNotification(userNotifyProps, away, "") {
   982  		t.Fatal("Should have been true")
   983  	}
   984  
   985  	// WHEN props is AWAY and user is online
   986  	if DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
   987  		t.Fatal("Should have been false")
   988  	}
   989  
   990  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
   991  		t.Fatal("Should have been false")
   992  	}
   993  
   994  	// WHEN props is AWAY and user is dnd
   995  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
   996  		t.Fatal("Should have been false")
   997  	}
   998  
   999  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
  1000  		t.Fatal("Should have been false")
  1001  	}
  1002  
  1003  	userNotifyProps["push_status"] = model.STATUS_OFFLINE
  1004  	// WHEN props is OFFLINE and user is offline
  1005  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
  1006  		t.Fatal("Should have been true")
  1007  	}
  1008  
  1009  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
  1010  		t.Fatal("Should have been true")
  1011  	}
  1012  
  1013  	// WHEN props is OFFLINE and user is away
  1014  	if DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
  1015  		t.Fatal("Should have been false")
  1016  	}
  1017  
  1018  	if DoesStatusAllowPushNotification(userNotifyProps, away, "") {
  1019  		t.Fatal("Should have been false")
  1020  	}
  1021  
  1022  	// WHEN props is OFFLINE and user is online
  1023  	if DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
  1024  		t.Fatal("Should have been false")
  1025  	}
  1026  
  1027  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
  1028  		t.Fatal("Should have been false")
  1029  	}
  1030  
  1031  	// WHEN props is OFFLINE and user is dnd
  1032  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
  1033  		t.Fatal("Should have been false")
  1034  	}
  1035  
  1036  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
  1037  		t.Fatal("Should have been false")
  1038  	}
  1039  
  1040  }
  1041  
  1042  func TestGetDirectMessageNotificationEmailSubject(t *testing.T) {
  1043  	th := Setup()
  1044  	defer th.TearDown()
  1045  
  1046  	expectedPrefix := "[http://localhost:8065] New Direct Message from sender on"
  1047  	post := &model.Post{
  1048  		CreateAt: 1501804801000,
  1049  	}
  1050  	translateFunc := utils.GetUserTranslations("en")
  1051  	subject := getDirectMessageNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "sender")
  1052  	if !strings.HasPrefix(subject, expectedPrefix) {
  1053  		t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
  1054  	}
  1055  }
  1056  
  1057  func TestGetNotificationEmailSubject(t *testing.T) {
  1058  	th := Setup()
  1059  	defer th.TearDown()
  1060  
  1061  	expectedPrefix := "[http://localhost:8065] Notification in team on"
  1062  	post := &model.Post{
  1063  		CreateAt: 1501804801000,
  1064  	}
  1065  	translateFunc := utils.GetUserTranslations("en")
  1066  	subject := getNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "team")
  1067  	if !strings.HasPrefix(subject, expectedPrefix) {
  1068  		t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
  1069  	}
  1070  }
  1071  
  1072  func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) {
  1073  	th := Setup()
  1074  	defer th.TearDown()
  1075  
  1076  	recipient := &model.User{}
  1077  	post := &model.Post{
  1078  		Message: "This is the message",
  1079  	}
  1080  	channel := &model.Channel{
  1081  		DisplayName: "ChannelName",
  1082  		Type:        model.CHANNEL_OPEN,
  1083  	}
  1084  	senderName := "sender"
  1085  	teamName := "team"
  1086  	teamURL := "http://localhost:8065/" + teamName
  1087  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1088  	translateFunc := utils.GetUserTranslations("en")
  1089  
  1090  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1091  	if !strings.Contains(body, "You have a new notification.") {
  1092  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1093  	}
  1094  	if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1095  		t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1096  	}
  1097  	if !strings.Contains(body, senderName+" - ") {
  1098  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1099  	}
  1100  	if !strings.Contains(body, post.Message) {
  1101  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1102  	}
  1103  	if !strings.Contains(body, teamURL) {
  1104  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1105  	}
  1106  }
  1107  
  1108  func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
  1109  	th := Setup()
  1110  	defer th.TearDown()
  1111  
  1112  	recipient := &model.User{}
  1113  	post := &model.Post{
  1114  		Message: "This is the message",
  1115  	}
  1116  	channel := &model.Channel{
  1117  		DisplayName: "ChannelName",
  1118  		Type:        model.CHANNEL_GROUP,
  1119  	}
  1120  	senderName := "sender"
  1121  	teamName := "team"
  1122  	teamURL := "http://localhost:8065/" + teamName
  1123  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1124  	translateFunc := utils.GetUserTranslations("en")
  1125  
  1126  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1127  	if !strings.Contains(body, "You have a new notification.") {
  1128  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1129  	}
  1130  	if !strings.Contains(body, "CHANNEL: Group Message") {
  1131  		t.Fatal("Expected email text 'CHANNEL: Group Message'. Got " + body)
  1132  	}
  1133  	if !strings.Contains(body, senderName+" - ") {
  1134  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1135  	}
  1136  	if !strings.Contains(body, post.Message) {
  1137  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1138  	}
  1139  	if !strings.Contains(body, teamURL) {
  1140  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1141  	}
  1142  }
  1143  
  1144  func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
  1145  	th := Setup()
  1146  	defer th.TearDown()
  1147  
  1148  	recipient := &model.User{}
  1149  	post := &model.Post{
  1150  		Message: "This is the message",
  1151  	}
  1152  	channel := &model.Channel{
  1153  		DisplayName: "ChannelName",
  1154  		Type:        model.CHANNEL_PRIVATE,
  1155  	}
  1156  	senderName := "sender"
  1157  	teamName := "team"
  1158  	teamURL := "http://localhost:8065/" + teamName
  1159  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1160  	translateFunc := utils.GetUserTranslations("en")
  1161  
  1162  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1163  	if !strings.Contains(body, "You have a new notification.") {
  1164  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1165  	}
  1166  	if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1167  		t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1168  	}
  1169  	if !strings.Contains(body, senderName+" - ") {
  1170  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1171  	}
  1172  	if !strings.Contains(body, post.Message) {
  1173  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1174  	}
  1175  	if !strings.Contains(body, teamURL) {
  1176  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1177  	}
  1178  }
  1179  
  1180  func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
  1181  	th := Setup()
  1182  	defer th.TearDown()
  1183  
  1184  	recipient := &model.User{}
  1185  	post := &model.Post{
  1186  		Message: "This is the message",
  1187  	}
  1188  	channel := &model.Channel{
  1189  		DisplayName: "ChannelName",
  1190  		Type:        model.CHANNEL_DIRECT,
  1191  	}
  1192  	senderName := "sender"
  1193  	teamName := "team"
  1194  	teamURL := "http://localhost:8065/" + teamName
  1195  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1196  	translateFunc := utils.GetUserTranslations("en")
  1197  
  1198  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1199  	if !strings.Contains(body, "You have a new direct message.") {
  1200  		t.Fatal("Expected email text 'You have a new direct message. Got " + body)
  1201  	}
  1202  	if !strings.Contains(body, senderName+" - ") {
  1203  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1204  	}
  1205  	if !strings.Contains(body, post.Message) {
  1206  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1207  	}
  1208  	if !strings.Contains(body, teamURL) {
  1209  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1210  	}
  1211  }
  1212  
  1213  // from here
  1214  func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T) {
  1215  	th := Setup()
  1216  	defer th.TearDown()
  1217  
  1218  	recipient := &model.User{}
  1219  	post := &model.Post{
  1220  		Message: "This is the message",
  1221  	}
  1222  	channel := &model.Channel{
  1223  		DisplayName: "ChannelName",
  1224  		Type:        model.CHANNEL_OPEN,
  1225  	}
  1226  	senderName := "sender"
  1227  	teamName := "team"
  1228  	teamURL := "http://localhost:8065/" + teamName
  1229  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1230  	translateFunc := utils.GetUserTranslations("en")
  1231  
  1232  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1233  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1234  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1235  	}
  1236  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1237  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1238  	}
  1239  	if strings.Contains(body, post.Message) {
  1240  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1241  	}
  1242  	if !strings.Contains(body, teamURL) {
  1243  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1244  	}
  1245  }
  1246  
  1247  func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
  1248  	th := Setup()
  1249  	defer th.TearDown()
  1250  
  1251  	recipient := &model.User{}
  1252  	post := &model.Post{
  1253  		Message: "This is the message",
  1254  	}
  1255  	channel := &model.Channel{
  1256  		DisplayName: "ChannelName",
  1257  		Type:        model.CHANNEL_GROUP,
  1258  	}
  1259  	senderName := "sender"
  1260  	teamName := "team"
  1261  	teamURL := "http://localhost:8065/" + teamName
  1262  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1263  	translateFunc := utils.GetUserTranslations("en")
  1264  
  1265  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1266  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1267  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1268  	}
  1269  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1270  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1271  	}
  1272  	if strings.Contains(body, post.Message) {
  1273  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1274  	}
  1275  	if !strings.Contains(body, teamURL) {
  1276  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1277  	}
  1278  }
  1279  
  1280  func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T) {
  1281  	th := Setup()
  1282  	defer th.TearDown()
  1283  
  1284  	recipient := &model.User{}
  1285  	post := &model.Post{
  1286  		Message: "This is the message",
  1287  	}
  1288  	channel := &model.Channel{
  1289  		DisplayName: "ChannelName",
  1290  		Type:        model.CHANNEL_PRIVATE,
  1291  	}
  1292  	senderName := "sender"
  1293  	teamName := "team"
  1294  	teamURL := "http://localhost:8065/" + teamName
  1295  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1296  	translateFunc := utils.GetUserTranslations("en")
  1297  
  1298  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1299  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1300  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1301  	}
  1302  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1303  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1304  	}
  1305  	if strings.Contains(body, post.Message) {
  1306  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1307  	}
  1308  	if !strings.Contains(body, teamURL) {
  1309  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1310  	}
  1311  }
  1312  
  1313  func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T) {
  1314  	th := Setup()
  1315  	defer th.TearDown()
  1316  
  1317  	recipient := &model.User{}
  1318  	post := &model.Post{
  1319  		Message: "This is the message",
  1320  	}
  1321  	channel := &model.Channel{
  1322  		DisplayName: "ChannelName",
  1323  		Type:        model.CHANNEL_DIRECT,
  1324  	}
  1325  	senderName := "sender"
  1326  	teamName := "team"
  1327  	teamURL := "http://localhost:8065/" + teamName
  1328  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1329  	translateFunc := utils.GetUserTranslations("en")
  1330  
  1331  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1332  	if !strings.Contains(body, "You have a new direct message from "+senderName) {
  1333  		t.Fatal("Expected email text 'You have a new direct message from " + senderName + "'. Got " + body)
  1334  	}
  1335  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1336  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1337  	}
  1338  	if strings.Contains(body, post.Message) {
  1339  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1340  	}
  1341  	if !strings.Contains(body, teamURL) {
  1342  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1343  	}
  1344  }
  1345  
  1346  func TestGetPushNotificationMessage(t *testing.T) {
  1347  	th := Setup()
  1348  	defer th.TearDown()
  1349  
  1350  	for name, tc := range map[string]struct {
  1351  		Message                  string
  1352  		WasMentioned             bool
  1353  		HasFiles                 bool
  1354  		Locale                   string
  1355  		PushNotificationContents string
  1356  		ChannelType              string
  1357  
  1358  		ExpectedMessage  string
  1359  		ExpectedCategory string
  1360  	}{
  1361  		"full message, public channel, no mention": {
  1362  			Message:          "this is a message",
  1363  			ChannelType:      model.CHANNEL_OPEN,
  1364  			ExpectedMessage:  "user in channel: this is a message",
  1365  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1366  		},
  1367  		"full message, public channel, mention": {
  1368  			Message:          "this is a message",
  1369  			WasMentioned:     true,
  1370  			ChannelType:      model.CHANNEL_OPEN,
  1371  			ExpectedMessage:  "user in channel: this is a message",
  1372  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1373  		},
  1374  		"full message, private channel, no mention": {
  1375  			Message:          "this is a message",
  1376  			ChannelType:      model.CHANNEL_PRIVATE,
  1377  			ExpectedMessage:  "user in channel: this is a message",
  1378  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1379  		},
  1380  		"full message, private channel, mention": {
  1381  			Message:          "this is a message",
  1382  			WasMentioned:     true,
  1383  			ChannelType:      model.CHANNEL_PRIVATE,
  1384  			ExpectedMessage:  "user in channel: this is a message",
  1385  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1386  		},
  1387  		"full message, group message channel, no mention": {
  1388  			Message:          "this is a message",
  1389  			ChannelType:      model.CHANNEL_GROUP,
  1390  			ExpectedMessage:  "user in channel: this is a message",
  1391  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1392  		},
  1393  		"full message, group message channel, mention": {
  1394  			Message:          "this is a message",
  1395  			WasMentioned:     true,
  1396  			ChannelType:      model.CHANNEL_GROUP,
  1397  			ExpectedMessage:  "user in channel: this is a message",
  1398  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1399  		},
  1400  		"full message, direct message channel, no mention": {
  1401  			Message:          "this is a message",
  1402  			ChannelType:      model.CHANNEL_DIRECT,
  1403  			ExpectedMessage:  "user: this is a message",
  1404  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1405  		},
  1406  		"full message, direct message channel, mention": {
  1407  			Message:          "this is a message",
  1408  			WasMentioned:     true,
  1409  			ChannelType:      model.CHANNEL_DIRECT,
  1410  			ExpectedMessage:  "user: this is a message",
  1411  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1412  		},
  1413  		"generic message with channel, public channel, no mention": {
  1414  			Message:                  "this is a message",
  1415  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1416  			ChannelType:              model.CHANNEL_OPEN,
  1417  			ExpectedMessage:          "user posted in channel",
  1418  		},
  1419  		"generic message with channel, public channel, mention": {
  1420  			Message:                  "this is a message",
  1421  			WasMentioned:             true,
  1422  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1423  			ChannelType:              model.CHANNEL_OPEN,
  1424  			ExpectedMessage:          "user mentioned you in channel",
  1425  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1426  		},
  1427  		"generic message with channel, private channel, no mention": {
  1428  			Message:                  "this is a message",
  1429  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1430  			ChannelType:              model.CHANNEL_PRIVATE,
  1431  			ExpectedMessage:          "user posted in channel",
  1432  		},
  1433  		"generic message with channel, private channel, mention": {
  1434  			Message:                  "this is a message",
  1435  			WasMentioned:             true,
  1436  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1437  			ChannelType:              model.CHANNEL_PRIVATE,
  1438  			ExpectedMessage:          "user mentioned you in channel",
  1439  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1440  		},
  1441  		"generic message with channel, group message channel, no mention": {
  1442  			Message:                  "this is a message",
  1443  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1444  			ChannelType:              model.CHANNEL_GROUP,
  1445  			ExpectedMessage:          "user posted in channel",
  1446  		},
  1447  		"generic message with channel, group message channel, mention": {
  1448  			Message:                  "this is a message",
  1449  			WasMentioned:             true,
  1450  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1451  			ChannelType:              model.CHANNEL_GROUP,
  1452  			ExpectedMessage:          "user mentioned you in channel",
  1453  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1454  		},
  1455  		"generic message with channel, direct message channel, no mention": {
  1456  			Message:                  "this is a message",
  1457  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1458  			ChannelType:              model.CHANNEL_DIRECT,
  1459  			ExpectedMessage:          "user sent you a direct message",
  1460  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1461  		},
  1462  		"generic message with channel, direct message channel, mention": {
  1463  			Message:                  "this is a message",
  1464  			WasMentioned:             true,
  1465  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1466  			ChannelType:              model.CHANNEL_DIRECT,
  1467  			ExpectedMessage:          "user sent you a direct message",
  1468  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1469  		},
  1470  		"generic message without channel, public channel, no mention": {
  1471  			Message:                  "this is a message",
  1472  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1473  			ChannelType:              model.CHANNEL_OPEN,
  1474  			ExpectedMessage:          "user posted a message",
  1475  		},
  1476  		"generic message without channel, public channel, mention": {
  1477  			Message:                  "this is a message",
  1478  			WasMentioned:             true,
  1479  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1480  			ChannelType:              model.CHANNEL_OPEN,
  1481  			ExpectedMessage:          "user mentioned you",
  1482  		},
  1483  		"generic message without channel, private channel, no mention": {
  1484  			Message:                  "this is a message",
  1485  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1486  			ChannelType:              model.CHANNEL_PRIVATE,
  1487  			ExpectedMessage:          "user posted a message",
  1488  		},
  1489  		"generic message without channel, private channel, mention": {
  1490  			Message:                  "this is a message",
  1491  			WasMentioned:             true,
  1492  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1493  			ChannelType:              model.CHANNEL_PRIVATE,
  1494  			ExpectedMessage:          "user mentioned you",
  1495  		},
  1496  		"generic message without channel, group message channel, no mention": {
  1497  			Message:                  "this is a message",
  1498  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1499  			ChannelType:              model.CHANNEL_GROUP,
  1500  			ExpectedMessage:          "user posted a message",
  1501  		},
  1502  		"generic message without channel, group message channel, mention": {
  1503  			Message:                  "this is a message",
  1504  			WasMentioned:             true,
  1505  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1506  			ChannelType:              model.CHANNEL_GROUP,
  1507  			ExpectedMessage:          "user mentioned you",
  1508  		},
  1509  		"generic message without channel, direct message channel, no mention": {
  1510  			Message:                  "this is a message",
  1511  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1512  			ChannelType:              model.CHANNEL_DIRECT,
  1513  			ExpectedMessage:          "user sent you a direct message",
  1514  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1515  		},
  1516  		"generic message without channel, direct message channel, mention": {
  1517  			Message:                  "this is a message",
  1518  			WasMentioned:             true,
  1519  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1520  			ChannelType:              model.CHANNEL_DIRECT,
  1521  			ExpectedMessage:          "user sent you a direct message",
  1522  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1523  		},
  1524  		"only files, public channel": {
  1525  			HasFiles:         true,
  1526  			ChannelType:      model.CHANNEL_OPEN,
  1527  			ExpectedMessage:  "user uploaded one or more files in channel",
  1528  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1529  		},
  1530  		"only files, private channel": {
  1531  			HasFiles:         true,
  1532  			ChannelType:      model.CHANNEL_PRIVATE,
  1533  			ExpectedMessage:  "user uploaded one or more files in channel",
  1534  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1535  		},
  1536  		"only files, group message channel": {
  1537  			HasFiles:         true,
  1538  			ChannelType:      model.CHANNEL_GROUP,
  1539  			ExpectedMessage:  "user uploaded one or more files in channel",
  1540  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1541  		},
  1542  		"only files, direct message channel": {
  1543  			HasFiles:         true,
  1544  			ChannelType:      model.CHANNEL_DIRECT,
  1545  			ExpectedMessage:  "user uploaded one or more files in a direct message",
  1546  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1547  		},
  1548  		"only files without channel, public channel": {
  1549  			HasFiles:                 true,
  1550  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1551  			ChannelType:              model.CHANNEL_OPEN,
  1552  			ExpectedMessage:          "user uploaded one or more files",
  1553  		},
  1554  	} {
  1555  		t.Run(name, func(t *testing.T) {
  1556  			locale := tc.Locale
  1557  			if locale == "" {
  1558  				locale = "en"
  1559  			}
  1560  
  1561  			pushNotificationContents := tc.PushNotificationContents
  1562  			if pushNotificationContents == "" {
  1563  				pushNotificationContents = model.FULL_NOTIFICATION
  1564  			}
  1565  
  1566  			th.App.UpdateConfig(func(cfg *model.Config) {
  1567  				*cfg.EmailSettings.PushNotificationContents = pushNotificationContents
  1568  			})
  1569  
  1570  			if actualMessage, actualCategory := th.App.getPushNotificationMessage(
  1571  				tc.Message,
  1572  				tc.WasMentioned,
  1573  				tc.HasFiles,
  1574  				"user",
  1575  				"channel",
  1576  				tc.ChannelType,
  1577  				utils.GetUserTranslations(locale),
  1578  			); actualMessage != tc.ExpectedMessage {
  1579  				t.Fatalf("Received incorrect push notification message `%v`, expected `%v`", actualMessage, tc.ExpectedMessage)
  1580  			} else if actualCategory != tc.ExpectedCategory {
  1581  				t.Fatalf("Received incorrect push notification category `%v`, expected `%v`", actualCategory, tc.ExpectedCategory)
  1582  			}
  1583  		})
  1584  	}
  1585  }