summaryrefslogtreecommitdiffstats
path: root/store/storetest
diff options
context:
space:
mode:
authorChris <ccbrown112@gmail.com>2017-10-06 11:08:59 -0700
committerGitHub <noreply@github.com>2017-10-06 11:08:59 -0700
commit70e5f00241473c27a3008959ce08832c75e76ba8 (patch)
tree3afd074964c9220cc4a87210286a13dfd38c61d0 /store/storetest
parentd1958bdc49cd10277ca2e27bb2eea499c5994954 (diff)
downloadchat-70e5f00241473c27a3008959ce08832c75e76ba8.tar.gz
chat-70e5f00241473c27a3008959ce08832c75e76ba8.tar.bz2
chat-70e5f00241473c27a3008959ce08832c75e76ba8.zip
store/storetest package (#7588)
* prerequisites * storetest package
Diffstat (limited to 'store/storetest')
-rw-r--r--store/storetest/audit_store.go91
-rw-r--r--store/storetest/channel_store.go1967
-rw-r--r--store/storetest/cluster_discovery_store.go200
-rw-r--r--store/storetest/command_store.go251
-rw-r--r--store/storetest/command_webhook_store.go68
-rw-r--r--store/storetest/compliance_store.go318
-rw-r--r--store/storetest/emoji_store.go175
-rw-r--r--store/storetest/file_info_store.go296
-rw-r--r--store/storetest/job_store.go507
-rw-r--r--store/storetest/license_store.go56
-rw-r--r--store/storetest/oauth_store.go435
-rw-r--r--store/storetest/post_store.go1684
-rw-r--r--store/storetest/preference_store.go447
-rw-r--r--store/storetest/reaction_store.go350
-rw-r--r--store/storetest/session_store.go250
-rw-r--r--store/storetest/status_store.go106
-rw-r--r--store/storetest/system_store.go58
-rw-r--r--store/storetest/team_store.go1010
-rw-r--r--store/storetest/user_access_token_store.go89
-rw-r--r--store/storetest/user_store.go2074
-rw-r--r--store/storetest/webhook_store.go507
21 files changed, 10939 insertions, 0 deletions
diff --git a/store/storetest/audit_store.go b/store/storetest/audit_store.go
new file mode 100644
index 000000000..2e107dba8
--- /dev/null
+++ b/store/storetest/audit_store.go
@@ -0,0 +1,91 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestAuditStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testAuditStore(t, ss) })
+ t.Run("PermanentDeleteBatch", func(t *testing.T) { testAuditStorePermanentDeleteBatch(t, ss) })
+}
+
+func testAuditStore(t *testing.T, ss store.Store) {
+ audit := &model.Audit{UserId: model.NewId(), IpAddress: "ipaddress", Action: "Action"}
+ store.Must(ss.Audit().Save(audit))
+ time.Sleep(100 * time.Millisecond)
+ store.Must(ss.Audit().Save(audit))
+ time.Sleep(100 * time.Millisecond)
+ store.Must(ss.Audit().Save(audit))
+ time.Sleep(100 * time.Millisecond)
+ audit.ExtraInfo = "extra"
+ time.Sleep(100 * time.Millisecond)
+ store.Must(ss.Audit().Save(audit))
+
+ time.Sleep(100 * time.Millisecond)
+
+ c := ss.Audit().Get(audit.UserId, 0, 100)
+ result := <-c
+ audits := result.Data.(model.Audits)
+
+ if len(audits) != 4 {
+ t.Fatal("Failed to save and retrieve 4 audit logs")
+ }
+
+ if audits[0].ExtraInfo != "extra" {
+ t.Fatal("Failed to save property for extra info")
+ }
+
+ c = ss.Audit().Get("missing", 0, 100)
+ result = <-c
+ audits = result.Data.(model.Audits)
+
+ if len(audits) != 0 {
+ t.Fatal("Should have returned empty because user_id is missing")
+ }
+
+ c = ss.Audit().Get("", 0, 100)
+ result = <-c
+ audits = result.Data.(model.Audits)
+
+ if len(audits) < 4 {
+ t.Fatal("Failed to save and retrieve 4 audit logs")
+ }
+
+ if r2 := <-ss.Audit().PermanentDeleteByUser(audit.UserId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+}
+
+func testAuditStorePermanentDeleteBatch(t *testing.T, ss store.Store) {
+ a1 := &model.Audit{UserId: model.NewId(), IpAddress: "ipaddress", Action: "Action"}
+ store.Must(ss.Audit().Save(a1))
+ time.Sleep(10 * time.Millisecond)
+ a2 := &model.Audit{UserId: a1.UserId, IpAddress: "ipaddress", Action: "Action"}
+ store.Must(ss.Audit().Save(a2))
+ time.Sleep(10 * time.Millisecond)
+ cutoff := model.GetMillis()
+ time.Sleep(10 * time.Millisecond)
+ a3 := &model.Audit{UserId: a1.UserId, IpAddress: "ipaddress", Action: "Action"}
+ store.Must(ss.Audit().Save(a3))
+
+ if r := <-ss.Audit().Get(a1.UserId, 0, 100); len(r.Data.(model.Audits)) != 3 {
+ t.Fatal("Expected 3 audits. Got ", len(r.Data.(model.Audits)))
+ }
+
+ store.Must(ss.Audit().PermanentDeleteBatch(cutoff, 1000000))
+
+ if r := <-ss.Audit().Get(a1.UserId, 0, 100); len(r.Data.(model.Audits)) != 1 {
+ t.Fatal("Expected 1 audit. Got ", len(r.Data.(model.Audits)))
+ }
+
+ if r2 := <-ss.Audit().PermanentDeleteByUser(a1.UserId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+}
diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go
new file mode 100644
index 000000000..53d81bdc0
--- /dev/null
+++ b/store/storetest/channel_store.go
@@ -0,0 +1,1967 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestChannelStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testChannelStoreSave(t, ss) })
+ t.Run("SaveDirectChannel", func(t *testing.T) { testChannelStoreSaveDirectChannel(t, ss) })
+ t.Run("CreateDirectChannel", func(t *testing.T) { testChannelStoreCreateDirectChannel(t, ss) })
+ t.Run("Update", func(t *testing.T) { testChannelStoreUpdate(t, ss) })
+ t.Run("GetChannelUnread", func(t *testing.T) { testGetChannelUnread(t, ss) })
+ t.Run("Get", func(t *testing.T) { testChannelStoreGet(t, ss) })
+ t.Run("GetForPost", func(t *testing.T) { testChannelStoreGetForPost(t, ss) })
+ t.Run("Restore", func(t *testing.T) { testChannelStoreRestore(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testChannelStoreDelete(t, ss) })
+ t.Run("GetByName", func(t *testing.T) { testChannelStoreGetByName(t, ss) })
+ t.Run("GetDeletedByName", func(t *testing.T) { testChannelStoreGetDeletedByName(t, ss) })
+ t.Run("GetDeleted", func(t *testing.T) { testChannelStoreGetDeleted(t, ss) })
+ t.Run("ChannelMemberStore", func(t *testing.T) { testChannelMemberStore(t, ss) })
+ t.Run("ChannelDeleteMemberStore", func(t *testing.T) { testChannelDeleteMemberStore(t, ss) })
+ t.Run("GetChannels", func(t *testing.T) { testChannelStoreGetChannels(t, ss) })
+ t.Run("GetMoreChannels", func(t *testing.T) { testChannelStoreGetMoreChannels(t, ss) })
+ t.Run("GetPublicChannelsForTeam", func(t *testing.T) { testChannelStoreGetPublicChannelsForTeam(t, ss) })
+ t.Run("GetPublicChannelsByIdsForTeam", func(t *testing.T) { testChannelStoreGetPublicChannelsByIdsForTeam(t, ss) })
+ t.Run("GetChannelCounts", func(t *testing.T) { testChannelStoreGetChannelCounts(t, ss) })
+ t.Run("GetMembersForUser", func(t *testing.T) { testChannelStoreGetMembersForUser(t, ss) })
+ t.Run("UpdateLastViewedAt", func(t *testing.T) { testChannelStoreUpdateLastViewedAt(t, ss) })
+ t.Run("IncrementMentionCount", func(t *testing.T) { testChannelStoreIncrementMentionCount(t, ss) })
+ t.Run("UpdateChannelMember", func(t *testing.T) { testUpdateChannelMember(t, ss) })
+ t.Run("GetMember", func(t *testing.T) { testGetMember(t, ss) })
+ t.Run("GetMemberForPost", func(t *testing.T) { testChannelStoreGetMemberForPost(t, ss) })
+ t.Run("GetMemberCount", func(t *testing.T) { testGetMemberCount(t, ss) })
+ t.Run("UpdateExtrasByUser", func(t *testing.T) { testUpdateExtrasByUser(t, ss) })
+ t.Run("SearchMore", func(t *testing.T) { testChannelStoreSearchMore(t, ss) })
+ t.Run("SearchInTeam", func(t *testing.T) { testChannelStoreSearchInTeam(t, ss) })
+ t.Run("GetMembersByIds", func(t *testing.T) { testChannelStoreGetMembersByIds(t, ss) })
+ t.Run("AnalyticsDeletedTypeCount", func(t *testing.T) { testChannelStoreAnalyticsDeletedTypeCount(t, ss) })
+ t.Run("GetPinnedPosts", func(t *testing.T) { testChannelStoreGetPinnedPosts(t, ss) })
+}
+
+func testChannelStoreSave(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ o1 := model.Channel{}
+ o1.TeamId = teamId
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+
+ if err := (<-ss.Channel().Save(&o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Channel().Save(&o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+
+ o1.Id = ""
+ if err := (<-ss.Channel().Save(&o1)).Err; err == nil {
+ t.Fatal("should be unique name")
+ }
+
+ o1.Id = ""
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_DIRECT
+ if err := (<-ss.Channel().Save(&o1)).Err; err == nil {
+ t.Fatal("Should not be able to save direct channel")
+ }
+}
+
+func testChannelStoreSaveDirectChannel(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ o1 := model.Channel{}
+ o1.TeamId = teamId
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_DIRECT
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ if err := (<-ss.Channel().SaveDirectChannel(&o1, &m1, &m2)).Err; err != nil {
+ t.Fatal("couldn't save direct channel", err)
+ }
+
+ members := (<-ss.Channel().GetMembers(o1.Id, 0, 100)).Data.(*model.ChannelMembers)
+ if len(*members) != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ if err := (<-ss.Channel().SaveDirectChannel(&o1, &m1, &m2)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+
+ // Attempt to save a direct channel that already exists
+ o1a := model.Channel{
+ TeamId: o1.TeamId,
+ DisplayName: o1.DisplayName,
+ Name: o1.Name,
+ Type: o1.Type,
+ }
+
+ if result := <-ss.Channel().SaveDirectChannel(&o1a, &m1, &m2); result.Err == nil {
+ t.Fatal("should've failed to save a duplicate direct channel")
+ } else if result.Err.Id != store.CHANNEL_EXISTS_ERROR {
+ t.Fatal("should've returned CHANNEL_EXISTS_ERROR")
+ } else if returned := result.Data.(*model.Channel); returned.Id != o1.Id {
+ t.Fatal("should've returned original channel when saving a duplicate direct channel")
+ }
+
+ // Attempt to save a non-direct channel
+ o1.Id = ""
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ if err := (<-ss.Channel().SaveDirectChannel(&o1, &m1, &m2)).Err; err == nil {
+ t.Fatal("Should not be able to save non-direct channel")
+ }
+}
+
+func testChannelStoreCreateDirectChannel(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ res := <-ss.Channel().CreateDirectChannel(u1.Id, u2.Id)
+ if res.Err != nil {
+ t.Fatal("couldn't create direct channel", res.Err)
+ }
+
+ c1 := res.Data.(*model.Channel)
+
+ members := (<-ss.Channel().GetMembers(c1.Id, 0, 100)).Data.(*model.ChannelMembers)
+ if len(*members) != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+}
+
+func testChannelStoreUpdate(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = o1.TeamId
+ o2.DisplayName = "Name"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := (<-ss.Channel().Update(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ o1.Id = "missing"
+ if err := (<-ss.Channel().Update(&o1)).Err; err == nil {
+ t.Fatal("Update should have failed because of missing key")
+ }
+
+ o1.Id = model.NewId()
+ if err := (<-ss.Channel().Update(&o1)).Err; err == nil {
+ t.Fatal("Update should have faile because id change")
+ }
+
+ o2.Name = o1.Name
+ if err := (<-ss.Channel().Update(&o2)).Err; err == nil {
+ t.Fatal("Update should have failed because of existing name")
+ }
+}
+
+func testGetChannelUnread(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+ teamId2 := model.NewId()
+
+ uid := model.NewId()
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: uid}
+ m2 := &model.TeamMember{TeamId: teamId2, UserId: uid}
+ store.Must(ss.Team().SaveMember(m1))
+ store.Must(ss.Team().SaveMember(m2))
+ notifyPropsModel := model.GetDefaultChannelNotifyProps()
+
+ // Setup Channel 1
+ c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Downtown", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c1))
+ cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: notifyPropsModel, MsgCount: 90}
+ store.Must(ss.Channel().SaveMember(cm1))
+
+ // Setup Channel 2
+ c2 := &model.Channel{TeamId: m2.TeamId, Name: model.NewId(), DisplayName: "Cultural", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c2))
+ cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m2.UserId, NotifyProps: notifyPropsModel, MsgCount: 90, MentionCount: 5}
+ store.Must(ss.Channel().SaveMember(cm2))
+
+ // Check for Channel 1
+ if resp := <-ss.Channel().GetChannelUnread(c1.Id, uid); resp.Err != nil {
+ t.Fatal(resp.Err)
+ } else {
+ ch := resp.Data.(*model.ChannelUnread)
+ if c1.Id != ch.ChannelId {
+ t.Fatal("wrong channel id")
+ }
+
+ if teamId1 != ch.TeamId {
+ t.Fatal("wrong team id for channel 1")
+ }
+
+ if ch.NotifyProps == nil {
+ t.Fatal("wrong props for channel 1")
+ }
+
+ if ch.MentionCount != 0 {
+ t.Fatal("wrong MentionCount for channel 1")
+ }
+
+ if ch.MsgCount != 10 {
+ t.Fatal("wrong MsgCount for channel 1")
+ }
+ }
+
+ // Check for Channel 2
+ if resp2 := <-ss.Channel().GetChannelUnread(c2.Id, uid); resp2.Err != nil {
+ t.Fatal(resp2.Err)
+ } else {
+ ch2 := resp2.Data.(*model.ChannelUnread)
+ if c2.Id != ch2.ChannelId {
+ t.Fatal("wrong channel id")
+ }
+
+ if teamId2 != ch2.TeamId {
+ t.Fatal("wrong team id")
+ }
+
+ if ch2.MentionCount != 5 {
+ t.Fatal("wrong MentionCount for channel 2")
+ }
+
+ if ch2.MsgCount != 10 {
+ t.Fatal("wrong MsgCount for channel 2")
+ }
+ }
+}
+
+func testChannelStoreGet(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ if r1 := <-ss.Channel().Get(o1.Id, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Channel).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if err := (<-ss.Channel().Get("", false)).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(&u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Direct Name"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_DIRECT
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o2.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o2.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ store.Must(ss.Channel().SaveDirectChannel(&o2, &m1, &m2))
+
+ if r2 := <-ss.Channel().Get(o2.Id, false); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if r2.Data.(*model.Channel).ToJson() != o2.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if r4 := <-ss.Channel().Get(o2.Id, true); r4.Err != nil {
+ t.Fatal(r4.Err)
+ } else {
+ if r4.Data.(*model.Channel).ToJson() != o2.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if r3 := <-ss.Channel().GetAll(o1.TeamId); r3.Err != nil {
+ t.Fatal(r3.Err)
+ } else {
+ channels := r3.Data.([]*model.Channel)
+ if len(channels) == 0 {
+ t.Fatal("too little")
+ }
+ }
+
+ if r3 := <-ss.Channel().GetTeamChannels(o1.TeamId); r3.Err != nil {
+ t.Fatal(r3.Err)
+ } else {
+ channels := r3.Data.(*model.ChannelList)
+ if len(*channels) == 0 {
+ t.Fatal("too little")
+ }
+ }
+}
+
+func testChannelStoreGetForPost(t *testing.T, ss store.Store) {
+ o1 := store.Must(ss.Channel().Save(&model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: "Name",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ })).(*model.Channel)
+
+ p1 := store.Must(ss.Post().Save(&model.Post{
+ UserId: model.NewId(),
+ ChannelId: o1.Id,
+ Message: "test",
+ })).(*model.Post)
+
+ if r1 := <-ss.Channel().GetForPost(p1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else if r1.Data.(*model.Channel).Id != o1.Id {
+ t.Fatal("incorrect channel returned")
+ }
+}
+
+func testChannelStoreRestore(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ if r := <-ss.Channel().Delete(o1.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ if r := <-ss.Channel().Get(o1.Id, false); r.Data.(*model.Channel).DeleteAt == 0 {
+ t.Fatal("should have been deleted")
+ }
+
+ if r := <-ss.Channel().Restore(o1.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ if r := <-ss.Channel().Get(o1.Id, false); r.Data.(*model.Channel).DeleteAt != 0 {
+ t.Fatal("should have been restored")
+ }
+
+}
+
+func testChannelStoreDelete(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = o1.TeamId
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "Channel3"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o3))
+
+ o4 := model.Channel{}
+ o4.TeamId = o1.TeamId
+ o4.DisplayName = "Channel4"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o4))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o2.Id
+ m2.UserId = m1.UserId
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ if r := <-ss.Channel().Delete(o1.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ if r := <-ss.Channel().Get(o1.Id, false); r.Data.(*model.Channel).DeleteAt == 0 {
+ t.Fatal("should have been deleted")
+ }
+
+ if r := <-ss.Channel().Delete(o3.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ cresult := <-ss.Channel().GetChannels(o1.TeamId, m1.UserId)
+ list := cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("invalid number of channels")
+ }
+
+ cresult = <-ss.Channel().GetMoreChannels(o1.TeamId, m1.UserId, 0, 100)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("invalid number of channels")
+ }
+
+ <-ss.Channel().PermanentDelete(o2.Id)
+
+ cresult = <-ss.Channel().GetChannels(o1.TeamId, m1.UserId)
+ t.Log(cresult.Err)
+ if cresult.Err.Id != "store.sql_channel.get_channels.not_found.app_error" {
+ t.Fatal("no channels should be found")
+ }
+
+ if r := <-ss.Channel().PermanentDeleteByTeam(o1.TeamId); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+}
+
+func testChannelStoreGetByName(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ r1 := <-ss.Channel().GetByName(o1.TeamId, o1.Name, true)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Channel).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if err := (<-ss.Channel().GetByName(o1.TeamId, "", true)).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ if r1 := <-ss.Channel().GetByName(o1.TeamId, o1.Name, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Channel).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if err := (<-ss.Channel().GetByName(o1.TeamId, "", false)).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ store.Must(ss.Channel().Delete(r1.Data.(*model.Channel).Id, model.GetMillis()))
+
+ if err := (<-ss.Channel().GetByName(o1.TeamId, "", false)).Err; err == nil {
+ t.Fatal("Deleted channel should not be returned by GetByName()")
+ }
+}
+
+func testChannelStoreGetDeletedByName(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Name"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ o1.DeleteAt = model.GetMillis()
+ store.Must(ss.Channel().Save(&o1))
+
+ if r1 := <-ss.Channel().GetDeletedByName(o1.TeamId, o1.Name); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Channel).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned channel")
+ }
+ }
+
+ if err := (<-ss.Channel().GetDeletedByName(o1.TeamId, "")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ o1.DeleteAt = model.GetMillis()
+ store.Must(ss.Channel().Save(&o1))
+
+ cresult := <-ss.Channel().GetDeleted(o1.TeamId, 0, 100)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list := cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list")
+ }
+
+ if (*list)[0].Name != o1.Name {
+ t.Fatal("missing channel")
+ }
+
+ o2 := model.Channel{}
+ o2.TeamId = o1.TeamId
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ cresult = <-ss.Channel().GetDeleted(o1.TeamId, 0, 100)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list")
+ }
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "Channel3"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_OPEN
+ o3.DeleteAt = model.GetMillis()
+ store.Must(ss.Channel().Save(&o3))
+
+ cresult = <-ss.Channel().GetDeleted(o1.TeamId, 0, 100)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 2 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetDeleted(o1.TeamId, 0, 1)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetDeleted(o1.TeamId, 1, 1)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+}
+
+func testChannelMemberStore(t *testing.T, ss store.Store) {
+ c1 := model.Channel{}
+ c1.TeamId = model.NewId()
+ c1.DisplayName = "NameName"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = *store.Must(ss.Channel().Save(&c1)).(*model.Channel)
+
+ c1t1 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t1 := c1t1.ExtraUpdateAt
+
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(&u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(&u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ o1 := model.ChannelMember{}
+ o1.ChannelId = c1.Id
+ o1.UserId = u1.Id
+ o1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&o1))
+
+ o2 := model.ChannelMember{}
+ o2.ChannelId = c1.Id
+ o2.UserId = u2.Id
+ o2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&o2))
+
+ c1t2 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t2 := c1t2.ExtraUpdateAt
+
+ if t2 <= t1 {
+ t.Fatal("Member update time incorrect")
+ }
+
+ count := (<-ss.Channel().GetMemberCount(o1.ChannelId, true)).Data.(int64)
+ if count != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ count = (<-ss.Channel().GetMemberCount(o1.ChannelId, true)).Data.(int64)
+ if count != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ if ss.Channel().GetMemberCountFromCache(o1.ChannelId) != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ if ss.Channel().GetMemberCountFromCache("junk") != 0 {
+ t.Fatal("should have saved 0 members")
+ }
+
+ count = (<-ss.Channel().GetMemberCount(o1.ChannelId, false)).Data.(int64)
+ if count != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ store.Must(ss.Channel().RemoveMember(o2.ChannelId, o2.UserId))
+
+ count = (<-ss.Channel().GetMemberCount(o1.ChannelId, false)).Data.(int64)
+ if count != 1 {
+ t.Fatal("should have removed 1 member")
+ }
+
+ c1t3 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t3 := c1t3.ExtraUpdateAt
+
+ if t3 <= t2 || t3 <= t1 {
+ t.Fatal("Member update time incorrect on delete")
+ }
+
+ member := (<-ss.Channel().GetMember(o1.ChannelId, o1.UserId)).Data.(*model.ChannelMember)
+ if member.ChannelId != o1.ChannelId {
+ t.Fatal("should have go member")
+ }
+
+ if err := (<-ss.Channel().SaveMember(&o1)).Err; err == nil {
+ t.Fatal("Should have been a duplicate")
+ }
+
+ c1t4 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t4 := c1t4.ExtraUpdateAt
+ if t4 != t3 {
+ t.Fatal("Should not update time upon failure")
+ }
+}
+
+func testChannelDeleteMemberStore(t *testing.T, ss store.Store) {
+ c1 := model.Channel{}
+ c1.TeamId = model.NewId()
+ c1.DisplayName = "NameName"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = *store.Must(ss.Channel().Save(&c1)).(*model.Channel)
+
+ c1t1 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t1 := c1t1.ExtraUpdateAt
+
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(&u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(&u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ o1 := model.ChannelMember{}
+ o1.ChannelId = c1.Id
+ o1.UserId = u1.Id
+ o1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&o1))
+
+ o2 := model.ChannelMember{}
+ o2.ChannelId = c1.Id
+ o2.UserId = u2.Id
+ o2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&o2))
+
+ c1t2 := (<-ss.Channel().Get(c1.Id, false)).Data.(*model.Channel)
+ t2 := c1t2.ExtraUpdateAt
+
+ if t2 <= t1 {
+ t.Fatal("Member update time incorrect")
+ }
+
+ count := (<-ss.Channel().GetMemberCount(o1.ChannelId, false)).Data.(int64)
+ if count != 2 {
+ t.Fatal("should have saved 2 members")
+ }
+
+ store.Must(ss.Channel().PermanentDeleteMembersByUser(o2.UserId))
+
+ count = (<-ss.Channel().GetMemberCount(o1.ChannelId, false)).Data.(int64)
+ if count != 1 {
+ t.Fatal("should have removed 1 member")
+ }
+
+ if r1 := <-ss.Channel().PermanentDeleteMembersByChannel(o1.ChannelId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ count = (<-ss.Channel().GetMemberCount(o1.ChannelId, false)).Data.(int64)
+ if count != 0 {
+ t.Fatal("should have removed all members")
+ }
+}
+
+func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = o2.Id
+ m3.UserId = model.NewId()
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ cresult := <-ss.Channel().GetChannels(o1.TeamId, m1.UserId)
+ list := cresult.Data.(*model.ChannelList)
+
+ if (*list)[0].Id != o1.Id {
+ t.Fatal("missing channel")
+ }
+
+ acresult := <-ss.Channel().GetAllChannelMembersForUser(m1.UserId, false)
+ ids := acresult.Data.(map[string]string)
+ if _, ok := ids[o1.Id]; !ok {
+ t.Fatal("missing channel")
+ }
+
+ acresult2 := <-ss.Channel().GetAllChannelMembersForUser(m1.UserId, true)
+ ids2 := acresult2.Data.(map[string]string)
+ if _, ok := ids2[o1.Id]; !ok {
+ t.Fatal("missing channel")
+ }
+
+ acresult3 := <-ss.Channel().GetAllChannelMembersForUser(m1.UserId, true)
+ ids3 := acresult3.Data.(map[string]string)
+ if _, ok := ids3[o1.Id]; !ok {
+ t.Fatal("missing channel")
+ }
+
+ if !ss.Channel().IsUserInChannelUseCache(m1.UserId, o1.Id) {
+ t.Fatal("missing channel")
+ }
+
+ if ss.Channel().IsUserInChannelUseCache(m1.UserId, o2.Id) {
+ t.Fatal("missing channel")
+ }
+
+ if ss.Channel().IsUserInChannelUseCache(m1.UserId, "blahblah") {
+ t.Fatal("missing channel")
+ }
+
+ if ss.Channel().IsUserInChannelUseCache("blahblah", "blahblah") {
+ t.Fatal("missing channel")
+ }
+
+ ss.Channel().InvalidateAllChannelMembersForUser(m1.UserId)
+}
+
+func testChannelStoreGetMoreChannels(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = o2.Id
+ m3.UserId = model.NewId()
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "ChannelA"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o3))
+
+ o4 := model.Channel{}
+ o4.TeamId = o1.TeamId
+ o4.DisplayName = "ChannelB"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o4))
+
+ o5 := model.Channel{}
+ o5.TeamId = o1.TeamId
+ o5.DisplayName = "ChannelC"
+ o5.Name = "zz" + model.NewId() + "b"
+ o5.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o5))
+
+ cresult := <-ss.Channel().GetMoreChannels(o1.TeamId, m1.UserId, 0, 100)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list := cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list")
+ }
+
+ if (*list)[0].Name != o3.Name {
+ t.Fatal("missing channel")
+ }
+
+ o6 := model.Channel{}
+ o6.TeamId = o1.TeamId
+ o6.DisplayName = "ChannelA"
+ o6.Name = "zz" + model.NewId() + "b"
+ o6.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o6))
+
+ cresult = <-ss.Channel().GetMoreChannels(o1.TeamId, m1.UserId, 0, 100)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 2 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetMoreChannels(o1.TeamId, m1.UserId, 0, 1)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetMoreChannels(o1.TeamId, m1.UserId, 1, 1)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+ if r1 := <-ss.Channel().AnalyticsTypeCount(o1.TeamId, model.CHANNEL_OPEN); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) != 3 {
+ t.Log(r1.Data)
+ t.Fatal("wrong value")
+ }
+ }
+
+ if r1 := <-ss.Channel().AnalyticsTypeCount(o1.TeamId, model.CHANNEL_PRIVATE); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) != 2 {
+ t.Log(r1.Data)
+ t.Fatal("wrong value")
+ }
+ }
+}
+
+func testChannelStoreGetPublicChannelsForTeam(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "OpenChannel1Team1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "OpenChannel1Team2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "PrivateChannel1Team1"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o3))
+
+ cresult := <-ss.Channel().GetPublicChannelsForTeam(o1.TeamId, 0, 100)
+ if cresult.Err != nil {
+ t.Fatal(cresult.Err)
+ }
+ list := cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list")
+ }
+
+ if (*list)[0].Name != o1.Name {
+ t.Fatal("missing channel")
+ }
+
+ o4 := model.Channel{}
+ o4.TeamId = o1.TeamId
+ o4.DisplayName = "OpenChannel2Team1"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o4))
+
+ cresult = <-ss.Channel().GetPublicChannelsForTeam(o1.TeamId, 0, 100)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 2 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetPublicChannelsForTeam(o1.TeamId, 0, 1)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+ cresult = <-ss.Channel().GetPublicChannelsForTeam(o1.TeamId, 1, 1)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("wrong list length")
+ }
+
+ if r1 := <-ss.Channel().AnalyticsTypeCount(o1.TeamId, model.CHANNEL_OPEN); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) != 2 {
+ t.Log(r1.Data)
+ t.Fatal("wrong value")
+ }
+ }
+
+ if r1 := <-ss.Channel().AnalyticsTypeCount(o1.TeamId, model.CHANNEL_PRIVATE); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) != 1 {
+ t.Log(r1.Data)
+ t.Fatal("wrong value")
+ }
+ }
+}
+
+func testChannelStoreGetPublicChannelsByIdsForTeam(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+
+ oc1 := model.Channel{}
+ oc1.TeamId = teamId1
+ oc1.DisplayName = "OpenChannel1Team1"
+ oc1.Name = "zz" + model.NewId() + "b"
+ oc1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&oc1))
+
+ oc2 := model.Channel{}
+ oc2.TeamId = model.NewId()
+ oc2.DisplayName = "OpenChannel2TeamOther"
+ oc2.Name = "zz" + model.NewId() + "b"
+ oc2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&oc2))
+
+ pc3 := model.Channel{}
+ pc3.TeamId = teamId1
+ pc3.DisplayName = "PrivateChannel3Team1"
+ pc3.Name = "zz" + model.NewId() + "b"
+ pc3.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&pc3))
+
+ cids := []string{oc1.Id}
+ cresult := <-ss.Channel().GetPublicChannelsByIdsForTeam(teamId1, cids)
+ list := cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("should return 1 channel")
+ }
+
+ if (*list)[0].Id != oc1.Id {
+ t.Fatal("missing channel")
+ }
+
+ cids = append(cids, oc2.Id)
+ cids = append(cids, model.NewId())
+ cids = append(cids, pc3.Id)
+ cresult = <-ss.Channel().GetPublicChannelsByIdsForTeam(teamId1, cids)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 1 {
+ t.Fatal("should return 1 channel")
+ }
+
+ oc4 := model.Channel{}
+ oc4.TeamId = teamId1
+ oc4.DisplayName = "OpenChannel4Team1"
+ oc4.Name = "zz" + model.NewId() + "b"
+ oc4.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&oc4))
+
+ cids = append(cids, oc4.Id)
+ cresult = <-ss.Channel().GetPublicChannelsByIdsForTeam(teamId1, cids)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 2 {
+ t.Fatal("should return 2 channels")
+ }
+
+ if (*list)[0].Id != oc1.Id {
+ t.Fatal("missing channel")
+ }
+
+ if (*list)[1].Id != oc4.Id {
+ t.Fatal("missing channel")
+ }
+
+ cids = cids[:0]
+ cids = append(cids, model.NewId())
+ cresult = <-ss.Channel().GetPublicChannelsByIdsForTeam(teamId1, cids)
+ list = cresult.Data.(*model.ChannelList)
+
+ if len(*list) != 0 {
+ t.Fatal("should not return a channel")
+ }
+}
+
+func testChannelStoreGetChannelCounts(t *testing.T, ss store.Store) {
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = o2.Id
+ m3.UserId = model.NewId()
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ cresult := <-ss.Channel().GetChannelCounts(o1.TeamId, m1.UserId)
+ counts := cresult.Data.(*model.ChannelCounts)
+
+ if len(counts.Counts) != 1 {
+ t.Fatal("wrong number of counts")
+ }
+
+ if len(counts.UpdateTimes) != 1 {
+ t.Fatal("wrong number of update times")
+ }
+}
+
+func testChannelStoreGetMembersForUser(t *testing.T, ss store.Store) {
+ t1 := model.Team{}
+ t1.DisplayName = "Name"
+ t1.Name = model.NewId()
+ t1.Email = model.NewId() + "@nowhere.com"
+ t1.Type = model.TEAM_OPEN
+ store.Must(ss.Team().Save(&t1))
+
+ o1 := model.Channel{}
+ o1.TeamId = t1.Id
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = o1.TeamId
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o2.Id
+ m2.UserId = m1.UserId
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ cresult := <-ss.Channel().GetMembersForUser(o1.TeamId, m1.UserId)
+ members := cresult.Data.(*model.ChannelMembers)
+
+ // no unread messages
+ if len(*members) != 2 {
+ t.Fatal("wrong number of members")
+ }
+}
+
+func testChannelStoreUpdateLastViewedAt(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ o1.TotalMsgCount = 25
+ o1.LastPostAt = 12345
+ store.Must(ss.Channel().Save(&o1))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel1"
+ o2.Name = "zz" + model.NewId() + "c"
+ o2.Type = model.CHANNEL_OPEN
+ o2.TotalMsgCount = 26
+ o2.LastPostAt = 123456
+ store.Must(ss.Channel().Save(&o2))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o2.Id
+ m2.UserId = m1.UserId
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ if result := <-ss.Channel().UpdateLastViewedAt([]string{m1.ChannelId}, m1.UserId); result.Err != nil {
+ t.Fatal("failed to update", result.Err)
+ } else if result.Data.(map[string]int64)[o1.Id] != o1.LastPostAt {
+ t.Fatal("last viewed at time incorrect")
+ }
+
+ if result := <-ss.Channel().UpdateLastViewedAt([]string{m1.ChannelId, m2.ChannelId}, m1.UserId); result.Err != nil {
+ t.Fatal("failed to update", result.Err)
+ } else if result.Data.(map[string]int64)[o2.Id] != o2.LastPostAt {
+ t.Fatal("last viewed at time incorrect")
+ }
+
+ rm1 := store.Must(ss.Channel().GetMember(m1.ChannelId, m1.UserId)).(*model.ChannelMember)
+ assert.Equal(t, rm1.LastViewedAt, o1.LastPostAt)
+ assert.Equal(t, rm1.LastUpdateAt, o1.LastPostAt)
+ assert.Equal(t, rm1.MsgCount, o1.TotalMsgCount)
+
+ rm2 := store.Must(ss.Channel().GetMember(m2.ChannelId, m2.UserId)).(*model.ChannelMember)
+ assert.Equal(t, rm2.LastViewedAt, o2.LastPostAt)
+ assert.Equal(t, rm2.LastUpdateAt, o2.LastPostAt)
+ assert.Equal(t, rm2.MsgCount, o2.TotalMsgCount)
+
+ if result := <-ss.Channel().UpdateLastViewedAt([]string{m1.ChannelId}, "missing id"); result.Err != nil {
+ t.Fatal("failed to update")
+ }
+}
+
+func testChannelStoreIncrementMentionCount(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ o1.TotalMsgCount = 25
+ store.Must(ss.Channel().Save(&o1))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ err := (<-ss.Channel().IncrementMentionCount(m1.ChannelId, m1.UserId)).Err
+ if err != nil {
+ t.Fatal("failed to update")
+ }
+
+ err = (<-ss.Channel().IncrementMentionCount(m1.ChannelId, "missing id")).Err
+ if err != nil {
+ t.Fatal("failed to update")
+ }
+
+ err = (<-ss.Channel().IncrementMentionCount("missing id", m1.UserId)).Err
+ if err != nil {
+ t.Fatal("failed to update")
+ }
+
+ err = (<-ss.Channel().IncrementMentionCount("missing id", "missing id")).Err
+ if err != nil {
+ t.Fatal("failed to update")
+ }
+}
+
+func testUpdateChannelMember(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+
+ c1 := &model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: model.NewId(),
+ Name: model.NewId(),
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(c1))
+
+ m1 := &model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: userId,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(m1))
+
+ m1.NotifyProps["test"] = "sometext"
+ if result := <-ss.Channel().UpdateMember(m1); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ m1.UserId = ""
+ if result := <-ss.Channel().UpdateMember(m1); result.Err == nil {
+ t.Fatal("bad user id - should fail")
+ }
+}
+
+func testGetMember(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+
+ c1 := &model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: model.NewId(),
+ Name: model.NewId(),
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(c1))
+
+ c2 := &model.Channel{
+ TeamId: c1.TeamId,
+ DisplayName: model.NewId(),
+ Name: model.NewId(),
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(c2))
+
+ m1 := &model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: userId,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(m1))
+
+ m2 := &model.ChannelMember{
+ ChannelId: c2.Id,
+ UserId: userId,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(m2))
+
+ if result := <-ss.Channel().GetMember(model.NewId(), userId); result.Err == nil {
+ t.Fatal("should've failed to get member for non-existant channel")
+ }
+
+ if result := <-ss.Channel().GetMember(c1.Id, model.NewId()); result.Err == nil {
+ t.Fatal("should've failed to get member for non-existant user")
+ }
+
+ if result := <-ss.Channel().GetMember(c1.Id, userId); result.Err != nil {
+ t.Fatal("shouldn't have errored when getting member", result.Err)
+ } else if member := result.Data.(*model.ChannelMember); member.ChannelId != c1.Id {
+ t.Fatal("should've gotten member of channel 1")
+ } else if member.UserId != userId {
+ t.Fatal("should've gotten member for user")
+ }
+
+ if result := <-ss.Channel().GetMember(c2.Id, userId); result.Err != nil {
+ t.Fatal("shouldn't have errored when getting member", result.Err)
+ } else if member := result.Data.(*model.ChannelMember); member.ChannelId != c2.Id {
+ t.Fatal("should've gotten member of channel 2")
+ } else if member.UserId != userId {
+ t.Fatal("should've gotten member for user")
+ }
+
+ if result := <-ss.Channel().GetAllChannelMembersNotifyPropsForChannel(c2.Id, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ props := result.Data.(map[string]model.StringMap)
+ if len(props) == 0 {
+ t.Fatal("should not be empty")
+ }
+ }
+
+ if result := <-ss.Channel().GetAllChannelMembersNotifyPropsForChannel(c2.Id, true); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ props := result.Data.(map[string]model.StringMap)
+ if len(props) == 0 {
+ t.Fatal("should not be empty")
+ }
+ }
+
+ ss.Channel().InvalidateCacheForChannelMembersNotifyProps(c2.Id)
+}
+
+func testChannelStoreGetMemberForPost(t *testing.T, ss store.Store) {
+ o1 := store.Must(ss.Channel().Save(&model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: "Name",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ })).(*model.Channel)
+
+ m1 := store.Must(ss.Channel().SaveMember(&model.ChannelMember{
+ ChannelId: o1.Id,
+ UserId: model.NewId(),
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ })).(*model.ChannelMember)
+
+ p1 := store.Must(ss.Post().Save(&model.Post{
+ UserId: model.NewId(),
+ ChannelId: o1.Id,
+ Message: "test",
+ })).(*model.Post)
+
+ if r1 := <-ss.Channel().GetMemberForPost(p1.Id, m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else if r1.Data.(*model.ChannelMember).ToJson() != m1.ToJson() {
+ t.Fatal("invalid returned channel member")
+ }
+
+ if r2 := <-ss.Channel().GetMemberForPost(p1.Id, model.NewId()); r2.Err == nil {
+ t.Fatal("shouldn't have returned a member")
+ }
+}
+
+func testGetMemberCount(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ c1 := model.Channel{
+ TeamId: teamId,
+ DisplayName: "Channel1",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(&c1))
+
+ c2 := model.Channel{
+ TeamId: teamId,
+ DisplayName: "Channel2",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(&c2))
+
+ u1 := &model.User{
+ Email: model.NewId(),
+ DeleteAt: 0,
+ }
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ m1 := model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: u1.Id,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ if result := <-ss.Channel().GetMemberCount(c1.Id, false); result.Err != nil {
+ t.Fatalf("failed to get member count: %v", result.Err)
+ } else if result.Data.(int64) != 1 {
+ t.Fatalf("got incorrect member count %v", result.Data)
+ }
+
+ u2 := model.User{
+ Email: model.NewId(),
+ DeleteAt: 0,
+ }
+ store.Must(ss.User().Save(&u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ m2 := model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: u2.Id,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ if result := <-ss.Channel().GetMemberCount(c1.Id, false); result.Err != nil {
+ t.Fatalf("failed to get member count: %v", result.Err)
+ } else if result.Data.(int64) != 2 {
+ t.Fatalf("got incorrect member count %v", result.Data)
+ }
+
+ // make sure members of other channels aren't counted
+ u3 := model.User{
+ Email: model.NewId(),
+ DeleteAt: 0,
+ }
+ store.Must(ss.User().Save(&u3))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u3.Id}))
+
+ m3 := model.ChannelMember{
+ ChannelId: c2.Id,
+ UserId: u3.Id,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ if result := <-ss.Channel().GetMemberCount(c1.Id, false); result.Err != nil {
+ t.Fatalf("failed to get member count: %v", result.Err)
+ } else if result.Data.(int64) != 2 {
+ t.Fatalf("got incorrect member count %v", result.Data)
+ }
+
+ // make sure inactive users aren't counted
+ u4 := &model.User{
+ Email: model.NewId(),
+ DeleteAt: 10000,
+ }
+ store.Must(ss.User().Save(u4))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u4.Id}))
+
+ m4 := model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: u4.Id,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(&m4))
+
+ if result := <-ss.Channel().GetMemberCount(c1.Id, false); result.Err != nil {
+ t.Fatalf("failed to get member count: %v", result.Err)
+ } else if result.Data.(int64) != 2 {
+ t.Fatalf("got incorrect member count %v", result.Data)
+ }
+}
+
+func testUpdateExtrasByUser(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ c1 := model.Channel{
+ TeamId: teamId,
+ DisplayName: "Channel1",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(&c1))
+
+ c2 := model.Channel{
+ TeamId: teamId,
+ DisplayName: "Channel2",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ }
+ store.Must(ss.Channel().Save(&c2))
+
+ u1 := &model.User{
+ Email: model.NewId(),
+ DeleteAt: 0,
+ }
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ m1 := model.ChannelMember{
+ ChannelId: c1.Id,
+ UserId: u1.Id,
+ NotifyProps: model.GetDefaultChannelNotifyProps(),
+ }
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ u1.DeleteAt = model.GetMillis()
+ store.Must(ss.User().Update(u1, true))
+
+ if result := <-ss.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil {
+ t.Fatalf("failed to update extras by user: %v", result.Err)
+ }
+
+ u1.DeleteAt = 0
+ store.Must(ss.User().Update(u1, true))
+
+ if result := <-ss.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil {
+ t.Fatalf("failed to update extras by user: %v", result.Err)
+ }
+}
+
+func testChannelStoreSearchMore(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "ChannelA"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = o2.Id
+ m3.UserId = model.NewId()
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "ChannelA"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o3))
+
+ o4 := model.Channel{}
+ o4.TeamId = o1.TeamId
+ o4.DisplayName = "ChannelB"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o4))
+
+ o5 := model.Channel{}
+ o5.TeamId = o1.TeamId
+ o5.DisplayName = "ChannelC"
+ o5.Name = "zz" + model.NewId() + "b"
+ o5.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o5))
+
+ if result := <-ss.Channel().SearchMore(m1.UserId, o1.TeamId, "ChannelA"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) == 0 {
+ t.Fatal("should not be empty")
+ }
+
+ if (*channels)[0].Name != o3.Name {
+ t.Fatal("wrong channel returned")
+ }
+ }
+
+ if result := <-ss.Channel().SearchMore(m1.UserId, o1.TeamId, o4.Name); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) != 0 {
+ t.Fatal("should be empty")
+ }
+ }
+
+ if result := <-ss.Channel().SearchMore(m1.UserId, o1.TeamId, o3.Name); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) == 0 {
+ t.Fatal("should not be empty")
+ }
+
+ if (*channels)[0].Name != o3.Name {
+ t.Fatal("wrong channel returned")
+ }
+ }
+
+}
+
+func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "ChannelA"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = o1.Id
+ m1.UserId = model.NewId()
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = o1.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = o2.Id
+ m3.UserId = model.NewId()
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ o3 := model.Channel{}
+ o3.TeamId = o1.TeamId
+ o3.DisplayName = "ChannelA"
+ o3.Name = "zz" + model.NewId() + "b"
+ o3.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o3))
+
+ o4 := model.Channel{}
+ o4.TeamId = o1.TeamId
+ o4.DisplayName = "ChannelB"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o4))
+
+ o5 := model.Channel{}
+ o5.TeamId = o1.TeamId
+ o5.DisplayName = "ChannelC"
+ o5.Name = "zz" + model.NewId() + "b"
+ o5.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&o5))
+
+ if result := <-ss.Channel().SearchInTeam(o1.TeamId, "ChannelA"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) != 2 {
+ t.Fatal("wrong length")
+ }
+ }
+
+ if result := <-ss.Channel().SearchInTeam(o1.TeamId, ""); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) == 0 {
+ t.Fatal("should not be empty")
+ }
+ }
+
+ if result := <-ss.Channel().SearchInTeam(o1.TeamId, "blargh"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ channels := result.Data.(*model.ChannelList)
+ if len(*channels) != 0 {
+ t.Fatal("should be empty")
+ }
+ }
+}
+
+func testChannelStoreGetMembersByIds(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "ChannelA"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ m1 := &model.ChannelMember{ChannelId: o1.Id, UserId: model.NewId(), NotifyProps: model.GetDefaultChannelNotifyProps()}
+ store.Must(ss.Channel().SaveMember(m1))
+
+ if r := <-ss.Channel().GetMembersByIds(m1.ChannelId, []string{m1.UserId}); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ rm1 := (*r.Data.(*model.ChannelMembers))[0]
+
+ if rm1.ChannelId != m1.ChannelId {
+ t.Fatal("bad team id")
+ }
+
+ if rm1.UserId != m1.UserId {
+ t.Fatal("bad user id")
+ }
+ }
+
+ m2 := &model.ChannelMember{ChannelId: o1.Id, UserId: model.NewId(), NotifyProps: model.GetDefaultChannelNotifyProps()}
+ store.Must(ss.Channel().SaveMember(m2))
+
+ if r := <-ss.Channel().GetMembersByIds(m1.ChannelId, []string{m1.UserId, m2.UserId, model.NewId()}); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ rm := (*r.Data.(*model.ChannelMembers))
+
+ if len(rm) != 2 {
+ t.Fatal("return wrong number of results")
+ }
+ }
+
+ if r := <-ss.Channel().GetMembersByIds(m1.ChannelId, []string{}); r.Err == nil {
+ t.Fatal("empty user ids - should have failed")
+ }
+}
+
+func testChannelStoreAnalyticsDeletedTypeCount(t *testing.T, ss store.Store) {
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "ChannelA"
+ o1.Name = "zz" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o1))
+
+ o2 := model.Channel{}
+ o2.TeamId = model.NewId()
+ o2.DisplayName = "Channel2"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Type = model.CHANNEL_OPEN
+ store.Must(ss.Channel().Save(&o2))
+
+ p3 := model.Channel{}
+ p3.TeamId = model.NewId()
+ p3.DisplayName = "Channel3"
+ p3.Name = "zz" + model.NewId() + "b"
+ p3.Type = model.CHANNEL_PRIVATE
+ store.Must(ss.Channel().Save(&p3))
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Nickname = model.NewId()
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Nickname = model.NewId()
+ store.Must(ss.User().Save(u2))
+
+ var d4 *model.Channel
+ if result := <-ss.Channel().CreateDirectChannel(u1.Id, u2.Id); result.Err != nil {
+ t.Fatalf(result.Err.Error())
+ } else {
+ d4 = result.Data.(*model.Channel)
+ }
+
+ var openStartCount int64
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "O"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ openStartCount = result.Data.(int64)
+ }
+
+ var privateStartCount int64
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "P"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ privateStartCount = result.Data.(int64)
+ }
+
+ var directStartCount int64
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "D"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ directStartCount = result.Data.(int64)
+ }
+
+ store.Must(ss.Channel().Delete(o1.Id, model.GetMillis()))
+ store.Must(ss.Channel().Delete(o2.Id, model.GetMillis()))
+ store.Must(ss.Channel().Delete(p3.Id, model.GetMillis()))
+ store.Must(ss.Channel().Delete(d4.Id, model.GetMillis()))
+
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "O"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ if result.Data.(int64) != openStartCount+2 {
+ t.Fatalf("Wrong open channel deleted count.")
+ }
+ }
+
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "P"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ if result.Data.(int64) != privateStartCount+1 {
+ t.Fatalf("Wrong private channel deleted count.")
+ }
+ }
+
+ if result := <-ss.Channel().AnalyticsDeletedTypeCount("", "D"); result.Err != nil {
+ t.Fatal(result.Err.Error())
+ } else {
+ if result.Data.(int64) != directStartCount+1 {
+ t.Fatalf("Wrong direct channel deleted count.")
+ }
+ }
+}
+
+func testChannelStoreGetPinnedPosts(t *testing.T, ss store.Store) {
+ o1 := store.Must(ss.Channel().Save(&model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: "Name",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ })).(*model.Channel)
+
+ p1 := store.Must(ss.Post().Save(&model.Post{
+ UserId: model.NewId(),
+ ChannelId: o1.Id,
+ Message: "test",
+ IsPinned: true,
+ })).(*model.Post)
+
+ if r1 := <-ss.Channel().GetPinnedPosts(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else if r1.Data.(*model.PostList).Posts[p1.Id] == nil {
+ t.Fatal("didn't return relevant pinned posts")
+ }
+
+ o2 := store.Must(ss.Channel().Save(&model.Channel{
+ TeamId: model.NewId(),
+ DisplayName: "Name",
+ Name: "zz" + model.NewId() + "b",
+ Type: model.CHANNEL_OPEN,
+ })).(*model.Channel)
+
+ store.Must(ss.Post().Save(&model.Post{
+ UserId: model.NewId(),
+ ChannelId: o2.Id,
+ Message: "test",
+ }))
+
+ if r2 := <-ss.Channel().GetPinnedPosts(o2.Id); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else if len(r2.Data.(*model.PostList).Posts) != 0 {
+ t.Fatal("wasn't supposed to return posts")
+ }
+}
diff --git a/store/storetest/cluster_discovery_store.go b/store/storetest/cluster_discovery_store.go
new file mode 100644
index 000000000..478f2e5f8
--- /dev/null
+++ b/store/storetest/cluster_discovery_store.go
@@ -0,0 +1,200 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestClusterDiscoveryStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testClusterDiscoveryStore(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testClusterDiscoveryStoreDelete(t, ss) })
+ t.Run("LastPing", func(t *testing.T) { testClusterDiscoveryStoreLastPing(t, ss) })
+ t.Run("Exists", func(t *testing.T) { testClusterDiscoveryStoreExists(t, ss) })
+ t.Run("ClusterDiscoveryGetStore", func(t *testing.T) { testClusterDiscoveryGetStore(t, ss) })
+}
+
+func testClusterDiscoveryStore(t *testing.T, ss store.Store) {
+ discovery := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname" + model.NewId(),
+ Type: "test_test",
+ }
+
+ if result := <-ss.ClusterDiscovery().Save(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.ClusterDiscovery().Cleanup(); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testClusterDiscoveryStoreDelete(t *testing.T, ss store.Store) {
+ discovery := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname" + model.NewId(),
+ Type: "test_test",
+ }
+
+ if result := <-ss.ClusterDiscovery().Save(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.ClusterDiscovery().Delete(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testClusterDiscoveryStoreLastPing(t *testing.T, ss store.Store) {
+ discovery := &model.ClusterDiscovery{
+ ClusterName: "cluster_name_lastPing",
+ Hostname: "hostname" + model.NewId(),
+ Type: "test_test_lastPing" + model.NewId(),
+ }
+
+ if result := <-ss.ClusterDiscovery().Save(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.ClusterDiscovery().SetLastPingAt(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ttime := model.GetMillis()
+
+ time.Sleep(1 * time.Second)
+
+ if result := <-ss.ClusterDiscovery().SetLastPingAt(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.ClusterDiscovery().GetAll(discovery.Type, "cluster_name_lastPing"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ list := result.Data.([]*model.ClusterDiscovery)
+
+ if len(list) != 1 {
+ t.Fatal("should only be 1 items")
+ return
+ }
+
+ if list[0].LastPingAt-ttime < 500 {
+ t.Fatal("failed to set time")
+ }
+ }
+
+ discovery2 := &model.ClusterDiscovery{
+ ClusterName: "cluster_name_missing",
+ Hostname: "hostname" + model.NewId(),
+ Type: "test_test_missing",
+ }
+
+ if result := <-ss.ClusterDiscovery().SetLastPingAt(discovery2); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testClusterDiscoveryStoreExists(t *testing.T, ss store.Store) {
+ discovery := &model.ClusterDiscovery{
+ ClusterName: "cluster_name_Exists",
+ Hostname: "hostname" + model.NewId(),
+ Type: "test_test_Exists" + model.NewId(),
+ }
+
+ if result := <-ss.ClusterDiscovery().Save(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.ClusterDiscovery().Exists(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ val := result.Data.(bool)
+ if !val {
+ t.Fatal("should be true")
+ }
+ }
+
+ discovery.ClusterName = "cluster_name_Exists2"
+
+ if result := <-ss.ClusterDiscovery().Exists(discovery); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ val := result.Data.(bool)
+ if val {
+ t.Fatal("should be true")
+ }
+ }
+}
+
+func testClusterDiscoveryGetStore(t *testing.T, ss store.Store) {
+ testType1 := model.NewId()
+
+ discovery1 := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname1",
+ Type: testType1,
+ }
+ store.Must(ss.ClusterDiscovery().Save(discovery1))
+
+ discovery2 := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname2",
+ Type: testType1,
+ }
+ store.Must(ss.ClusterDiscovery().Save(discovery2))
+
+ discovery3 := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname3",
+ Type: testType1,
+ CreateAt: 1,
+ LastPingAt: 1,
+ }
+ store.Must(ss.ClusterDiscovery().Save(discovery3))
+
+ testType2 := model.NewId()
+
+ discovery4 := &model.ClusterDiscovery{
+ ClusterName: "cluster_name",
+ Hostname: "hostname1",
+ Type: testType2,
+ }
+ store.Must(ss.ClusterDiscovery().Save(discovery4))
+
+ if result := <-ss.ClusterDiscovery().GetAll(testType1, "cluster_name"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ list := result.Data.([]*model.ClusterDiscovery)
+
+ if len(list) != 2 {
+ t.Fatal("Should only have returned 2")
+ }
+ }
+
+ if result := <-ss.ClusterDiscovery().GetAll(testType2, "cluster_name"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ list := result.Data.([]*model.ClusterDiscovery)
+
+ if len(list) != 1 {
+ t.Fatal("Should only have returned 1")
+ }
+ }
+
+ if result := <-ss.ClusterDiscovery().GetAll(model.NewId(), "cluster_name"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ list := result.Data.([]*model.ClusterDiscovery)
+
+ if len(list) != 0 {
+ t.Fatal("shouldn't be any")
+ }
+ }
+}
diff --git a/store/storetest/command_store.go b/store/storetest/command_store.go
new file mode 100644
index 000000000..92d981660
--- /dev/null
+++ b/store/storetest/command_store.go
@@ -0,0 +1,251 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestCommandStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testCommandStoreSave(t, ss) })
+ t.Run("Get", func(t *testing.T) { testCommandStoreGet(t, ss) })
+ t.Run("GetByTeam", func(t *testing.T) { testCommandStoreGetByTeam(t, ss) })
+ t.Run("GetByTrigger", func(t *testing.T) { testCommandStoreGetByTrigger(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testCommandStoreDelete(t, ss) })
+ t.Run("DeleteByTeam", func(t *testing.T) { testCommandStoreDeleteByTeam(t, ss) })
+ t.Run("DeleteByUser", func(t *testing.T) { testCommandStoreDeleteByUser(t, ss) })
+ t.Run("Update", func(t *testing.T) { testCommandStoreUpdate(t, ss) })
+ t.Run("CommandCount", func(t *testing.T) { testCommandCount(t, ss) })
+}
+
+func testCommandStoreSave(t *testing.T, ss store.Store) {
+ o1 := model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ if err := (<-ss.Command().Save(&o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Command().Save(&o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+}
+
+func testCommandStoreGet(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ if err := (<-ss.Command().Get("123")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testCommandStoreGetByTeam(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().GetByTeam(o1.TeamId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.([]*model.Command)[0].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ if result := <-ss.Command().GetByTeam("123"); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.Command)) != 0 {
+ t.Fatal("no commands should have returned")
+ }
+ }
+}
+
+func testCommandStoreGetByTrigger(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger1"
+
+ o2 := &model.Command{}
+ o2.CreatorId = model.NewId()
+ o2.Method = model.COMMAND_METHOD_POST
+ o2.TeamId = model.NewId()
+ o2.URL = "http://nowhere.com/"
+ o2.Trigger = "trigger1"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+ o2 = (<-ss.Command().Save(o2)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().GetByTrigger(o1.TeamId, o1.Trigger); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).Id != o1.Id {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ store.Must(ss.Command().Delete(o1.Id, model.GetMillis()))
+
+ if result := <-ss.Command().GetByTrigger(o1.TeamId, o1.Trigger); result.Err == nil {
+ t.Fatal("no commands should have returned")
+ }
+}
+
+func testCommandStoreDelete(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ if r2 := <-ss.Command().Delete(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Command().Get(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testCommandStoreDeleteByTeam(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ if r2 := <-ss.Command().PermanentDeleteByTeam(o1.TeamId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Command().Get(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testCommandStoreDeleteByUser(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Command).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned command")
+ }
+ }
+
+ if r2 := <-ss.Command().PermanentDeleteByUser(o1.CreatorId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Command().Get(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testCommandStoreUpdate(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ o1.Token = model.NewId()
+
+ if r2 := <-ss.Command().Update(o1); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+}
+
+func testCommandCount(t *testing.T, ss store.Store) {
+ o1 := &model.Command{}
+ o1.CreatorId = model.NewId()
+ o1.Method = model.COMMAND_METHOD_POST
+ o1.TeamId = model.NewId()
+ o1.URL = "http://nowhere.com/"
+ o1.Trigger = "trigger"
+
+ o1 = (<-ss.Command().Save(o1)).Data.(*model.Command)
+
+ if r1 := <-ss.Command().AnalyticsCommandCount(""); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) == 0 {
+ t.Fatal("should be at least 1 command")
+ }
+ }
+
+ if r2 := <-ss.Command().AnalyticsCommandCount(o1.TeamId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if r2.Data.(int64) != 1 {
+ t.Fatal("should be 1 command")
+ }
+ }
+}
diff --git a/store/storetest/command_webhook_store.go b/store/storetest/command_webhook_store.go
new file mode 100644
index 000000000..a1f97b979
--- /dev/null
+++ b/store/storetest/command_webhook_store.go
@@ -0,0 +1,68 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "net/http"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestCommandWebhookStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testCommandWebhookStore(t, ss) })
+}
+
+func testCommandWebhookStore(t *testing.T, ss store.Store) {
+ cws := ss.CommandWebhook()
+
+ h1 := &model.CommandWebhook{}
+ h1.CommandId = model.NewId()
+ h1.UserId = model.NewId()
+ h1.ChannelId = model.NewId()
+ h1 = (<-cws.Save(h1)).Data.(*model.CommandWebhook)
+
+ if r1 := <-cws.Get(h1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if *r1.Data.(*model.CommandWebhook) != *h1 {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if err := (<-cws.Get("123")).Err; err.StatusCode != http.StatusNotFound {
+ t.Fatal("Should have set the status as not found for missing id")
+ }
+
+ h2 := &model.CommandWebhook{}
+ h2.CreateAt = model.GetMillis() - 2*model.COMMAND_WEBHOOK_LIFETIME
+ h2.CommandId = model.NewId()
+ h2.UserId = model.NewId()
+ h2.ChannelId = model.NewId()
+ h2 = (<-cws.Save(h2)).Data.(*model.CommandWebhook)
+
+ if err := (<-cws.Get(h2.Id)).Err; err == nil || err.StatusCode != http.StatusNotFound {
+ t.Fatal("Should have set the status as not found for expired webhook")
+ }
+
+ cws.Cleanup()
+
+ if err := (<-cws.Get(h1.Id)).Err; err != nil {
+ t.Fatal("Should have no error getting unexpired webhook")
+ }
+
+ if err := (<-cws.Get(h2.Id)).Err; err.StatusCode != http.StatusNotFound {
+ t.Fatal("Should have set the status as not found for expired webhook")
+ }
+
+ if err := (<-cws.TryUse(h1.Id, 1)).Err; err != nil {
+ t.Fatal("Should be able to use webhook once")
+ }
+
+ if err := (<-cws.TryUse(h1.Id, 1)).Err; err == nil || err.StatusCode != http.StatusBadRequest {
+ t.Fatal("Should be able to use webhook once")
+ }
+}
diff --git a/store/storetest/compliance_store.go b/store/storetest/compliance_store.go
new file mode 100644
index 000000000..1069bb88b
--- /dev/null
+++ b/store/storetest/compliance_store.go
@@ -0,0 +1,318 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestComplianceStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testComplianceStore(t, ss) })
+ t.Run("ComplianceExport", func(t *testing.T) { testComplianceExport(t, ss) })
+ t.Run("ComplianceExportDirectMessages", func(t *testing.T) { testComplianceExportDirectMessages(t, ss) })
+}
+
+func testComplianceStore(t *testing.T, ss store.Store) {
+ compliance1 := &model.Compliance{Desc: "Audit for federal subpoena case #22443", UserId: model.NewId(), Status: model.COMPLIANCE_STATUS_FAILED, StartAt: model.GetMillis() - 1, EndAt: model.GetMillis() + 1, Type: model.COMPLIANCE_TYPE_ADHOC}
+ store.Must(ss.Compliance().Save(compliance1))
+ time.Sleep(100 * time.Millisecond)
+
+ compliance2 := &model.Compliance{Desc: "Audit for federal subpoena case #11458", UserId: model.NewId(), Status: model.COMPLIANCE_STATUS_RUNNING, StartAt: model.GetMillis() - 1, EndAt: model.GetMillis() + 1, Type: model.COMPLIANCE_TYPE_ADHOC}
+ store.Must(ss.Compliance().Save(compliance2))
+ time.Sleep(100 * time.Millisecond)
+
+ c := ss.Compliance().GetAll(0, 1000)
+ result := <-c
+ compliances := result.Data.(model.Compliances)
+
+ if compliances[0].Status != model.COMPLIANCE_STATUS_RUNNING && compliance2.Id != compliances[0].Id {
+ t.Fatal()
+ }
+
+ compliance2.Status = model.COMPLIANCE_STATUS_FAILED
+ store.Must(ss.Compliance().Update(compliance2))
+
+ c = ss.Compliance().GetAll(0, 1000)
+ result = <-c
+ compliances = result.Data.(model.Compliances)
+
+ if compliances[0].Status != model.COMPLIANCE_STATUS_FAILED && compliance2.Id != compliances[0].Id {
+ t.Fatal()
+ }
+
+ c = ss.Compliance().GetAll(0, 1)
+ result = <-c
+ compliances = result.Data.(model.Compliances)
+
+ if len(compliances) != 1 {
+ t.Fatal("should only have returned 1")
+ }
+
+ c = ss.Compliance().GetAll(1, 1)
+ result = <-c
+ compliances = result.Data.(model.Compliances)
+
+ if len(compliances) != 1 {
+ t.Fatal("should only have returned 1")
+ }
+
+ rc2 := (<-ss.Compliance().Get(compliance2.Id)).Data.(*model.Compliance)
+ if rc2.Status != compliance2.Status {
+ t.Fatal()
+ }
+}
+
+func testComplianceExport(t *testing.T, ss store.Store) {
+ time.Sleep(100 * time.Millisecond)
+
+ t1 := &model.Team{}
+ t1.DisplayName = "DisplayName"
+ t1.Name = "zz" + model.NewId() + "b"
+ t1.Email = model.NewId() + "@nowhere.com"
+ t1.Type = model.TEAM_OPEN
+ t1 = store.Must(ss.Team().Save(t1)).(*model.Team)
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ u1 = store.Must(ss.User().Save(u1)).(*model.User)
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Username = model.NewId()
+ u2 = store.Must(ss.User().Save(u2)).(*model.User)
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u2.Id}))
+
+ c1 := &model.Channel{}
+ c1.TeamId = t1.Id
+ c1.DisplayName = "Channel2"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = store.Must(ss.Channel().Save(c1)).(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = u1.Id
+ o1.CreateAt = model.GetMillis()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = store.Must(ss.Post().Save(o1)).(*model.Post)
+
+ o1a := &model.Post{}
+ o1a.ChannelId = c1.Id
+ o1a.UserId = u1.Id
+ o1a.CreateAt = o1.CreateAt + 10
+ o1a.Message = "zz" + model.NewId() + "b"
+ o1a = store.Must(ss.Post().Save(o1a)).(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c1.Id
+ o2.UserId = u1.Id
+ o2.CreateAt = o1.CreateAt + 20
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = store.Must(ss.Post().Save(o2)).(*model.Post)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = c1.Id
+ o2a.UserId = u2.Id
+ o2a.CreateAt = o1.CreateAt + 30
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a = store.Must(ss.Post().Save(o2a)).(*model.Post)
+
+ time.Sleep(100 * time.Millisecond)
+
+ cr1 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1}
+ if r1 := <-ss.Compliance().ComplianceExport(cr1); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 4 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o1.Id {
+ t.Fatal("Wrong sort")
+ }
+
+ if cposts[3].PostId != o2a.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+
+ cr2 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1, Emails: u2.Email}
+ if r1 := <-ss.Compliance().ComplianceExport(cr2); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 1 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o2a.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+
+ cr3 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1, Emails: u2.Email + ", " + u1.Email}
+ if r1 := <-ss.Compliance().ComplianceExport(cr3); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 4 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o1.Id {
+ t.Fatal("Wrong sort")
+ }
+
+ if cposts[3].PostId != o2a.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+
+ cr4 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1, Keywords: o2a.Message}
+ if r1 := <-ss.Compliance().ComplianceExport(cr4); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 1 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o2a.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+
+ cr5 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1, Keywords: o2a.Message + " " + o1.Message}
+ if r1 := <-ss.Compliance().ComplianceExport(cr5); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 2 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o1.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+
+ cr6 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o2a.CreateAt + 1, Emails: u2.Email + ", " + u1.Email, Keywords: o2a.Message + " " + o1.Message}
+ if r1 := <-ss.Compliance().ComplianceExport(cr6); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 2 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o1.Id {
+ t.Fatal("Wrong sort")
+ }
+
+ if cposts[1].PostId != o2a.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+}
+
+func testComplianceExportDirectMessages(t *testing.T, ss store.Store) {
+ time.Sleep(100 * time.Millisecond)
+
+ t1 := &model.Team{}
+ t1.DisplayName = "DisplayName"
+ t1.Name = "zz" + model.NewId() + "b"
+ t1.Email = model.NewId() + "@nowhere.com"
+ t1.Type = model.TEAM_OPEN
+ t1 = store.Must(ss.Team().Save(t1)).(*model.Team)
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ u1 = store.Must(ss.User().Save(u1)).(*model.User)
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Username = model.NewId()
+ u2 = store.Must(ss.User().Save(u2)).(*model.User)
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u2.Id}))
+
+ c1 := &model.Channel{}
+ c1.TeamId = t1.Id
+ c1.DisplayName = "Channel2"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = store.Must(ss.Channel().Save(c1)).(*model.Channel)
+
+ cDM := store.Must(ss.Channel().CreateDirectChannel(u1.Id, u2.Id)).(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = u1.Id
+ o1.CreateAt = model.GetMillis()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = store.Must(ss.Post().Save(o1)).(*model.Post)
+
+ o1a := &model.Post{}
+ o1a.ChannelId = c1.Id
+ o1a.UserId = u1.Id
+ o1a.CreateAt = o1.CreateAt + 10
+ o1a.Message = "zz" + model.NewId() + "b"
+ o1a = store.Must(ss.Post().Save(o1a)).(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c1.Id
+ o2.UserId = u1.Id
+ o2.CreateAt = o1.CreateAt + 20
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = store.Must(ss.Post().Save(o2)).(*model.Post)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = c1.Id
+ o2a.UserId = u2.Id
+ o2a.CreateAt = o1.CreateAt + 30
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a = store.Must(ss.Post().Save(o2a)).(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = cDM.Id
+ o3.UserId = u1.Id
+ o3.CreateAt = o1.CreateAt + 40
+ o3.Message = "zz" + model.NewId() + "b"
+ o3 = store.Must(ss.Post().Save(o3)).(*model.Post)
+
+ time.Sleep(100 * time.Millisecond)
+
+ cr1 := &model.Compliance{Desc: "test" + model.NewId(), StartAt: o1.CreateAt - 1, EndAt: o3.CreateAt + 1, Emails: u1.Email}
+ if r1 := <-ss.Compliance().ComplianceExport(cr1); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ cposts := r1.Data.([]*model.CompliancePost)
+
+ if len(cposts) != 4 {
+ t.Fatal("return wrong results length")
+ }
+
+ if cposts[0].PostId != o1.Id {
+ t.Fatal("Wrong sort")
+ }
+
+ if cposts[len(cposts)-1].PostId != o3.Id {
+ t.Fatal("Wrong sort")
+ }
+ }
+}
diff --git a/store/storetest/emoji_store.go b/store/storetest/emoji_store.go
new file mode 100644
index 000000000..fc5a31a43
--- /dev/null
+++ b/store/storetest/emoji_store.go
@@ -0,0 +1,175 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestEmojiStore(t *testing.T, ss store.Store) {
+ t.Run("EmojiSaveDelete", func(t *testing.T) { testEmojiSaveDelete(t, ss) })
+ t.Run("EmojiGet", func(t *testing.T) { testEmojiGet(t, ss) })
+ t.Run("EmojiGetByName", func(t *testing.T) { testEmojiGetByName(t, ss) })
+ t.Run("EmojiGetList", func(t *testing.T) { testEmojiGetList(t, ss) })
+}
+
+func testEmojiSaveDelete(t *testing.T, ss store.Store) {
+ emoji1 := &model.Emoji{
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ }
+
+ if result := <-ss.Emoji().Save(emoji1); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if len(emoji1.Id) != 26 {
+ t.Fatal("should've set id for emoji")
+ }
+
+ emoji2 := model.Emoji{
+ CreatorId: model.NewId(),
+ Name: emoji1.Name,
+ }
+ if result := <-ss.Emoji().Save(&emoji2); result.Err == nil {
+ t.Fatal("shouldn't be able to save emoji with duplicate name")
+ }
+
+ if result := <-ss.Emoji().Delete(emoji1.Id, time.Now().Unix()); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.Emoji().Save(&emoji2); result.Err != nil {
+ t.Fatal("should be able to save emoji with duplicate name now that original has been deleted", result.Err)
+ }
+
+ if result := <-ss.Emoji().Delete(emoji2.Id, time.Now().Unix()+1); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testEmojiGet(t *testing.T, ss store.Store) {
+ emojis := []model.Emoji{
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ }
+
+ for i, emoji := range emojis {
+ emojis[i] = *store.Must(ss.Emoji().Save(&emoji)).(*model.Emoji)
+ }
+ defer func() {
+ for _, emoji := range emojis {
+ store.Must(ss.Emoji().Delete(emoji.Id, time.Now().Unix()))
+ }
+ }()
+
+ for _, emoji := range emojis {
+ if result := <-ss.Emoji().Get(emoji.Id, false); result.Err != nil {
+ t.Fatalf("failed to get emoji with id %v: %v", emoji.Id, result.Err)
+ }
+ }
+
+ for _, emoji := range emojis {
+ if result := <-ss.Emoji().Get(emoji.Id, true); result.Err != nil {
+ t.Fatalf("failed to get emoji with id %v: %v", emoji.Id, result.Err)
+ }
+ }
+
+ for _, emoji := range emojis {
+ if result := <-ss.Emoji().Get(emoji.Id, true); result.Err != nil {
+ t.Fatalf("failed to get emoji with id %v: %v", emoji.Id, result.Err)
+ }
+ }
+}
+
+func testEmojiGetByName(t *testing.T, ss store.Store) {
+ emojis := []model.Emoji{
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ }
+
+ for i, emoji := range emojis {
+ emojis[i] = *store.Must(ss.Emoji().Save(&emoji)).(*model.Emoji)
+ }
+ defer func() {
+ for _, emoji := range emojis {
+ store.Must(ss.Emoji().Delete(emoji.Id, time.Now().Unix()))
+ }
+ }()
+
+ for _, emoji := range emojis {
+ if result := <-ss.Emoji().GetByName(emoji.Name); result.Err != nil {
+ t.Fatalf("failed to get emoji with name %v: %v", emoji.Name, result.Err)
+ }
+ }
+}
+
+func testEmojiGetList(t *testing.T, ss store.Store) {
+ emojis := []model.Emoji{
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ {
+ CreatorId: model.NewId(),
+ Name: model.NewId(),
+ },
+ }
+
+ for i, emoji := range emojis {
+ emojis[i] = *store.Must(ss.Emoji().Save(&emoji)).(*model.Emoji)
+ }
+ defer func() {
+ for _, emoji := range emojis {
+ store.Must(ss.Emoji().Delete(emoji.Id, time.Now().Unix()))
+ }
+ }()
+
+ if result := <-ss.Emoji().GetList(0, 100); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ for _, emoji := range emojis {
+ found := false
+
+ for _, savedEmoji := range result.Data.([]*model.Emoji) {
+ if emoji.Id == savedEmoji.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatalf("failed to get emoji with id %v", emoji.Id)
+ }
+ }
+ }
+}
diff --git a/store/storetest/file_info_store.go b/store/storetest/file_info_store.go
new file mode 100644
index 000000000..9b3388db5
--- /dev/null
+++ b/store/storetest/file_info_store.go
@@ -0,0 +1,296 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestFileInfoStore(t *testing.T, ss store.Store) {
+ t.Run("FileInfoSaveGet", func(t *testing.T) { testFileInfoSaveGet(t, ss) })
+ t.Run("FileInfoSaveGetByPath", func(t *testing.T) { testFileInfoSaveGetByPath(t, ss) })
+ t.Run("FileInfoGetForPost", func(t *testing.T) { testFileInfoGetForPost(t, ss) })
+ t.Run("FileInfoAttachToPost", func(t *testing.T) { testFileInfoAttachToPost(t, ss) })
+ t.Run("FileInfoDeleteForPost", func(t *testing.T) { testFileInfoDeleteForPost(t, ss) })
+ t.Run("FileInfoPermanentDelete", func(t *testing.T) { testFileInfoPermanentDelete(t, ss) })
+ t.Run("FileInfoPermanentDeleteBatch", func(t *testing.T) { testFileInfoPermanentDeleteBatch(t, ss) })
+}
+
+func testFileInfoSaveGet(t *testing.T, ss store.Store) {
+ info := &model.FileInfo{
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ }
+
+ if result := <-ss.FileInfo().Save(info); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.(*model.FileInfo); len(returned.Id) == 0 {
+ t.Fatal("should've assigned an id to FileInfo")
+ } else {
+ info = returned
+ }
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info.Id)
+ }()
+
+ if result := <-ss.FileInfo().Get(info.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.(*model.FileInfo); returned.Id != info.Id {
+ t.Log(info)
+ t.Log(returned)
+ t.Fatal("should've returned correct FileInfo")
+ }
+
+ info2 := store.Must(ss.FileInfo().Save(&model.FileInfo{
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ DeleteAt: 123,
+ })).(*model.FileInfo)
+
+ if result := <-ss.FileInfo().Get(info2.Id); result.Err == nil {
+ t.Fatal("shouldn't have gotten deleted file")
+ }
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info2.Id)
+ }()
+}
+
+func testFileInfoSaveGetByPath(t *testing.T, ss store.Store) {
+ info := &model.FileInfo{
+ CreatorId: model.NewId(),
+ Path: fmt.Sprintf("%v/file.txt", model.NewId()),
+ }
+
+ if result := <-ss.FileInfo().Save(info); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.(*model.FileInfo); len(returned.Id) == 0 {
+ t.Fatal("should've assigned an id to FileInfo")
+ } else {
+ info = returned
+ }
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info.Id)
+ }()
+
+ if result := <-ss.FileInfo().GetByPath(info.Path); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.(*model.FileInfo); returned.Id != info.Id {
+ t.Log(info)
+ t.Log(returned)
+ t.Fatal("should've returned correct FileInfo")
+ }
+
+ info2 := store.Must(ss.FileInfo().Save(&model.FileInfo{
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ DeleteAt: 123,
+ })).(*model.FileInfo)
+
+ if result := <-ss.FileInfo().GetByPath(info2.Id); result.Err == nil {
+ t.Fatal("shouldn't have gotten deleted file")
+ }
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info2.Id)
+ }()
+}
+
+func testFileInfoGetForPost(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ postId := model.NewId()
+
+ infos := []*model.FileInfo{
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ DeleteAt: 123,
+ },
+ {
+ PostId: model.NewId(),
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ }
+
+ for i, info := range infos {
+ infos[i] = store.Must(ss.FileInfo().Save(info)).(*model.FileInfo)
+ defer func(id string) {
+ <-ss.FileInfo().PermanentDelete(id)
+ }(infos[i].Id)
+ }
+
+ if result := <-ss.FileInfo().GetForPost(postId, true, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.([]*model.FileInfo); len(returned) != 2 {
+ t.Fatal("should've returned exactly 2 file infos")
+ }
+
+ if result := <-ss.FileInfo().GetForPost(postId, false, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.([]*model.FileInfo); len(returned) != 2 {
+ t.Fatal("should've returned exactly 2 file infos")
+ }
+
+ if result := <-ss.FileInfo().GetForPost(postId, true, true); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.([]*model.FileInfo); len(returned) != 2 {
+ t.Fatal("should've returned exactly 2 file infos")
+ }
+}
+
+func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ postId := model.NewId()
+
+ info1 := store.Must(ss.FileInfo().Save(&model.FileInfo{
+ CreatorId: userId,
+ Path: "file.txt",
+ })).(*model.FileInfo)
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info1.Id)
+ }()
+
+ if len(info1.PostId) != 0 {
+ t.Fatal("file shouldn't have a PostId")
+ }
+
+ if result := <-ss.FileInfo().AttachToPost(info1.Id, postId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ info1 = store.Must(ss.FileInfo().Get(info1.Id)).(*model.FileInfo)
+ }
+
+ if len(info1.PostId) == 0 {
+ t.Fatal("file should now have a PostId")
+ }
+
+ info2 := store.Must(ss.FileInfo().Save(&model.FileInfo{
+ CreatorId: userId,
+ Path: "file.txt",
+ })).(*model.FileInfo)
+ defer func() {
+ <-ss.FileInfo().PermanentDelete(info2.Id)
+ }()
+
+ if result := <-ss.FileInfo().AttachToPost(info2.Id, postId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ info2 = store.Must(ss.FileInfo().Get(info2.Id)).(*model.FileInfo)
+ }
+
+ if result := <-ss.FileInfo().GetForPost(postId, true, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if infos := result.Data.([]*model.FileInfo); len(infos) != 2 {
+ t.Fatal("should've returned exactly 2 file infos")
+ }
+}
+
+func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ postId := model.NewId()
+
+ infos := []*model.FileInfo{
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ {
+ PostId: postId,
+ CreatorId: userId,
+ Path: "file.txt",
+ DeleteAt: 123,
+ },
+ {
+ PostId: model.NewId(),
+ CreatorId: userId,
+ Path: "file.txt",
+ },
+ }
+
+ for i, info := range infos {
+ infos[i] = store.Must(ss.FileInfo().Save(info)).(*model.FileInfo)
+ defer func(id string) {
+ <-ss.FileInfo().PermanentDelete(id)
+ }(infos[i].Id)
+ }
+
+ if result := <-ss.FileInfo().DeleteForPost(postId); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if infos := store.Must(ss.FileInfo().GetForPost(postId, true, false)).([]*model.FileInfo); len(infos) != 0 {
+ t.Fatal("shouldn't have returned any file infos")
+ }
+}
+
+func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
+ info := store.Must(ss.FileInfo().Save(&model.FileInfo{
+ PostId: model.NewId(),
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ })).(*model.FileInfo)
+
+ if result := <-ss.FileInfo().PermanentDelete(info.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
+ postId := model.NewId()
+
+ store.Must(ss.FileInfo().Save(&model.FileInfo{
+ PostId: postId,
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ CreateAt: 1000,
+ }))
+
+ store.Must(ss.FileInfo().Save(&model.FileInfo{
+ PostId: postId,
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ CreateAt: 1200,
+ }))
+
+ store.Must(ss.FileInfo().Save(&model.FileInfo{
+ PostId: postId,
+ CreatorId: model.NewId(),
+ Path: "file.txt",
+ CreateAt: 2000,
+ }))
+
+ if result := <-ss.FileInfo().GetForPost(postId, true, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if len(result.Data.([]*model.FileInfo)) != 3 {
+ t.Fatal("Expected 3 fileInfos")
+ }
+
+ store.Must(ss.FileInfo().PermanentDeleteBatch(1500, 1000))
+
+ if result := <-ss.FileInfo().GetForPost(postId, true, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if len(result.Data.([]*model.FileInfo)) != 1 {
+ t.Fatal("Expected 3 fileInfos")
+ }
+}
diff --git a/store/storetest/job_store.go b/store/storetest/job_store.go
new file mode 100644
index 000000000..631df08fd
--- /dev/null
+++ b/store/storetest/job_store.go
@@ -0,0 +1,507 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestJobStore(t *testing.T, ss store.Store) {
+ t.Run("JobSaveGet", func(t *testing.T) { testJobSaveGet(t, ss) })
+ t.Run("JobGetAllByType", func(t *testing.T) { testJobGetAllByType(t, ss) })
+ t.Run("JobGetAllByTypePage", func(t *testing.T) { testJobGetAllByTypePage(t, ss) })
+ t.Run("JobGetAllPage", func(t *testing.T) { testJobGetAllPage(t, ss) })
+ t.Run("JobGetAllByStatus", func(t *testing.T) { testJobGetAllByStatus(t, ss) })
+ t.Run("GetNewestJobByStatusAndType", func(t *testing.T) { testJobStoreGetNewestJobByStatusAndType(t, ss) })
+ t.Run("GetCountByStatusAndType", func(t *testing.T) { testJobStoreGetCountByStatusAndType(t, ss) })
+ t.Run("JobUpdateOptimistically", func(t *testing.T) { testJobUpdateOptimistically(t, ss) })
+ t.Run("JobUpdateStatusUpdateStatusOptimistically", func(t *testing.T) { testJobUpdateStatusUpdateStatusOptimistically(t, ss) })
+ t.Run("JobDelete", func(t *testing.T) { testJobDelete(t, ss) })
+}
+
+func testJobSaveGet(t *testing.T, ss store.Store) {
+ job := &model.Job{
+ Id: model.NewId(),
+ Type: model.NewId(),
+ Status: model.NewId(),
+ Data: map[string]string{
+ "Processed": "0",
+ "Total": "12345",
+ "LastProcessed": "abcd",
+ },
+ }
+
+ if result := <-ss.Job().Save(job); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ defer func() {
+ <-ss.Job().Delete(job.Id)
+ }()
+
+ if result := <-ss.Job().Get(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.(*model.Job); received.Id != job.Id {
+ t.Fatal("received incorrect job after save")
+ } else if received.Data["Total"] != "12345" {
+ t.Fatal("data field was not retrieved successfully:", received.Data)
+ }
+}
+
+func testJobGetAllByType(t *testing.T, ss store.Store) {
+ jobType := model.NewId()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ },
+ {
+ Id: model.NewId(),
+ Type: model.NewId(),
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ if result := <-ss.Job().GetAllByType(jobType); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) != 2 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[0].Id && received[1].Id != jobs[0].Id {
+ t.Fatal("should've received first jobs")
+ } else if received[0].Id != jobs[1].Id && received[1].Id != jobs[1].Id {
+ t.Fatal("should've received second jobs")
+ }
+}
+
+func testJobGetAllByTypePage(t *testing.T, ss store.Store) {
+ jobType := model.NewId()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 1000,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 999,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 1001,
+ },
+ {
+ Id: model.NewId(),
+ Type: model.NewId(),
+ CreateAt: 1002,
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ if result := <-ss.Job().GetAllByTypePage(jobType, 0, 2); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) != 2 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[2].Id {
+ t.Fatal("should've received newest job first")
+ } else if received[1].Id != jobs[0].Id {
+ t.Fatal("should've received second newest job second")
+ }
+
+ if result := <-ss.Job().GetAllByTypePage(jobType, 2, 2); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) != 1 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[1].Id {
+ t.Fatal("should've received oldest job last")
+ }
+}
+
+func testJobGetAllPage(t *testing.T, ss store.Store) {
+ jobType := model.NewId()
+ createAtTime := model.GetMillis()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: createAtTime + 1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: createAtTime,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: createAtTime + 2,
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ if result := <-ss.Job().GetAllPage(0, 2); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) != 2 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[2].Id {
+ t.Fatal("should've received newest job first")
+ } else if received[1].Id != jobs[0].Id {
+ t.Fatal("should've received second newest job second")
+ }
+
+ if result := <-ss.Job().GetAllPage(2, 2); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) < 1 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[1].Id {
+ t.Fatal("should've received oldest job last")
+ }
+}
+
+func testJobGetAllByStatus(t *testing.T, ss store.Store) {
+ jobType := model.NewId()
+ status := model.NewId()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 1000,
+ Status: status,
+ Data: map[string]string{
+ "test": "data",
+ },
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 999,
+ Status: status,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 1001,
+ Status: status,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType,
+ CreateAt: 1002,
+ Status: model.NewId(),
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ if result := <-ss.Job().GetAllByStatus(status); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.Job); len(received) != 3 {
+ t.Fatal("received wrong number of jobs")
+ } else if received[0].Id != jobs[1].Id || received[1].Id != jobs[0].Id || received[2].Id != jobs[2].Id {
+ t.Fatal("should've received jobs ordered by CreateAt time")
+ } else if received[1].Data["test"] != "data" {
+ t.Fatal("should've received job data field back as saved")
+ }
+}
+
+func testJobStoreGetNewestJobByStatusAndType(t *testing.T, ss store.Store) {
+ jobType1 := model.NewId()
+ jobType2 := model.NewId()
+ status1 := model.NewId()
+ status2 := model.NewId()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 1001,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 1000,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType2,
+ CreateAt: 1003,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 1004,
+ Status: status2,
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ result := <-ss.Job().GetNewestJobByStatusAndType(status1, jobType1)
+ assert.Nil(t, result.Err)
+ assert.EqualValues(t, jobs[0].Id, result.Data.(*model.Job).Id)
+
+ result = <-ss.Job().GetNewestJobByStatusAndType(model.NewId(), model.NewId())
+ assert.Nil(t, result.Err)
+ assert.Nil(t, result.Data.(*model.Job))
+}
+
+func testJobStoreGetCountByStatusAndType(t *testing.T, ss store.Store) {
+ jobType1 := model.NewId()
+ jobType2 := model.NewId()
+ status1 := model.NewId()
+ status2 := model.NewId()
+
+ jobs := []*model.Job{
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 1000,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 999,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType2,
+ CreateAt: 1001,
+ Status: status1,
+ },
+ {
+ Id: model.NewId(),
+ Type: jobType1,
+ CreateAt: 1002,
+ Status: status2,
+ },
+ }
+
+ for _, job := range jobs {
+ store.Must(ss.Job().Save(job))
+ defer ss.Job().Delete(job.Id)
+ }
+
+ result := <-ss.Job().GetCountByStatusAndType(status1, jobType1)
+ assert.Nil(t, result.Err)
+ assert.EqualValues(t, 2, result.Data.(int64))
+
+ result = <-ss.Job().GetCountByStatusAndType(status2, jobType2)
+ assert.Nil(t, result.Err)
+ assert.EqualValues(t, 0, result.Data.(int64))
+
+ result = <-ss.Job().GetCountByStatusAndType(status1, jobType2)
+ assert.Nil(t, result.Err)
+ assert.EqualValues(t, 1, result.Data.(int64))
+
+ result = <-ss.Job().GetCountByStatusAndType(status2, jobType1)
+ assert.Nil(t, result.Err)
+ assert.EqualValues(t, 1, result.Data.(int64))
+}
+
+func testJobUpdateOptimistically(t *testing.T, ss store.Store) {
+ job := &model.Job{
+ Id: model.NewId(),
+ Type: model.JOB_TYPE_DATA_RETENTION,
+ CreateAt: model.GetMillis(),
+ Status: model.JOB_STATUS_PENDING,
+ }
+
+ if result := <-ss.Job().Save(job); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+ defer ss.Job().Delete(job.Id)
+
+ job.LastActivityAt = model.GetMillis()
+ job.Status = model.JOB_STATUS_IN_PROGRESS
+ job.Progress = 50
+ job.Data = map[string]string{
+ "Foo": "Bar",
+ }
+
+ if result := <-ss.Job().UpdateOptimistically(job, model.JOB_STATUS_SUCCESS); result.Err != nil {
+ if result.Data.(bool) {
+ t.Fatal("should have failed due to incorrect old status")
+ }
+ }
+
+ time.Sleep(2 * time.Millisecond)
+
+ if result := <-ss.Job().UpdateOptimistically(job, model.JOB_STATUS_PENDING); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if !result.Data.(bool) {
+ t.Fatal("Should have successfully updated")
+ }
+
+ var updatedJob *model.Job
+
+ if result := <-ss.Job().Get(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ updatedJob = result.Data.(*model.Job)
+ }
+
+ if updatedJob.Type != job.Type || updatedJob.CreateAt != job.CreateAt || updatedJob.Status != job.Status || updatedJob.LastActivityAt <= job.LastActivityAt || updatedJob.Progress != job.Progress || updatedJob.Data["Foo"] != job.Data["Foo"] {
+ t.Fatal("Some update property was not as expected")
+ }
+ }
+
+}
+
+func testJobUpdateStatusUpdateStatusOptimistically(t *testing.T, ss store.Store) {
+ job := &model.Job{
+ Id: model.NewId(),
+ Type: model.JOB_TYPE_DATA_RETENTION,
+ CreateAt: model.GetMillis(),
+ Status: model.JOB_STATUS_SUCCESS,
+ }
+
+ var lastUpdateAt int64
+ if result := <-ss.Job().Save(job); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ lastUpdateAt = result.Data.(*model.Job).LastActivityAt
+ }
+
+ defer ss.Job().Delete(job.Id)
+
+ time.Sleep(2 * time.Millisecond)
+
+ if result := <-ss.Job().UpdateStatus(job.Id, model.JOB_STATUS_PENDING); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ received := result.Data.(*model.Job)
+ if received.Status != model.JOB_STATUS_PENDING {
+ t.Fatal("status wasn't updated")
+ }
+ if received.LastActivityAt <= lastUpdateAt {
+ t.Fatal("lastActivityAt wasn't updated")
+ }
+ lastUpdateAt = received.LastActivityAt
+ }
+
+ time.Sleep(2 * time.Millisecond)
+
+ if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if result.Data.(bool) {
+ t.Fatal("should be false due to incorrect original status")
+ }
+ }
+
+ if result := <-ss.Job().Get(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ received := result.Data.(*model.Job)
+ if received.Status != model.JOB_STATUS_PENDING {
+ t.Fatal("should still be pending")
+ }
+ if received.LastActivityAt != lastUpdateAt {
+ t.Fatal("last activity at shouldn't have changed")
+ }
+ }
+
+ time.Sleep(2 * time.Millisecond)
+
+ if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_PENDING, model.JOB_STATUS_IN_PROGRESS); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if !result.Data.(bool) {
+ t.Fatal("should have succeeded")
+ }
+ }
+
+ var startAtSet int64
+ if result := <-ss.Job().Get(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ received := result.Data.(*model.Job)
+ if received.Status != model.JOB_STATUS_IN_PROGRESS {
+ t.Fatal("should be in progress")
+ }
+ if received.StartAt == 0 {
+ t.Fatal("received should have start at set")
+ }
+ if received.LastActivityAt <= lastUpdateAt {
+ t.Fatal("lastActivityAt wasn't updated")
+ }
+ lastUpdateAt = received.LastActivityAt
+ startAtSet = received.StartAt
+ }
+
+ time.Sleep(2 * time.Millisecond)
+
+ if result := <-ss.Job().UpdateStatusOptimistically(job.Id, model.JOB_STATUS_IN_PROGRESS, model.JOB_STATUS_SUCCESS); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if !result.Data.(bool) {
+ t.Fatal("should have succeeded")
+ }
+ }
+
+ if result := <-ss.Job().Get(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ received := result.Data.(*model.Job)
+ if received.Status != model.JOB_STATUS_SUCCESS {
+ t.Fatal("should be success status")
+ }
+ if received.StartAt != startAtSet {
+ t.Fatal("startAt should not have changed")
+ }
+ if received.LastActivityAt <= lastUpdateAt {
+ t.Fatal("lastActivityAt wasn't updated")
+ }
+ lastUpdateAt = received.LastActivityAt
+ }
+}
+
+func testJobDelete(t *testing.T, ss store.Store) {
+ job := store.Must(ss.Job().Save(&model.Job{
+ Id: model.NewId(),
+ })).(*model.Job)
+
+ if result := <-ss.Job().Delete(job.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
diff --git a/store/storetest/license_store.go b/store/storetest/license_store.go
new file mode 100644
index 000000000..452d37e7b
--- /dev/null
+++ b/store/storetest/license_store.go
@@ -0,0 +1,56 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestLicenseStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testLicenseStoreSave(t, ss) })
+ t.Run("Get", func(t *testing.T) { testLicenseStoreGet(t, ss) })
+}
+
+func testLicenseStoreSave(t *testing.T, ss store.Store) {
+ l1 := model.LicenseRecord{}
+ l1.Id = model.NewId()
+ l1.Bytes = "junk"
+
+ if err := (<-ss.License().Save(&l1)).Err; err != nil {
+ t.Fatal("couldn't save license record", err)
+ }
+
+ if err := (<-ss.License().Save(&l1)).Err; err != nil {
+ t.Fatal("shouldn't fail on trying to save existing license record", err)
+ }
+
+ l1.Id = ""
+
+ if err := (<-ss.License().Save(&l1)).Err; err == nil {
+ t.Fatal("should fail on invalid license", err)
+ }
+}
+
+func testLicenseStoreGet(t *testing.T, ss store.Store) {
+ l1 := model.LicenseRecord{}
+ l1.Id = model.NewId()
+ l1.Bytes = "junk"
+
+ store.Must(ss.License().Save(&l1))
+
+ if r := <-ss.License().Get(l1.Id); r.Err != nil {
+ t.Fatal("couldn't get license", r.Err)
+ } else {
+ if r.Data.(*model.LicenseRecord).Bytes != l1.Bytes {
+ t.Fatal("license bytes didn't match")
+ }
+ }
+
+ if err := (<-ss.License().Get("missing")).Err; err == nil {
+ t.Fatal("should fail on get license", err)
+ }
+}
diff --git a/store/storetest/oauth_store.go b/store/storetest/oauth_store.go
new file mode 100644
index 000000000..cd5df18da
--- /dev/null
+++ b/store/storetest/oauth_store.go
@@ -0,0 +1,435 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestOAuthStore(t *testing.T, ss store.Store) {
+ t.Run("SaveApp", func(t *testing.T) { testOAuthStoreSaveApp(t, ss) })
+ t.Run("GetApp", func(t *testing.T) { testOAuthStoreGetApp(t, ss) })
+ t.Run("UpdateApp", func(t *testing.T) { testOAuthStoreUpdateApp(t, ss) })
+ t.Run("SaveAccessData", func(t *testing.T) { testOAuthStoreSaveAccessData(t, ss) })
+ t.Run("OAuthUpdateAccessData", func(t *testing.T) { testOAuthUpdateAccessData(t, ss) })
+ t.Run("GetAccessData", func(t *testing.T) { testOAuthStoreGetAccessData(t, ss) })
+ t.Run("RemoveAccessData", func(t *testing.T) { testOAuthStoreRemoveAccessData(t, ss) })
+ t.Run("SaveAuthData", func(t *testing.T) { testOAuthStoreSaveAuthData(t, ss) })
+ t.Run("GetAuthData", func(t *testing.T) { testOAuthStoreGetAuthData(t, ss) })
+ t.Run("RemoveAuthData", func(t *testing.T) { testOAuthStoreRemoveAuthData(t, ss) })
+ t.Run("RemoveAuthDataByUser", func(t *testing.T) { testOAuthStoreRemoveAuthDataByUser(t, ss) })
+ t.Run("OAuthGetAuthorizedApps", func(t *testing.T) { testOAuthGetAuthorizedApps(t, ss) })
+ t.Run("OAuthGetAccessDataByUserForApp", func(t *testing.T) { testOAuthGetAccessDataByUserForApp(t, ss) })
+ t.Run("DeleteApp", func(t *testing.T) { testOAuthStoreDeleteApp(t, ss) })
+}
+
+func testOAuthStoreSaveApp(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+
+ // Try to save an app that already has an Id
+ a1.Id = model.NewId()
+ if err := (<-ss.OAuth().SaveApp(&a1)).Err; err == nil {
+ t.Fatal("Should have failed, cannot add an OAuth app cannot be save with an Id, it has to be updated")
+ }
+
+ // Try to save an Invalid App
+ a1.Id = ""
+ if err := (<-ss.OAuth().SaveApp(&a1)).Err; err == nil {
+ t.Fatal("Should have failed, app should be invalid cause it doesn' have a name set")
+ }
+
+ // Save the app
+ a1.Id = ""
+ a1.Name = "TestApp" + model.NewId()
+ if err := (<-ss.OAuth().SaveApp(&a1)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthStoreGetApp(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.Name = "TestApp" + model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+ store.Must(ss.OAuth().SaveApp(&a1))
+
+ // Lets try to get and app that does not exists
+ if err := (<-ss.OAuth().GetApp("fake0123456789abcderfgret1")).Err; err == nil {
+ t.Fatal("Should have failed. App does not exists")
+ }
+
+ if err := (<-ss.OAuth().GetApp(a1.Id)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ // Lets try and get the app from a user that hasn't created any apps
+ if result := (<-ss.OAuth().GetAppByUser("fake0123456789abcderfgret1", 0, 1000)); result.Err == nil {
+ if len(result.Data.([]*model.OAuthApp)) > 0 {
+ t.Fatal("Should have failed. Fake user hasn't created any apps")
+ }
+ } else {
+ t.Fatal(result.Err)
+ }
+
+ if err := (<-ss.OAuth().GetAppByUser(a1.CreatorId, 0, 1000)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.OAuth().GetApps(0, 1000)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthStoreUpdateApp(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.Name = "TestApp" + model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+ store.Must(ss.OAuth().SaveApp(&a1))
+
+ // temporarily save the created app id
+ id := a1.Id
+
+ a1.CreateAt = 1
+ a1.ClientSecret = "pwd"
+ a1.CreatorId = "12345678901234567890123456"
+
+ // Lets update the app by removing the name
+ a1.Name = ""
+ if result := <-ss.OAuth().UpdateApp(&a1); result.Err == nil {
+ t.Fatal("Should have failed. App name is not set")
+ }
+
+ // Lets not find the app that we are trying to update
+ a1.Id = "fake0123456789abcderfgret1"
+ a1.Name = "NewName"
+ if result := <-ss.OAuth().UpdateApp(&a1); result.Err == nil {
+ t.Fatal("Should have failed. Not able to find the app")
+ }
+
+ a1.Id = id
+ if result := <-ss.OAuth().UpdateApp(&a1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ ua1 := (result.Data.([2]*model.OAuthApp)[0])
+ if ua1.Name != "NewName" {
+ t.Fatal("name did not update")
+ }
+ if ua1.CreateAt == 1 {
+ t.Fatal("create at should not have updated")
+ }
+ if ua1.CreatorId == "12345678901234567890123456" {
+ t.Fatal("creator id should not have updated")
+ }
+ }
+}
+
+func testOAuthStoreSaveAccessData(t *testing.T, ss store.Store) {
+ a1 := model.AccessData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+
+ // Lets try and save an incomplete access data
+ if err := (<-ss.OAuth().SaveAccessData(&a1)).Err; err == nil {
+ t.Fatal("Should have failed. Access data needs the token")
+ }
+
+ a1.Token = model.NewId()
+ a1.RefreshToken = model.NewId()
+ a1.RedirectUri = "http://example.com"
+
+ if err := (<-ss.OAuth().SaveAccessData(&a1)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthUpdateAccessData(t *testing.T, ss store.Store) {
+ a1 := model.AccessData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Token = model.NewId()
+ a1.RefreshToken = model.NewId()
+ a1.ExpiresAt = model.GetMillis()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAccessData(&a1))
+
+ //Try to update to invalid Refresh Token
+ refreshToken := a1.RefreshToken
+ a1.RefreshToken = model.NewId() + "123"
+ if err := (<-ss.OAuth().UpdateAccessData(&a1)).Err; err == nil {
+ t.Fatal("Should have failed with invalid token")
+ }
+
+ //Try to update to invalid RedirectUri
+ a1.RefreshToken = model.NewId()
+ a1.RedirectUri = ""
+ if err := (<-ss.OAuth().UpdateAccessData(&a1)).Err; err == nil {
+ t.Fatal("Should have failed with invalid Redirect URI")
+ }
+
+ // Should update fine
+ a1.RedirectUri = "http://example.com"
+ if result := <-ss.OAuth().UpdateAccessData(&a1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ ra1 := result.Data.(*model.AccessData)
+ if ra1.RefreshToken == refreshToken {
+ t.Fatal("refresh tokens didn't match")
+ }
+ }
+}
+
+func testOAuthStoreGetAccessData(t *testing.T, ss store.Store) {
+ a1 := model.AccessData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Token = model.NewId()
+ a1.RefreshToken = model.NewId()
+ a1.ExpiresAt = model.GetMillis()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAccessData(&a1))
+
+ if err := (<-ss.OAuth().GetAccessData("invalidToken")).Err; err == nil {
+ t.Fatal("Should have failed. There is no data with an invalid token")
+ }
+
+ if result := <-ss.OAuth().GetAccessData(a1.Token); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ ra1 := result.Data.(*model.AccessData)
+ if a1.Token != ra1.Token {
+ t.Fatal("tokens didn't match")
+ }
+ }
+
+ if err := (<-ss.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.OAuth().GetPreviousAccessData("user", "junk")).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ // Try to get the Access data using an invalid refresh token
+ if err := (<-ss.OAuth().GetAccessDataByRefreshToken(a1.Token)).Err; err == nil {
+ t.Fatal("Should have failed. There is no data with an invalid token")
+ }
+
+ // Get the Access Data using the refresh token
+ if result := <-ss.OAuth().GetAccessDataByRefreshToken(a1.RefreshToken); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ ra1 := result.Data.(*model.AccessData)
+ if a1.RefreshToken != ra1.RefreshToken {
+ t.Fatal("tokens didn't match")
+ }
+ }
+}
+
+func testOAuthStoreRemoveAccessData(t *testing.T, ss store.Store) {
+ a1 := model.AccessData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Token = model.NewId()
+ a1.RefreshToken = model.NewId()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAccessData(&a1))
+
+ if err := (<-ss.OAuth().RemoveAccessData(a1.Token)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if result := (<-ss.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)); result.Err != nil {
+ } else {
+ if result.Data != nil {
+ t.Fatal("did not delete access token")
+ }
+ }
+}
+
+func testOAuthStoreSaveAuthData(t *testing.T, ss store.Store) {
+ a1 := model.AuthData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Code = model.NewId()
+ a1.RedirectUri = "http://example.com"
+ if err := (<-ss.OAuth().SaveAuthData(&a1)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthStoreGetAuthData(t *testing.T, ss store.Store) {
+ a1 := model.AuthData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Code = model.NewId()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAuthData(&a1))
+
+ if err := (<-ss.OAuth().GetAuthData(a1.Code)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthStoreRemoveAuthData(t *testing.T, ss store.Store) {
+ a1 := model.AuthData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Code = model.NewId()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAuthData(&a1))
+
+ if err := (<-ss.OAuth().RemoveAuthData(a1.Code)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.OAuth().GetAuthData(a1.Code)).Err; err == nil {
+ t.Fatal("should have errored - auth code removed")
+ }
+}
+
+func testOAuthStoreRemoveAuthDataByUser(t *testing.T, ss store.Store) {
+ a1 := model.AuthData{}
+ a1.ClientId = model.NewId()
+ a1.UserId = model.NewId()
+ a1.Code = model.NewId()
+ a1.RedirectUri = "http://example.com"
+ store.Must(ss.OAuth().SaveAuthData(&a1))
+
+ if err := (<-ss.OAuth().PermanentDeleteAuthDataByUser(a1.UserId)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testOAuthGetAuthorizedApps(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.Name = "TestApp" + model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+ store.Must(ss.OAuth().SaveApp(&a1))
+
+ // Lets try and get an Authorized app for a user who hasn't authorized it
+ if result := <-ss.OAuth().GetAuthorizedApps("fake0123456789abcderfgret1", 0, 1000); result.Err == nil {
+ if len(result.Data.([]*model.OAuthApp)) > 0 {
+ t.Fatal("Should have failed. Fake user hasn't authorized the app")
+ }
+ } else {
+ t.Fatal(result.Err)
+ }
+
+ // allow the app
+ p := model.Preference{}
+ p.UserId = a1.CreatorId
+ p.Category = model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP
+ p.Name = a1.Id
+ p.Value = "true"
+ store.Must(ss.Preference().Save(&model.Preferences{p}))
+
+ if result := <-ss.OAuth().GetAuthorizedApps(a1.CreatorId, 0, 1000); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ apps := result.Data.([]*model.OAuthApp)
+ if len(apps) == 0 {
+ t.Fatal("It should have return apps")
+ }
+ }
+}
+
+func testOAuthGetAccessDataByUserForApp(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.Name = "TestApp" + model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+ store.Must(ss.OAuth().SaveApp(&a1))
+
+ // allow the app
+ p := model.Preference{}
+ p.UserId = a1.CreatorId
+ p.Category = model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP
+ p.Name = a1.Id
+ p.Value = "true"
+ store.Must(ss.Preference().Save(&model.Preferences{p}))
+
+ if result := <-ss.OAuth().GetAuthorizedApps(a1.CreatorId, 0, 1000); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ apps := result.Data.([]*model.OAuthApp)
+ if len(apps) == 0 {
+ t.Fatal("It should have return apps")
+ }
+ }
+
+ // save the token
+ ad1 := model.AccessData{}
+ ad1.ClientId = a1.Id
+ ad1.UserId = a1.CreatorId
+ ad1.Token = model.NewId()
+ ad1.RefreshToken = model.NewId()
+ ad1.RedirectUri = "http://example.com"
+
+ if err := (<-ss.OAuth().SaveAccessData(&ad1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if result := <-ss.OAuth().GetAccessDataByUserForApp(a1.CreatorId, a1.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ accessData := result.Data.([]*model.AccessData)
+ if len(accessData) == 0 {
+ t.Fatal("It should have return access data")
+ }
+ }
+}
+
+func testOAuthStoreDeleteApp(t *testing.T, ss store.Store) {
+ a1 := model.OAuthApp{}
+ a1.CreatorId = model.NewId()
+ a1.Name = "TestApp" + model.NewId()
+ a1.CallbackUrls = []string{"https://nowhere.com"}
+ a1.Homepage = "https://nowhere.com"
+ store.Must(ss.OAuth().SaveApp(&a1))
+
+ // delete a non-existent app
+ if err := (<-ss.OAuth().DeleteApp("fakeclientId")).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ s1.Token = model.NewId()
+ s1.IsOAuth = true
+
+ store.Must(ss.Session().Save(&s1))
+
+ ad1 := model.AccessData{}
+ ad1.ClientId = a1.Id
+ ad1.UserId = a1.CreatorId
+ ad1.Token = s1.Token
+ ad1.RefreshToken = model.NewId()
+ ad1.RedirectUri = "http://example.com"
+
+ store.Must(ss.OAuth().SaveAccessData(&ad1))
+
+ if err := (<-ss.OAuth().DeleteApp(a1.Id)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.Session().Get(s1.Token)).Err; err == nil {
+ t.Fatal("should error - session should be deleted")
+ }
+
+ if err := (<-ss.OAuth().GetAccessData(s1.Token)).Err; err == nil {
+ t.Fatal("should error - access data should be deleted")
+ }
+}
diff --git a/store/storetest/post_store.go b/store/storetest/post_store.go
new file mode 100644
index 000000000..f721bed64
--- /dev/null
+++ b/store/storetest/post_store.go
@@ -0,0 +1,1684 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+ "github.com/mattermost/mattermost-server/utils"
+)
+
+func TestPostStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testPostStoreSave(t, ss) })
+ t.Run("Get", func(t *testing.T) { testPostStoreGet(t, ss) })
+ t.Run("GetSingle", func(t *testing.T) { testPostStoreGetSingle(t, ss) })
+ t.Run("GetEtagCache", func(t *testing.T) { testGetEtagCache(t, ss) })
+ t.Run("Update", func(t *testing.T) { testPostStoreUpdate(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testPostStoreDelete(t, ss) })
+ t.Run("Delete1Level", func(t *testing.T) { testPostStoreDelete1Level(t, ss) })
+ t.Run("Delete2Level", func(t *testing.T) { testPostStoreDelete2Level(t, ss) })
+ t.Run("PermDelete1Level", func(t *testing.T) { testPostStorePermDelete1Level(t, ss) })
+ t.Run("PermDelete1Level2", func(t *testing.T) { testPostStorePermDelete1Level2(t, ss) })
+ t.Run("GetWithChildren", func(t *testing.T) { testPostStoreGetWithChildren(t, ss) })
+ t.Run("GetPostsWtihDetails", func(t *testing.T) { testPostStoreGetPostsWtihDetails(t, ss) })
+ t.Run("GetPostsBeforeAfter", func(t *testing.T) { testPostStoreGetPostsBeforeAfter(t, ss) })
+ t.Run("GetPostsSince", func(t *testing.T) { testPostStoreGetPostsSince(t, ss) })
+ t.Run("Search", func(t *testing.T) { testPostStoreSearch(t, ss) })
+ t.Run("UserCountsWithPostsByDay", func(t *testing.T) { testUserCountsWithPostsByDay(t, ss) })
+ t.Run("PostCountsByDay", func(t *testing.T) { testPostCountsByDay(t, ss) })
+ t.Run("GetFlaggedPostsForTeam", func(t *testing.T) { testPostStoreGetFlaggedPostsForTeam(t, ss) })
+ t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
+ t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
+ t.Run("GetPostsCreatedAt", func(t *testing.T) { testPostStoreGetPostsCreatedAt(t, ss) })
+ t.Run("Overwrite", func(t *testing.T) { testPostStoreOverwrite(t, ss) })
+ t.Run("GetPostsByIds", func(t *testing.T) { testPostStoreGetPostsByIds(t, ss) })
+ t.Run("GetPostsBatchForIndexing", func(t *testing.T) { testPostStoreGetPostsBatchForIndexing(t, ss) })
+ t.Run("PermanentDeleteBatch", func(t *testing.T) { testPostStorePermanentDeleteBatch(t, ss) })
+}
+
+func testPostStoreSave(t *testing.T, ss store.Store) {
+ o1 := model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+
+ if err := (<-ss.Post().Save(&o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Post().Save(&o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+}
+
+func testPostStoreGet(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+
+ etag1 := (<-ss.Post().GetEtag(o1.ChannelId, false)).Data.(string)
+ if strings.Index(etag1, model.CurrentVersion+".") != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ etag2 := (<-ss.Post().GetEtag(o1.ChannelId, false)).Data.(string)
+ if strings.Index(etag2, fmt.Sprintf("%v.%v", model.CurrentVersion, o1.UpdateAt)) != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ if r1 := <-ss.Post().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.PostList).Posts[o1.Id].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned post")
+ }
+ }
+
+ if err := (<-ss.Post().Get("123")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ if err := (<-ss.Post().Get("")).Err; err == nil {
+ t.Fatal("should fail for blank post ids")
+ }
+}
+
+func testPostStoreGetSingle(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ if r1 := <-ss.Post().GetSingle(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Post).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned post")
+ }
+ }
+
+ if err := (<-ss.Post().GetSingle("123")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testGetEtagCache(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+
+ etag1 := (<-ss.Post().GetEtag(o1.ChannelId, true)).Data.(string)
+ if strings.Index(etag1, model.CurrentVersion+".") != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ // This one should come from the cache
+ etag2 := (<-ss.Post().GetEtag(o1.ChannelId, true)).Data.(string)
+ if strings.Index(etag2, model.CurrentVersion+".") != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ // We have not invalidated the cache so this should be the same as above
+ etag3 := (<-ss.Post().GetEtag(o1.ChannelId, true)).Data.(string)
+ if strings.Index(etag3, etag2) != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ ss.Post().InvalidateLastPostTimeCache(o1.ChannelId)
+
+ // Invalidated cache so we should get a good result
+ etag4 := (<-ss.Post().GetEtag(o1.ChannelId, true)).Data.(string)
+ if strings.Index(etag4, fmt.Sprintf("%v.%v", model.CurrentVersion, o1.UpdateAt)) != 0 {
+ t.Fatal("Invalid Etag")
+ }
+}
+
+func testPostStoreUpdate(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ ro1 := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o1.Id]
+ ro2 := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o2.Id]
+ ro3 := (<-ss.Post().Get(o3.Id)).Data.(*model.PostList).Posts[o3.Id]
+
+ if ro1.Message != o1.Message {
+ t.Fatal("Failed to save/get")
+ }
+
+ o1a := &model.Post{}
+ *o1a = *ro1
+ o1a.Message = ro1.Message + "BBBBBBBBBB"
+ if result := <-ss.Post().Update(o1a, ro1); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro1a := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o1.Id]
+
+ if ro1a.Message != o1a.Message {
+ t.Fatal("Failed to update/get")
+ }
+
+ o2a := &model.Post{}
+ *o2a = *ro2
+ o2a.Message = ro2.Message + "DDDDDDD"
+ if result := <-ss.Post().Update(o2a, ro2); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro2a := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o2.Id]
+
+ if ro2a.Message != o2a.Message {
+ t.Fatal("Failed to update/get")
+ }
+
+ o3a := &model.Post{}
+ *o3a = *ro3
+ o3a.Message = ro3.Message + "WWWWWWW"
+ if result := <-ss.Post().Update(o3a, ro3); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro3a := (<-ss.Post().Get(o3.Id)).Data.(*model.PostList).Posts[o3.Id]
+
+ if ro3a.Message != o3a.Message && ro3a.Hashtags != o3a.Hashtags {
+ t.Fatal("Failed to update/get")
+ }
+
+ o4 := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ Message: model.NewId(),
+ Filenames: []string{"test"},
+ })).(*model.Post)
+
+ ro4 := (<-ss.Post().Get(o4.Id)).Data.(*model.PostList).Posts[o4.Id]
+
+ o4a := &model.Post{}
+ *o4a = *ro4
+ o4a.Filenames = []string{}
+ o4a.FileIds = []string{model.NewId()}
+ if result := <-ss.Post().Update(o4a, ro4); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if ro4a := store.Must(ss.Post().Get(o4.Id)).(*model.PostList).Posts[o4.Id]; len(ro4a.Filenames) != 0 {
+ t.Fatal("Failed to clear Filenames")
+ } else if len(ro4a.FileIds) != 1 {
+ t.Fatal("Failed to set FileIds")
+ }
+}
+
+func testPostStoreDelete(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+
+ etag1 := (<-ss.Post().GetEtag(o1.ChannelId, false)).Data.(string)
+ if strings.Index(etag1, model.CurrentVersion+".") != 0 {
+ t.Fatal("Invalid Etag")
+ }
+
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ if r1 := <-ss.Post().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.PostList).Posts[o1.Id].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned post")
+ }
+ }
+
+ if r2 := <-ss.Post().Delete(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+
+ etag2 := (<-ss.Post().GetEtag(o1.ChannelId, false)).Data.(string)
+ if strings.Index(etag2, model.CurrentVersion+".") != 0 {
+ t.Fatal("Invalid Etag")
+ }
+}
+
+func testPostStoreDelete1Level(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ if r2 := <-ss.Post().Delete(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o1.Id)); r3.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r4 := (<-ss.Post().Get(o2.Id)); r4.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+}
+
+func testPostStoreDelete2Level(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.ParentId = o2.Id
+ o3.RootId = o1.Id
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ o4 := &model.Post{}
+ o4.ChannelId = model.NewId()
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+
+ if r2 := <-ss.Post().Delete(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o1.Id)); r3.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r4 := (<-ss.Post().Get(o2.Id)); r4.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r5 := (<-ss.Post().Get(o3.Id)); r5.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r6 := <-ss.Post().Get(o4.Id); r6.Err != nil {
+ t.Fatal(r6.Err)
+ }
+}
+
+func testPostStorePermDelete1Level(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = model.NewId()
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ if r2 := <-ss.Post().PermanentDeleteByUser(o2.UserId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o1.Id)); r3.Err != nil {
+ t.Fatal("Deleted id shouldn't have failed")
+ }
+
+ if r4 := (<-ss.Post().Get(o2.Id)); r4.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r2 := <-ss.Post().PermanentDeleteByChannel(o3.ChannelId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o3.Id)); r3.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+}
+
+func testPostStorePermDelete1Level2(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = model.NewId()
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ if r2 := <-ss.Post().PermanentDeleteByUser(o1.UserId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Post().Get(o1.Id)); r3.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r4 := (<-ss.Post().Get(o2.Id)); r4.Err == nil {
+ t.Fatal("Deleted id should have failed")
+ }
+
+ if r5 := (<-ss.Post().Get(o3.Id)); r5.Err != nil {
+ t.Fatal("Deleted id shouldn't have failed")
+ }
+}
+
+func testPostStoreGetWithChildren(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.ParentId = o2.Id
+ o3.RootId = o1.Id
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ if r1 := <-ss.Post().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ pl := r1.Data.(*model.PostList)
+ if len(pl.Posts) != 3 {
+ t.Fatal("invalid returned post")
+ }
+ }
+
+ store.Must(ss.Post().Delete(o3.Id, model.GetMillis()))
+
+ if r2 := <-ss.Post().Get(o1.Id); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ pl := r2.Data.(*model.PostList)
+ if len(pl.Posts) != 2 {
+ t.Fatal("invalid returned post")
+ }
+ }
+
+ store.Must(ss.Post().Delete(o2.Id, model.GetMillis()))
+
+ if r3 := <-ss.Post().Get(o1.Id); r3.Err != nil {
+ t.Fatal(r3.Err)
+ } else {
+ pl := r3.Data.(*model.PostList)
+ if len(pl.Posts) != 1 {
+ t.Fatal("invalid returned post")
+ }
+ }
+}
+
+func testPostStoreGetPostsWtihDetails(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = o1.ChannelId
+ o2a.UserId = model.NewId()
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a.ParentId = o1.Id
+ o2a.RootId = o1.Id
+ o2a = (<-ss.Post().Save(o2a)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.ParentId = o1.Id
+ o3.RootId = o1.Id
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o4 := &model.Post{}
+ o4.ChannelId = o1.ChannelId
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o5 := &model.Post{}
+ o5.ChannelId = o1.ChannelId
+ o5.UserId = model.NewId()
+ o5.Message = "zz" + model.NewId() + "b"
+ o5.ParentId = o4.Id
+ o5.RootId = o4.Id
+ o5 = (<-ss.Post().Save(o5)).Data.(*model.Post)
+
+ r1 := (<-ss.Post().GetPosts(o1.ChannelId, 0, 4, false)).Data.(*model.PostList)
+
+ if r1.Order[0] != o5.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[1] != o4.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[2] != o3.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[3] != o2a.Id {
+ t.Fatal("invalid order")
+ }
+
+ if len(r1.Posts) != 6 { //the last 4, + o1 (o2a and o3's parent) + o2 (in same thread as o2a and o3)
+ t.Fatal("wrong size")
+ }
+
+ if r1.Posts[o1.Id].Message != o1.Message {
+ t.Fatal("Missing parent")
+ }
+
+ r2 := (<-ss.Post().GetPosts(o1.ChannelId, 0, 4, true)).Data.(*model.PostList)
+
+ if r2.Order[0] != o5.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[1] != o4.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[2] != o3.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[3] != o2a.Id {
+ t.Fatal("invalid order")
+ }
+
+ if len(r2.Posts) != 6 { //the last 4, + o1 (o2a and o3's parent) + o2 (in same thread as o2a and o3)
+ t.Fatal("wrong size")
+ }
+
+ if r2.Posts[o1.Id].Message != o1.Message {
+ t.Fatal("Missing parent")
+ }
+}
+
+func testPostStoreGetPostsBeforeAfter(t *testing.T, ss store.Store) {
+ o0 := &model.Post{}
+ o0.ChannelId = model.NewId()
+ o0.UserId = model.NewId()
+ o0.Message = "zz" + model.NewId() + "b"
+ o0 = (<-ss.Post().Save(o0)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = o1.ChannelId
+ o2a.UserId = model.NewId()
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a.ParentId = o1.Id
+ o2a.RootId = o1.Id
+ o2a = (<-ss.Post().Save(o2a)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.ParentId = o1.Id
+ o3.RootId = o1.Id
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o4 := &model.Post{}
+ o4.ChannelId = o1.ChannelId
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o5 := &model.Post{}
+ o5.ChannelId = o1.ChannelId
+ o5.UserId = model.NewId()
+ o5.Message = "zz" + model.NewId() + "b"
+ o5.ParentId = o4.Id
+ o5.RootId = o4.Id
+ o5 = (<-ss.Post().Save(o5)).Data.(*model.Post)
+
+ r1 := (<-ss.Post().GetPostsBefore(o1.ChannelId, o1.Id, 4, 0)).Data.(*model.PostList)
+
+ if len(r1.Posts) != 0 {
+ t.Fatal("Wrong size")
+ }
+
+ r2 := (<-ss.Post().GetPostsAfter(o1.ChannelId, o1.Id, 4, 0)).Data.(*model.PostList)
+
+ if r2.Order[0] != o4.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[1] != o3.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[2] != o2a.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r2.Order[3] != o2.Id {
+ t.Fatal("invalid order")
+ }
+
+ if len(r2.Posts) != 5 {
+ t.Fatal("wrong size")
+ }
+
+ r3 := (<-ss.Post().GetPostsBefore(o3.ChannelId, o3.Id, 2, 0)).Data.(*model.PostList)
+
+ if r3.Order[0] != o2a.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r3.Order[1] != o2.Id {
+ t.Fatal("invalid order")
+ }
+
+ if len(r3.Posts) != 3 {
+ t.Fatal("wrong size")
+ }
+
+ if r3.Posts[o1.Id].Message != o1.Message {
+ t.Fatal("Missing parent")
+ }
+}
+
+func testPostStoreGetPostsSince(t *testing.T, ss store.Store) {
+ o0 := &model.Post{}
+ o0.ChannelId = model.NewId()
+ o0.UserId = model.NewId()
+ o0.Message = "zz" + model.NewId() + "b"
+ o0 = (<-ss.Post().Save(o0)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = o1.ChannelId
+ o2a.UserId = model.NewId()
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a.ParentId = o1.Id
+ o2a.RootId = o1.Id
+ o2a = (<-ss.Post().Save(o2a)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.ParentId = o1.Id
+ o3.RootId = o1.Id
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o4 := &model.Post{}
+ o4.ChannelId = o1.ChannelId
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o5 := &model.Post{}
+ o5.ChannelId = o1.ChannelId
+ o5.UserId = model.NewId()
+ o5.Message = "zz" + model.NewId() + "b"
+ o5.ParentId = o4.Id
+ o5.RootId = o4.Id
+ o5 = (<-ss.Post().Save(o5)).Data.(*model.Post)
+
+ r1 := (<-ss.Post().GetPostsSince(o1.ChannelId, o1.CreateAt, false)).Data.(*model.PostList)
+
+ if r1.Order[0] != o5.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[1] != o4.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[2] != o3.Id {
+ t.Fatal("invalid order")
+ }
+
+ if r1.Order[3] != o2a.Id {
+ t.Fatal("invalid order")
+ }
+
+ if len(r1.Posts) != 6 {
+ t.Fatal("wrong size")
+ }
+
+ if r1.Posts[o1.Id].Message != o1.Message {
+ t.Fatal("Missing parent")
+ }
+
+ r2 := (<-ss.Post().GetPostsSince(o1.ChannelId, o5.UpdateAt, true)).Data.(*model.PostList)
+
+ if len(r2.Order) != 0 {
+ t.Fatal("wrong size ", len(r2.Posts))
+ }
+}
+
+func testPostStoreSearch(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+ userId := model.NewId()
+
+ c1 := &model.Channel{}
+ c1.TeamId = teamId
+ c1.DisplayName = "Channel1"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = (<-ss.Channel().Save(c1)).Data.(*model.Channel)
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = c1.Id
+ m1.UserId = userId
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+ store.Must(ss.Channel().SaveMember(&m1))
+
+ c2 := &model.Channel{}
+ c2.TeamId = teamId
+ c2.DisplayName = "Channel1"
+ c2.Name = "zz" + model.NewId() + "b"
+ c2.Type = model.CHANNEL_OPEN
+ c2 = (<-ss.Channel().Save(c2)).Data.(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = model.NewId()
+ o1.Message = "corey mattermost new york"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o1a := &model.Post{}
+ o1a.ChannelId = c1.Id
+ o1a.UserId = model.NewId()
+ o1a.Message = "corey mattermost new york"
+ o1a.Type = model.POST_JOIN_CHANNEL
+ o1a = (<-ss.Post().Save(o1a)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c1.Id
+ o2.UserId = model.NewId()
+ o2.Message = "New Jersey is where John is from"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = c2.Id
+ o3.UserId = model.NewId()
+ o3.Message = "New Jersey is where John is from corey new york"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ o4 := &model.Post{}
+ o4.ChannelId = c1.Id
+ o4.UserId = model.NewId()
+ o4.Hashtags = "#hashtag"
+ o4.Message = "(message)blargh"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+
+ o5 := &model.Post{}
+ o5.ChannelId = c1.Id
+ o5.UserId = model.NewId()
+ o5.Hashtags = "#secret #howdy"
+ o5 = (<-ss.Post().Save(o5)).Data.(*model.Post)
+
+ r1 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "corey", IsHashtag: false})).Data.(*model.PostList)
+ if len(r1.Order) != 1 || r1.Order[0] != o1.Id {
+ t.Fatal("returned wrong search result")
+ }
+
+ r3 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "new", IsHashtag: false})).Data.(*model.PostList)
+ if len(r3.Order) != 2 || (r3.Order[0] != o1.Id && r3.Order[1] != o1.Id) {
+ t.Fatal("returned wrong search result")
+ }
+
+ r4 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "john", IsHashtag: false})).Data.(*model.PostList)
+ if len(r4.Order) != 1 || r4.Order[0] != o2.Id {
+ t.Fatal("returned wrong search result")
+ }
+
+ r5 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter*", IsHashtag: false})).Data.(*model.PostList)
+ if len(r5.Order) != 1 || r5.Order[0] != o1.Id {
+ t.Fatal("returned wrong search result")
+ }
+
+ r6 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "#hashtag", IsHashtag: true})).Data.(*model.PostList)
+ if len(r6.Order) != 1 || r6.Order[0] != o4.Id {
+ t.Fatal("returned wrong search result")
+ }
+
+ r7 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "#secret", IsHashtag: true})).Data.(*model.PostList)
+ if len(r7.Order) != 1 || r7.Order[0] != o5.Id {
+ t.Fatal("returned wrong search result")
+ }
+
+ r8 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "@thisshouldmatchnothing", IsHashtag: true})).Data.(*model.PostList)
+ if len(r8.Order) != 0 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r9 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "mattermost jersey", IsHashtag: false})).Data.(*model.PostList)
+ if len(r9.Order) != 0 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r9a := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "corey new york", IsHashtag: false})).Data.(*model.PostList)
+ if len(r9a.Order) != 1 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r10 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter* jer*", IsHashtag: false})).Data.(*model.PostList)
+ if len(r10.Order) != 0 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r11 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "message blargh", IsHashtag: false})).Data.(*model.PostList)
+ if len(r11.Order) != 1 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r12 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "blargh>", IsHashtag: false})).Data.(*model.PostList)
+ if len(r12.Order) != 1 {
+ t.Fatal("returned wrong search result")
+ }
+
+ r13 := (<-ss.Post().Search(teamId, userId, &model.SearchParams{Terms: "Jersey corey", IsHashtag: false, OrTerms: true})).Data.(*model.PostList)
+ if len(r13.Order) != 2 {
+ t.Fatal("returned wrong search result")
+ }
+}
+
+func testUserCountsWithPostsByDay(t *testing.T, ss store.Store) {
+ t1 := &model.Team{}
+ t1.DisplayName = "DisplayName"
+ t1.Name = "zz" + model.NewId() + "b"
+ t1.Email = model.NewId() + "@nowhere.com"
+ t1.Type = model.TEAM_OPEN
+ t1 = store.Must(ss.Team().Save(t1)).(*model.Team)
+
+ c1 := &model.Channel{}
+ c1.TeamId = t1.Id
+ c1.DisplayName = "Channel2"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = store.Must(ss.Channel().Save(c1)).(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = model.NewId()
+ o1.CreateAt = utils.MillisFromTime(utils.Yesterday())
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = store.Must(ss.Post().Save(o1)).(*model.Post)
+
+ o1a := &model.Post{}
+ o1a.ChannelId = c1.Id
+ o1a.UserId = model.NewId()
+ o1a.CreateAt = o1.CreateAt
+ o1a.Message = "zz" + model.NewId() + "b"
+ o1a = store.Must(ss.Post().Save(o1a)).(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c1.Id
+ o2.UserId = model.NewId()
+ o2.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24)
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = store.Must(ss.Post().Save(o2)).(*model.Post)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = c1.Id
+ o2a.UserId = o2.UserId
+ o2a.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24)
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a = store.Must(ss.Post().Save(o2a)).(*model.Post)
+
+ if r1 := <-ss.Post().AnalyticsUserCountsWithPostsByDay(t1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ row1 := r1.Data.(model.AnalyticsRows)[0]
+ if row1.Value != 2 {
+ t.Fatal("wrong value")
+ }
+
+ row2 := r1.Data.(model.AnalyticsRows)[1]
+ if row2.Value != 1 {
+ t.Fatal("wrong value")
+ }
+ }
+}
+
+func testPostCountsByDay(t *testing.T, ss store.Store) {
+ t1 := &model.Team{}
+ t1.DisplayName = "DisplayName"
+ t1.Name = "zz" + model.NewId() + "b"
+ t1.Email = model.NewId() + "@nowhere.com"
+ t1.Type = model.TEAM_OPEN
+ t1 = store.Must(ss.Team().Save(t1)).(*model.Team)
+
+ c1 := &model.Channel{}
+ c1.TeamId = t1.Id
+ c1.DisplayName = "Channel2"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = store.Must(ss.Channel().Save(c1)).(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = model.NewId()
+ o1.CreateAt = utils.MillisFromTime(utils.Yesterday())
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = store.Must(ss.Post().Save(o1)).(*model.Post)
+
+ o1a := &model.Post{}
+ o1a.ChannelId = c1.Id
+ o1a.UserId = model.NewId()
+ o1a.CreateAt = o1.CreateAt
+ o1a.Message = "zz" + model.NewId() + "b"
+ o1a = store.Must(ss.Post().Save(o1a)).(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c1.Id
+ o2.UserId = model.NewId()
+ o2.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24 * 2)
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = store.Must(ss.Post().Save(o2)).(*model.Post)
+
+ o2a := &model.Post{}
+ o2a.ChannelId = c1.Id
+ o2a.UserId = o2.UserId
+ o2a.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24 * 2)
+ o2a.Message = "zz" + model.NewId() + "b"
+ o2a = store.Must(ss.Post().Save(o2a)).(*model.Post)
+
+ time.Sleep(1 * time.Second)
+
+ if r1 := <-ss.Post().AnalyticsPostCountsByDay(t1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ row1 := r1.Data.(model.AnalyticsRows)[0]
+ if row1.Value != 2 {
+ t.Fatal(row1)
+ }
+
+ row2 := r1.Data.(model.AnalyticsRows)[1]
+ if row2.Value != 2 {
+ t.Fatal("wrong value")
+ }
+ }
+
+ if r1 := <-ss.Post().AnalyticsPostCount(t1.Id, false, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) != 4 {
+ t.Fatal("wrong value")
+ }
+ }
+}
+
+func testPostStoreGetFlaggedPostsForTeam(t *testing.T, ss store.Store) {
+ c1 := &model.Channel{}
+ c1.TeamId = model.NewId()
+ c1.DisplayName = "Channel1"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = store.Must(ss.Channel().Save(c1)).(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.DeleteAt = 1
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o4 := &model.Post{}
+ o4.ChannelId = model.NewId()
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ c2 := &model.Channel{}
+ c2.DisplayName = "DMChannel1"
+ c2.Name = "zz" + model.NewId() + "b"
+ c2.Type = model.CHANNEL_DIRECT
+
+ m1 := &model.ChannelMember{}
+ m1.ChannelId = c2.Id
+ m1.UserId = o1.UserId
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := &model.ChannelMember{}
+ m2.ChannelId = c2.Id
+ m2.UserId = model.NewId()
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ c2 = store.Must(ss.Channel().SaveDirectChannel(c2, m1, m2)).(*model.Channel)
+
+ o5 := &model.Post{}
+ o5.ChannelId = c2.Id
+ o5.UserId = m2.UserId
+ o5.Message = "zz" + model.NewId() + "b"
+ o5 = (<-ss.Post().Save(o5)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ r1 := (<-ss.Post().GetFlaggedPosts(o1.ChannelId, 0, 2)).Data.(*model.PostList)
+
+ if len(r1.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ preferences := model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o1.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r2 := (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 2)).Data.(*model.PostList)
+
+ if len(r2.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o2.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r3 := (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 1)).Data.(*model.PostList)
+
+ if len(r3.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r3 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 1, 1)).Data.(*model.PostList)
+
+ if len(r3.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r3 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 1000, 10)).Data.(*model.PostList)
+
+ if len(r3.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ r4 := (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o3.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r4 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o4.Id,
+ Value: "true",
+ },
+ }
+ store.Must(ss.Preference().Save(&preferences))
+
+ r4 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+
+ r4 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, model.NewId(), 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 0 {
+ t.Fatal("should have 0 posts")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o5.Id,
+ Value: "true",
+ },
+ }
+ store.Must(ss.Preference().Save(&preferences))
+
+ r4 = (<-ss.Post().GetFlaggedPostsForTeam(o1.UserId, c1.TeamId, 0, 10)).Data.(*model.PostList)
+
+ if len(r4.Order) != 3 {
+ t.Fatal("should have 3 posts")
+ }
+}
+
+func testPostStoreGetFlaggedPosts(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.DeleteAt = 1
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ r1 := (<-ss.Post().GetFlaggedPosts(o1.UserId, 0, 2)).Data.(*model.PostList)
+
+ if len(r1.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ preferences := model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o1.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r2 := (<-ss.Post().GetFlaggedPosts(o1.UserId, 0, 2)).Data.(*model.PostList)
+
+ if len(r2.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o2.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r3 := (<-ss.Post().GetFlaggedPosts(o1.UserId, 0, 1)).Data.(*model.PostList)
+
+ if len(r3.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r3 = (<-ss.Post().GetFlaggedPosts(o1.UserId, 1, 1)).Data.(*model.PostList)
+
+ if len(r3.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r3 = (<-ss.Post().GetFlaggedPosts(o1.UserId, 1000, 10)).Data.(*model.PostList)
+
+ if len(r3.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ r4 := (<-ss.Post().GetFlaggedPosts(o1.UserId, 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+
+ preferences = model.Preferences{
+ {
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o3.Id,
+ Value: "true",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ r4 = (<-ss.Post().GetFlaggedPosts(o1.UserId, 0, 2)).Data.(*model.PostList)
+
+ if len(r4.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+}
+
+func testPostStoreGetFlaggedPostsForChannel(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ // deleted post
+ o3 := &model.Post{}
+ o3.ChannelId = model.NewId()
+ o3.UserId = o1.ChannelId
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.DeleteAt = 1
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o4 := &model.Post{}
+ o4.ChannelId = model.NewId()
+ o4.UserId = model.NewId()
+ o4.Message = "zz" + model.NewId() + "b"
+ o4 = (<-ss.Post().Save(o4)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ r := (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 0, 10)).Data.(*model.PostList)
+
+ if len(r.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ preference := model.Preference{
+ UserId: o1.UserId,
+ Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
+ Name: o1.Id,
+ Value: "true",
+ }
+
+ store.Must(ss.Preference().Save(&model.Preferences{preference}))
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 0, 10)).Data.(*model.PostList)
+
+ if len(r.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ preference.Name = o2.Id
+ store.Must(ss.Preference().Save(&model.Preferences{preference}))
+
+ preference.Name = o3.Id
+ store.Must(ss.Preference().Save(&model.Preferences{preference}))
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 0, 1)).Data.(*model.PostList)
+
+ if len(r.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 1, 1)).Data.(*model.PostList)
+
+ if len(r.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 1000, 10)).Data.(*model.PostList)
+
+ if len(r.Order) != 0 {
+ t.Fatal("should be empty")
+ }
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o1.ChannelId, 0, 10)).Data.(*model.PostList)
+
+ if len(r.Order) != 2 {
+ t.Fatal("should have 2 posts")
+ }
+
+ preference.Name = o4.Id
+ store.Must(ss.Preference().Save(&model.Preferences{preference}))
+
+ r = (<-ss.Post().GetFlaggedPostsForChannel(o1.UserId, o4.ChannelId, 0, 10)).Data.(*model.PostList)
+
+ if len(r.Order) != 1 {
+ t.Fatal("should have 1 post")
+ }
+}
+
+func testPostStoreGetPostsCreatedAt(t *testing.T, ss store.Store) {
+ createTime := model.GetMillis()
+
+ o0 := &model.Post{}
+ o0.ChannelId = model.NewId()
+ o0.UserId = model.NewId()
+ o0.Message = "zz" + model.NewId() + "b"
+ o0.CreateAt = createTime
+ o0 = (<-ss.Post().Save(o0)).Data.(*model.Post)
+
+ o1 := &model.Post{}
+ o1.ChannelId = o0.Id
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "b"
+ o0.CreateAt = createTime
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "b"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ o3 := &model.Post{}
+ o3.ChannelId = model.NewId()
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "b"
+ o3.CreateAt = createTime
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+ time.Sleep(2 * time.Millisecond)
+
+ r1 := (<-ss.Post().GetPostsCreatedAt(o1.ChannelId, createTime)).Data.([]*model.Post)
+
+ if len(r1) != 2 {
+ t.Fatalf("Got the wrong number of posts.")
+ }
+}
+
+func testPostStoreOverwrite(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
+ o2.ParentId = o1.Id
+ o2.RootId = o1.Id
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ ro1 := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o1.Id]
+ ro2 := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o2.Id]
+ ro3 := (<-ss.Post().Get(o3.Id)).Data.(*model.PostList).Posts[o3.Id]
+
+ if ro1.Message != o1.Message {
+ t.Fatal("Failed to save/get")
+ }
+
+ o1a := &model.Post{}
+ *o1a = *ro1
+ o1a.Message = ro1.Message + "BBBBBBBBBB"
+ if result := <-ss.Post().Overwrite(o1a); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro1a := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o1.Id]
+
+ if ro1a.Message != o1a.Message {
+ t.Fatal("Failed to overwrite/get")
+ }
+
+ o2a := &model.Post{}
+ *o2a = *ro2
+ o2a.Message = ro2.Message + "DDDDDDD"
+ if result := <-ss.Post().Overwrite(o2a); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro2a := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o2.Id]
+
+ if ro2a.Message != o2a.Message {
+ t.Fatal("Failed to overwrite/get")
+ }
+
+ o3a := &model.Post{}
+ *o3a = *ro3
+ o3a.Message = ro3.Message + "WWWWWWW"
+ if result := <-ss.Post().Overwrite(o3a); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ ro3a := (<-ss.Post().Get(o3.Id)).Data.(*model.PostList).Posts[o3.Id]
+
+ if ro3a.Message != o3a.Message && ro3a.Hashtags != o3a.Hashtags {
+ t.Fatal("Failed to overwrite/get")
+ }
+
+ o4 := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ Message: model.NewId(),
+ Filenames: []string{"test"},
+ })).(*model.Post)
+
+ ro4 := (<-ss.Post().Get(o4.Id)).Data.(*model.PostList).Posts[o4.Id]
+
+ o4a := &model.Post{}
+ *o4a = *ro4
+ o4a.Filenames = []string{}
+ o4a.FileIds = []string{model.NewId()}
+ if result := <-ss.Post().Overwrite(o4a); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if ro4a := store.Must(ss.Post().Get(o4.Id)).(*model.PostList).Posts[o4.Id]; len(ro4a.Filenames) != 0 {
+ t.Fatal("Failed to clear Filenames")
+ } else if len(ro4a.FileIds) != 1 {
+ t.Fatal("Failed to set FileIds")
+ }
+}
+
+func testPostStoreGetPostsByIds(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = o1.ChannelId
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = o1.ChannelId
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ ro1 := (<-ss.Post().Get(o1.Id)).Data.(*model.PostList).Posts[o1.Id]
+ ro2 := (<-ss.Post().Get(o2.Id)).Data.(*model.PostList).Posts[o2.Id]
+ ro3 := (<-ss.Post().Get(o3.Id)).Data.(*model.PostList).Posts[o3.Id]
+
+ postIds := []string{
+ ro1.Id,
+ ro2.Id,
+ ro3.Id,
+ }
+
+ if ro4 := store.Must(ss.Post().GetPostsByIds(postIds)).([]*model.Post); len(ro4) != 3 {
+ t.Fatalf("Expected 3 posts in results. Got %v", len(ro4))
+ }
+
+ store.Must(ss.Post().Delete(ro1.Id, model.GetMillis()))
+
+ if ro5 := store.Must(ss.Post().GetPostsByIds(postIds)).([]*model.Post); len(ro5) != 2 {
+ t.Fatalf("Expected 2 posts in results. Got %v", len(ro5))
+ }
+}
+
+func testPostStoreGetPostsBatchForIndexing(t *testing.T, ss store.Store) {
+ c1 := &model.Channel{}
+ c1.TeamId = model.NewId()
+ c1.DisplayName = "Channel1"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = (<-ss.Channel().Save(c1)).Data.(*model.Channel)
+
+ c2 := &model.Channel{}
+ c2.TeamId = model.NewId()
+ c2.DisplayName = "Channel2"
+ c2.Name = "zz" + model.NewId() + "b"
+ c2.Type = model.CHANNEL_OPEN
+ c2 = (<-ss.Channel().Save(c2)).Data.(*model.Channel)
+
+ o1 := &model.Post{}
+ o1.ChannelId = c1.Id
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = c2.Id
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = c1.Id
+ o3.UserId = model.NewId()
+ o3.ParentId = o1.Id
+ o3.RootId = o1.Id
+ o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ if r := store.Must(ss.Post().GetPostsBatchForIndexing(o1.CreateAt, 100)).([]*model.PostForIndexing); len(r) != 3 {
+ t.Fatalf("Expected 3 posts in results. Got %v", len(r))
+ } else {
+ for _, p := range r {
+ if p.Id == o1.Id {
+ if p.TeamId != c1.TeamId {
+ t.Fatalf("Unexpected team ID")
+ }
+ if p.ParentCreateAt != nil {
+ t.Fatalf("Unexpected parent create at")
+ }
+ } else if p.Id == o2.Id {
+ if p.TeamId != c2.TeamId {
+ t.Fatalf("Unexpected team ID")
+ }
+ if p.ParentCreateAt != nil {
+ t.Fatalf("Unexpected parent create at")
+ }
+ } else if p.Id == o3.Id {
+ if p.TeamId != c1.TeamId {
+ t.Fatalf("Unexpected team ID")
+ }
+ if *p.ParentCreateAt != o1.CreateAt {
+ t.Fatalf("Unexpected parent create at")
+ }
+ } else {
+ t.Fatalf("unexpected post returned")
+ }
+ }
+ }
+}
+
+func testPostStorePermanentDeleteBatch(t *testing.T, ss store.Store) {
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1.CreateAt = 1000
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ o2 := &model.Post{}
+ o2.ChannelId = model.NewId()
+ o2.UserId = model.NewId()
+ o2.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o2.CreateAt = 1000
+ o2 = (<-ss.Post().Save(o2)).Data.(*model.Post)
+
+ o3 := &model.Post{}
+ o3.ChannelId = model.NewId()
+ o3.UserId = model.NewId()
+ o3.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o3.CreateAt = 100000
+ o3 = (<-ss.Post().Save(o3)).Data.(*model.Post)
+
+ store.Must(ss.Post().PermanentDeleteBatch(2000, 1000))
+
+ if p := <-ss.Post().Get(o1.Id); p.Err == nil {
+ t.Fatalf("Should have not found post 1 after purge")
+ }
+
+ if p := <-ss.Post().Get(o2.Id); p.Err == nil {
+ t.Fatalf("Should have not found post 2 after purge")
+ }
+
+ if p := <-ss.Post().Get(o3.Id); p.Err != nil {
+ t.Fatalf("Should have found post 3 after purge")
+ }
+}
diff --git a/store/storetest/preference_store.go b/store/storetest/preference_store.go
new file mode 100644
index 000000000..edd0e9549
--- /dev/null
+++ b/store/storetest/preference_store.go
@@ -0,0 +1,447 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestPreferenceStore(t *testing.T, ss store.Store) {
+ t.Run("PreferenceSave", func(t *testing.T) { testPreferenceSave(t, ss) })
+ t.Run("PreferenceGet", func(t *testing.T) { testPreferenceGet(t, ss) })
+ t.Run("PreferenceGetCategory", func(t *testing.T) { testPreferenceGetCategory(t, ss) })
+ t.Run("PreferenceGetAll", func(t *testing.T) { testPreferenceGetAll(t, ss) })
+ t.Run("PreferenceDeleteByUser", func(t *testing.T) { testPreferenceDeleteByUser(t, ss) })
+ t.Run("IsFeatureEnabled", func(t *testing.T) { testIsFeatureEnabled(t, ss) })
+ t.Run("PreferenceDelete", func(t *testing.T) { testPreferenceDelete(t, ss) })
+ t.Run("PreferenceDeleteCategory", func(t *testing.T) { testPreferenceDeleteCategory(t, ss) })
+ t.Run("PreferenceDeleteCategoryAndName", func(t *testing.T) { testPreferenceDeleteCategoryAndName(t, ss) })
+ t.Run("PreferenceCleanupFlagsBatch", func(t *testing.T) { testPreferenceCleanupFlagsBatch(t, ss) })
+}
+
+func testPreferenceSave(t *testing.T, ss store.Store) {
+ id := model.NewId()
+
+ preferences := model.Preferences{
+ {
+ UserId: id,
+ Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
+ Name: model.NewId(),
+ Value: "value1a",
+ },
+ {
+ UserId: id,
+ Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
+ Name: model.NewId(),
+ Value: "value1b",
+ },
+ }
+ if count := store.Must(ss.Preference().Save(&preferences)); count != 2 {
+ t.Fatal("got incorrect number of rows saved")
+ }
+
+ for _, preference := range preferences {
+ if data := store.Must(ss.Preference().Get(preference.UserId, preference.Category, preference.Name)).(model.Preference); preference != data {
+ t.Fatal("got incorrect preference after first Save")
+ }
+ }
+
+ preferences[0].Value = "value2a"
+ preferences[1].Value = "value2b"
+ if count := store.Must(ss.Preference().Save(&preferences)); count != 2 {
+ t.Fatal("got incorrect number of rows saved")
+ }
+
+ for _, preference := range preferences {
+ if data := store.Must(ss.Preference().Get(preference.UserId, preference.Category, preference.Name)).(model.Preference); preference != data {
+ t.Fatal("got incorrect preference after second Save")
+ }
+ }
+}
+
+func testPreferenceGet(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ category := model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW
+ name := model.NewId()
+
+ preferences := model.Preferences{
+ {
+ UserId: userId,
+ Category: category,
+ Name: name,
+ },
+ {
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ },
+ {
+ UserId: userId,
+ Category: model.NewId(),
+ Name: name,
+ },
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: name,
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ if result := <-ss.Preference().Get(userId, category, name); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(model.Preference); data != preferences[0] {
+ t.Fatal("got incorrect preference")
+ }
+
+ // make sure getting a missing preference fails
+ if result := <-ss.Preference().Get(model.NewId(), model.NewId(), model.NewId()); result.Err == nil {
+ t.Fatal("no error on getting a missing preference")
+ }
+}
+
+func testPreferenceGetCategory(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ category := model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW
+ name := model.NewId()
+
+ preferences := model.Preferences{
+ {
+ UserId: userId,
+ Category: category,
+ Name: name,
+ },
+ // same user/category, different name
+ {
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ },
+ // same user/name, different category
+ {
+ UserId: userId,
+ Category: model.NewId(),
+ Name: name,
+ },
+ // same name/category, different user
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: name,
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ if result := <-ss.Preference().GetCategory(userId, category); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(model.Preferences); len(data) != 2 {
+ t.Fatal("got the wrong number of preferences")
+ } else if !((data[0] == preferences[0] && data[1] == preferences[1]) || (data[0] == preferences[1] && data[1] == preferences[0])) {
+ t.Fatal("got incorrect preferences")
+ }
+
+ // make sure getting a missing preference category doesn't fail
+ if result := <-ss.Preference().GetCategory(model.NewId(), model.NewId()); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(model.Preferences); len(data) != 0 {
+ t.Fatal("shouldn't have got any preferences")
+ }
+}
+
+func testPreferenceGetAll(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ category := model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW
+ name := model.NewId()
+
+ preferences := model.Preferences{
+ {
+ UserId: userId,
+ Category: category,
+ Name: name,
+ },
+ // same user/category, different name
+ {
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ },
+ // same user/name, different category
+ {
+ UserId: userId,
+ Category: model.NewId(),
+ Name: name,
+ },
+ // same name/category, different user
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: name,
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ if result := <-ss.Preference().GetAll(userId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(model.Preferences); len(data) != 3 {
+ t.Fatal("got the wrong number of preferences")
+ } else {
+ for i := 0; i < 3; i++ {
+ if data[0] != preferences[i] && data[1] != preferences[i] && data[2] != preferences[i] {
+ t.Fatal("got incorrect preferences")
+ }
+ }
+ }
+}
+
+func testPreferenceDeleteByUser(t *testing.T, ss store.Store) {
+ userId := model.NewId()
+ category := model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW
+ name := model.NewId()
+
+ preferences := model.Preferences{
+ {
+ UserId: userId,
+ Category: category,
+ Name: name,
+ },
+ // same user/category, different name
+ {
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ },
+ // same user/name, different category
+ {
+ UserId: userId,
+ Category: model.NewId(),
+ Name: name,
+ },
+ // same name/category, different user
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: name,
+ },
+ }
+
+ store.Must(ss.Preference().Save(&preferences))
+
+ if result := <-ss.Preference().PermanentDeleteByUser(userId); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testIsFeatureEnabled(t *testing.T, ss store.Store) {
+ feature1 := "testFeat1"
+ feature2 := "testFeat2"
+ feature3 := "testFeat3"
+
+ userId := model.NewId()
+ category := model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS
+
+ features := model.Preferences{
+ {
+ UserId: userId,
+ Category: category,
+ Name: store.FEATURE_TOGGLE_PREFIX + feature1,
+ Value: "true",
+ },
+ {
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ Value: "false",
+ },
+ {
+ UserId: userId,
+ Category: model.NewId(),
+ Name: store.FEATURE_TOGGLE_PREFIX + feature1,
+ Value: "false",
+ },
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: store.FEATURE_TOGGLE_PREFIX + feature2,
+ Value: "false",
+ },
+ {
+ UserId: model.NewId(),
+ Category: category,
+ Name: store.FEATURE_TOGGLE_PREFIX + feature3,
+ Value: "foobar",
+ },
+ }
+
+ store.Must(ss.Preference().Save(&features))
+
+ if result := <-ss.Preference().IsFeatureEnabled(feature1, userId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(bool); data != true {
+ t.Fatalf("got incorrect setting for feature1, %v=%v", true, data)
+ }
+
+ if result := <-ss.Preference().IsFeatureEnabled(feature2, userId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(bool); data != false {
+ t.Fatalf("got incorrect setting for feature2, %v=%v", false, data)
+ }
+
+ // make sure we get false if something different than "true" or "false" has been saved to database
+ if result := <-ss.Preference().IsFeatureEnabled(feature3, userId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(bool); data != false {
+ t.Fatalf("got incorrect setting for feature3, %v=%v", false, data)
+ }
+
+ // make sure false is returned if a non-existent feature is queried
+ if result := <-ss.Preference().IsFeatureEnabled("someOtherFeature", userId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if data := result.Data.(bool); data != false {
+ t.Fatalf("got incorrect setting for non-existent feature 'someOtherFeature', %v=%v", false, data)
+ }
+}
+
+func testPreferenceDelete(t *testing.T, ss store.Store) {
+ preference := model.Preference{
+ UserId: model.NewId(),
+ Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
+ Name: model.NewId(),
+ Value: "value1a",
+ }
+
+ store.Must(ss.Preference().Save(&model.Preferences{preference}))
+
+ if prefs := store.Must(ss.Preference().GetAll(preference.UserId)).(model.Preferences); len([]model.Preference(prefs)) != 1 {
+ t.Fatal("should've returned 1 preference")
+ }
+
+ if result := <-ss.Preference().Delete(preference.UserId, preference.Category, preference.Name); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if prefs := store.Must(ss.Preference().GetAll(preference.UserId)).(model.Preferences); len([]model.Preference(prefs)) != 0 {
+ t.Fatal("should've returned no preferences")
+ }
+}
+
+func testPreferenceDeleteCategory(t *testing.T, ss store.Store) {
+ category := model.NewId()
+ userId := model.NewId()
+
+ preference1 := model.Preference{
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ Value: "value1a",
+ }
+
+ preference2 := model.Preference{
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ Value: "value1a",
+ }
+
+ store.Must(ss.Preference().Save(&model.Preferences{preference1, preference2}))
+
+ if prefs := store.Must(ss.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 2 {
+ t.Fatal("should've returned 2 preferences")
+ }
+
+ if result := <-ss.Preference().DeleteCategory(userId, category); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if prefs := store.Must(ss.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 0 {
+ t.Fatal("should've returned no preferences")
+ }
+}
+
+func testPreferenceDeleteCategoryAndName(t *testing.T, ss store.Store) {
+ category := model.NewId()
+ name := model.NewId()
+ userId := model.NewId()
+ userId2 := model.NewId()
+
+ preference1 := model.Preference{
+ UserId: userId,
+ Category: category,
+ Name: name,
+ Value: "value1a",
+ }
+
+ preference2 := model.Preference{
+ UserId: userId2,
+ Category: category,
+ Name: name,
+ Value: "value1a",
+ }
+
+ store.Must(ss.Preference().Save(&model.Preferences{preference1, preference2}))
+
+ if prefs := store.Must(ss.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 1 {
+ t.Fatal("should've returned 1 preference")
+ }
+
+ if prefs := store.Must(ss.Preference().GetAll(userId2)).(model.Preferences); len([]model.Preference(prefs)) != 1 {
+ t.Fatal("should've returned 1 preference")
+ }
+
+ if result := <-ss.Preference().DeleteCategoryAndName(category, name); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if prefs := store.Must(ss.Preference().GetAll(userId)).(model.Preferences); len([]model.Preference(prefs)) != 0 {
+ t.Fatal("should've returned no preferences")
+ }
+
+ if prefs := store.Must(ss.Preference().GetAll(userId2)).(model.Preferences); len([]model.Preference(prefs)) != 0 {
+ t.Fatal("should've returned no preferences")
+ }
+}
+
+func testPreferenceCleanupFlagsBatch(t *testing.T, ss store.Store) {
+ category := model.PREFERENCE_CATEGORY_FLAGGED_POST
+ userId := model.NewId()
+
+ o1 := &model.Post{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = userId
+ o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
+ o1.CreateAt = 1000
+ o1 = (<-ss.Post().Save(o1)).Data.(*model.Post)
+
+ preference1 := model.Preference{
+ UserId: userId,
+ Category: category,
+ Name: o1.Id,
+ Value: "true",
+ }
+
+ preference2 := model.Preference{
+ UserId: userId,
+ Category: category,
+ Name: model.NewId(),
+ Value: "true",
+ }
+
+ store.Must(ss.Preference().Save(&model.Preferences{preference1, preference2}))
+
+ result := <-ss.Preference().CleanupFlagsBatch(10000)
+ assert.Nil(t, result.Err)
+
+ result = <-ss.Preference().Get(userId, category, preference1.Name)
+ assert.Nil(t, result.Err)
+
+ result = <-ss.Preference().Get(userId, category, preference2.Name)
+ assert.NotNil(t, result.Err)
+}
diff --git a/store/storetest/reaction_store.go b/store/storetest/reaction_store.go
new file mode 100644
index 000000000..1b5128426
--- /dev/null
+++ b/store/storetest/reaction_store.go
@@ -0,0 +1,350 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestReactionStore(t *testing.T, ss store.Store) {
+ t.Run("ReactionSave", func(t *testing.T) { testReactionSave(t, ss) })
+ t.Run("ReactionDelete", func(t *testing.T) { testReactionDelete(t, ss) })
+ t.Run("ReactionGetForPost", func(t *testing.T) { testReactionGetForPost(t, ss) })
+ t.Run("ReactionDeleteAllWithEmojiName", func(t *testing.T) { testReactionDeleteAllWithEmojiName(t, ss) })
+ t.Run("PermanentDeleteBatch", func(t *testing.T) { testReactionStorePermanentDeleteBatch(t, ss) })
+}
+
+func testReactionSave(t *testing.T, ss store.Store) {
+ post := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+ firstUpdateAt := post.UpdateAt
+
+ reaction1 := &model.Reaction{
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: model.NewId(),
+ }
+ if result := <-ss.Reaction().Save(reaction1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if saved := result.Data.(*model.Reaction); saved.UserId != reaction1.UserId ||
+ saved.PostId != reaction1.PostId || saved.EmojiName != reaction1.EmojiName {
+ t.Fatal("should've saved reaction and returned it")
+ }
+
+ var secondUpdateAt int64
+ if postList := store.Must(ss.Post().Get(reaction1.PostId)).(*model.PostList); !postList.Posts[post.Id].HasReactions {
+ t.Fatal("should've set HasReactions = true on post")
+ } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt {
+ t.Fatal("should've marked post as updated when HasReactions changed")
+ } else {
+ secondUpdateAt = postList.Posts[post.Id].UpdateAt
+ }
+
+ if result := <-ss.Reaction().Save(reaction1); result.Err != nil {
+ t.Log(result.Err)
+ t.Fatal("should've allowed saving a duplicate reaction")
+ }
+
+ // different user
+ reaction2 := &model.Reaction{
+ UserId: model.NewId(),
+ PostId: reaction1.PostId,
+ EmojiName: reaction1.EmojiName,
+ }
+ if result := <-ss.Reaction().Save(reaction2); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if postList := store.Must(ss.Post().Get(reaction2.PostId)).(*model.PostList); postList.Posts[post.Id].UpdateAt != secondUpdateAt {
+ t.Fatal("shouldn't mark as updated when HasReactions hasn't changed")
+ }
+
+ // different post
+ reaction3 := &model.Reaction{
+ UserId: reaction1.UserId,
+ PostId: model.NewId(),
+ EmojiName: reaction1.EmojiName,
+ }
+ if result := <-ss.Reaction().Save(reaction3); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ // different emoji
+ reaction4 := &model.Reaction{
+ UserId: reaction1.UserId,
+ PostId: reaction1.PostId,
+ EmojiName: model.NewId(),
+ }
+ if result := <-ss.Reaction().Save(reaction4); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ // invalid reaction
+ reaction5 := &model.Reaction{
+ UserId: reaction1.UserId,
+ PostId: reaction1.PostId,
+ }
+ if result := <-ss.Reaction().Save(reaction5); result.Err == nil {
+ t.Fatal("should've failed for invalid reaction")
+ }
+}
+
+func testReactionDelete(t *testing.T, ss store.Store) {
+ post := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+
+ reaction := &model.Reaction{
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: model.NewId(),
+ }
+
+ store.Must(ss.Reaction().Save(reaction))
+ firstUpdateAt := store.Must(ss.Post().Get(reaction.PostId)).(*model.PostList).Posts[post.Id].UpdateAt
+
+ if result := <-ss.Reaction().Delete(reaction); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.Reaction().GetForPost(post.Id, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if len(result.Data.([]*model.Reaction)) != 0 {
+ t.Fatal("should've deleted reaction")
+ }
+
+ if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); postList.Posts[post.Id].HasReactions {
+ t.Fatal("should've set HasReactions = false on post")
+ } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt {
+ t.Fatal("shouldn't mark as updated when HasReactions has changed after deleting reactions")
+ }
+}
+
+func testReactionGetForPost(t *testing.T, ss store.Store) {
+ postId := model.NewId()
+
+ userId := model.NewId()
+
+ reactions := []*model.Reaction{
+ {
+ UserId: userId,
+ PostId: postId,
+ EmojiName: "smile",
+ },
+ {
+ UserId: model.NewId(),
+ PostId: postId,
+ EmojiName: "smile",
+ },
+ {
+ UserId: userId,
+ PostId: postId,
+ EmojiName: "sad",
+ },
+ {
+ UserId: userId,
+ PostId: model.NewId(),
+ EmojiName: "angry",
+ },
+ }
+
+ for _, reaction := range reactions {
+ store.Must(ss.Reaction().Save(reaction))
+ }
+
+ if result := <-ss.Reaction().GetForPost(postId, false); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 {
+ t.Fatal("should've returned 3 reactions")
+ } else {
+ for _, reaction := range reactions {
+ found := false
+
+ for _, returnedReaction := range returned {
+ if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId &&
+ returnedReaction.EmojiName == reaction.EmojiName {
+ found = true
+ break
+ }
+ }
+
+ if !found && reaction.PostId == postId {
+ t.Fatalf("should've returned reaction for post %v", reaction)
+ } else if found && reaction.PostId != postId {
+ t.Fatal("shouldn't have returned reaction for another post")
+ }
+ }
+ }
+
+ // Should return cached item
+ if result := <-ss.Reaction().GetForPost(postId, true); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 {
+ t.Fatal("should've returned 3 reactions")
+ } else {
+ for _, reaction := range reactions {
+ found := false
+
+ for _, returnedReaction := range returned {
+ if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId &&
+ returnedReaction.EmojiName == reaction.EmojiName {
+ found = true
+ break
+ }
+ }
+
+ if !found && reaction.PostId == postId {
+ t.Fatalf("should've returned reaction for post %v", reaction)
+ } else if found && reaction.PostId != postId {
+ t.Fatal("shouldn't have returned reaction for another post")
+ }
+ }
+ }
+}
+
+func testReactionDeleteAllWithEmojiName(t *testing.T, ss store.Store) {
+ emojiToDelete := model.NewId()
+
+ post := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+ post2 := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+ post3 := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+
+ userId := model.NewId()
+
+ reactions := []*model.Reaction{
+ {
+ UserId: userId,
+ PostId: post.Id,
+ EmojiName: emojiToDelete,
+ },
+ {
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: emojiToDelete,
+ },
+ {
+ UserId: userId,
+ PostId: post.Id,
+ EmojiName: "sad",
+ },
+ {
+ UserId: userId,
+ PostId: post2.Id,
+ EmojiName: "angry",
+ },
+ {
+ UserId: userId,
+ PostId: post3.Id,
+ EmojiName: emojiToDelete,
+ },
+ }
+
+ for _, reaction := range reactions {
+ store.Must(ss.Reaction().Save(reaction))
+ }
+
+ if result := <-ss.Reaction().DeleteAllWithEmojiName(emojiToDelete); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ // check that the reactions were deleted
+ if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 {
+ t.Fatal("should've only removed reactions with emoji name")
+ } else {
+ for _, reaction := range returned {
+ if reaction.EmojiName == "smile" {
+ t.Fatal("should've removed reaction with emoji name")
+ }
+ }
+ }
+
+ if returned := store.Must(ss.Reaction().GetForPost(post2.Id, false)).([]*model.Reaction); len(returned) != 1 {
+ t.Fatal("should've only removed reactions with emoji name")
+ }
+
+ if returned := store.Must(ss.Reaction().GetForPost(post3.Id, false)).([]*model.Reaction); len(returned) != 0 {
+ t.Fatal("should've only removed reactions with emoji name")
+ }
+
+ // check that the posts are updated
+ if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); !postList.Posts[post.Id].HasReactions {
+ t.Fatal("post should still have reactions")
+ }
+
+ if postList := store.Must(ss.Post().Get(post2.Id)).(*model.PostList); !postList.Posts[post2.Id].HasReactions {
+ t.Fatal("post should still have reactions")
+ }
+
+ if postList := store.Must(ss.Post().Get(post3.Id)).(*model.PostList); postList.Posts[post3.Id].HasReactions {
+ t.Fatal("post shouldn't have reactions any more")
+ }
+}
+
+func testReactionStorePermanentDeleteBatch(t *testing.T, ss store.Store) {
+ post := store.Must(ss.Post().Save(&model.Post{
+ ChannelId: model.NewId(),
+ UserId: model.NewId(),
+ })).(*model.Post)
+
+ reactions := []*model.Reaction{
+ {
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: "sad",
+ CreateAt: 1000,
+ },
+ {
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: "sad",
+ CreateAt: 1500,
+ },
+ {
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: "sad",
+ CreateAt: 2000,
+ },
+ {
+ UserId: model.NewId(),
+ PostId: post.Id,
+ EmojiName: "sad",
+ CreateAt: 2000,
+ },
+ }
+
+ // Need to hang on to a reaction to delete later in order to clear the cache, as "allowFromCache" isn't honoured any more.
+ var lastReaction *model.Reaction
+ for _, reaction := range reactions {
+ lastReaction = store.Must(ss.Reaction().Save(reaction)).(*model.Reaction)
+ }
+
+ if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 4 {
+ t.Fatal("expected 4 reactions")
+ }
+
+ store.Must(ss.Reaction().PermanentDeleteBatch(1800, 1000))
+
+ // This is to force a clear of the cache.
+ store.Must(ss.Reaction().Delete(lastReaction))
+
+ if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 {
+ t.Fatalf("expected 1 reaction. Got: %v", len(returned))
+ }
+}
diff --git a/store/storetest/session_store.go b/store/storetest/session_store.go
new file mode 100644
index 000000000..3d35b91ad
--- /dev/null
+++ b/store/storetest/session_store.go
@@ -0,0 +1,250 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestSessionStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testSessionStoreSave(t, ss) })
+ t.Run("SessionGet", func(t *testing.T) { testSessionGet(t, ss) })
+ t.Run("SessionGetWithDeviceId", func(t *testing.T) { testSessionGetWithDeviceId(t, ss) })
+ t.Run("SessionRemove", func(t *testing.T) { testSessionRemove(t, ss) })
+ t.Run("SessionRemoveAll", func(t *testing.T) { testSessionRemoveAll(t, ss) })
+ t.Run("SessionRemoveByUser", func(t *testing.T) { testSessionRemoveByUser(t, ss) })
+ t.Run("SessionRemoveToken", func(t *testing.T) { testSessionRemoveToken(t, ss) })
+ t.Run("SessionUpdateDeviceId", func(t *testing.T) { testSessionUpdateDeviceId(t, ss) })
+ t.Run("SessionUpdateDeviceId2", func(t *testing.T) { testSessionUpdateDeviceId2(t, ss) })
+ t.Run("UpdateLastActivityAt", func(t *testing.T) { testSessionStoreUpdateLastActivityAt(t, ss) })
+ t.Run("SessionCount", func(t *testing.T) { testSessionCount(t, ss) })
+}
+
+func testSessionStoreSave(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+
+ if err := (<-ss.Session().Save(&s1)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testSessionGet(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ s2 := model.Session{}
+ s2.UserId = s1.UserId
+ store.Must(ss.Session().Save(&s2))
+
+ s3 := model.Session{}
+ s3.UserId = s1.UserId
+ s3.ExpiresAt = 1
+ store.Must(ss.Session().Save(&s3))
+
+ if rs1 := (<-ss.Session().Get(s1.Id)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if rs1.Data.(*model.Session).Id != s1.Id {
+ t.Fatal("should match")
+ }
+ }
+
+ if rs2 := (<-ss.Session().GetSessions(s1.UserId)); rs2.Err != nil {
+ t.Fatal(rs2.Err)
+ } else {
+ if len(rs2.Data.([]*model.Session)) != 2 {
+ t.Fatal("should match len")
+ }
+ }
+}
+
+func testSessionGetWithDeviceId(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ s1.ExpiresAt = model.GetMillis() + 10000
+ store.Must(ss.Session().Save(&s1))
+
+ s2 := model.Session{}
+ s2.UserId = s1.UserId
+ s2.DeviceId = model.NewId()
+ s2.ExpiresAt = model.GetMillis() + 10000
+ store.Must(ss.Session().Save(&s2))
+
+ s3 := model.Session{}
+ s3.UserId = s1.UserId
+ s3.ExpiresAt = 1
+ s3.DeviceId = model.NewId()
+ store.Must(ss.Session().Save(&s3))
+
+ if rs1 := (<-ss.Session().GetSessionsWithActiveDeviceIds(s1.UserId)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if len(rs1.Data.([]*model.Session)) != 1 {
+ t.Fatal("should match len")
+ }
+ }
+}
+
+func testSessionRemove(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().Get(s1.Id)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if rs1.Data.(*model.Session).Id != s1.Id {
+ t.Fatal("should match")
+ }
+ }
+
+ store.Must(ss.Session().Remove(s1.Id))
+
+ if rs2 := (<-ss.Session().Get(s1.Id)); rs2.Err == nil {
+ t.Fatal("should have been removed")
+ }
+}
+
+func testSessionRemoveAll(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().Get(s1.Id)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if rs1.Data.(*model.Session).Id != s1.Id {
+ t.Fatal("should match")
+ }
+ }
+
+ store.Must(ss.Session().RemoveAllSessions())
+
+ if rs2 := (<-ss.Session().Get(s1.Id)); rs2.Err == nil {
+ t.Fatal("should have been removed")
+ }
+}
+
+func testSessionRemoveByUser(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().Get(s1.Id)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if rs1.Data.(*model.Session).Id != s1.Id {
+ t.Fatal("should match")
+ }
+ }
+
+ store.Must(ss.Session().PermanentDeleteSessionsByUser(s1.UserId))
+
+ if rs2 := (<-ss.Session().Get(s1.Id)); rs2.Err == nil {
+ t.Fatal("should have been removed")
+ }
+}
+
+func testSessionRemoveToken(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().Get(s1.Id)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ } else {
+ if rs1.Data.(*model.Session).Id != s1.Id {
+ t.Fatal("should match")
+ }
+ }
+
+ store.Must(ss.Session().Remove(s1.Token))
+
+ if rs2 := (<-ss.Session().Get(s1.Id)); rs2.Err == nil {
+ t.Fatal("should have been removed")
+ }
+
+ if rs3 := (<-ss.Session().GetSessions(s1.UserId)); rs3.Err != nil {
+ t.Fatal(rs3.Err)
+ } else {
+ if len(rs3.Data.([]*model.Session)) != 0 {
+ t.Fatal("should match len")
+ }
+ }
+}
+
+func testSessionUpdateDeviceId(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890", s1.ExpiresAt)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ }
+
+ s2 := model.Session{}
+ s2.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s2))
+
+ if rs2 := (<-ss.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890", s1.ExpiresAt)); rs2.Err != nil {
+ t.Fatal(rs2.Err)
+ }
+}
+
+func testSessionUpdateDeviceId2(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if rs1 := (<-ss.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE_REACT_NATIVE+":1234567890", s1.ExpiresAt)); rs1.Err != nil {
+ t.Fatal(rs1.Err)
+ }
+
+ s2 := model.Session{}
+ s2.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s2))
+
+ if rs2 := (<-ss.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE_REACT_NATIVE+":1234567890", s1.ExpiresAt)); rs2.Err != nil {
+ t.Fatal(rs2.Err)
+ }
+}
+
+func testSessionStoreUpdateLastActivityAt(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ store.Must(ss.Session().Save(&s1))
+
+ if err := (<-ss.Session().UpdateLastActivityAt(s1.Id, 1234567890)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.Session().Get(s1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Session).LastActivityAt != 1234567890 {
+ t.Fatal("LastActivityAt not updated correctly")
+ }
+ }
+
+}
+
+func testSessionCount(t *testing.T, ss store.Store) {
+ s1 := model.Session{}
+ s1.UserId = model.NewId()
+ s1.ExpiresAt = model.GetMillis() + 100000
+ store.Must(ss.Session().Save(&s1))
+
+ if r1 := <-ss.Session().AnalyticsSessionCount(); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) == 0 {
+ t.Fatal("should have at least 1 session")
+ }
+ }
+}
diff --git a/store/storetest/status_store.go b/store/storetest/status_store.go
new file mode 100644
index 000000000..f2ea0f898
--- /dev/null
+++ b/store/storetest/status_store.go
@@ -0,0 +1,106 @@
+// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestStatusStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testStatusStore(t, ss) })
+ t.Run("ActiveUserCount", func(t *testing.T) { testActiveUserCount(t, ss) })
+}
+
+func testStatusStore(t *testing.T, ss store.Store) {
+ status := &model.Status{UserId: model.NewId(), Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
+
+ if err := (<-ss.Status().SaveOrUpdate(status)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ status.LastActivityAt = 10
+
+ if err := (<-ss.Status().SaveOrUpdate(status)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.Status().Get(status.UserId)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ status2 := &model.Status{UserId: model.NewId(), Status: model.STATUS_AWAY, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
+ if err := (<-ss.Status().SaveOrUpdate(status2)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ status3 := &model.Status{UserId: model.NewId(), Status: model.STATUS_OFFLINE, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
+ if err := (<-ss.Status().SaveOrUpdate(status3)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if result := <-ss.Status().GetOnlineAway(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ statuses := result.Data.([]*model.Status)
+ for _, status := range statuses {
+ if status.Status == model.STATUS_OFFLINE {
+ t.Fatal("should not have returned offline statuses")
+ }
+ }
+ }
+
+ if result := <-ss.Status().GetOnline(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ statuses := result.Data.([]*model.Status)
+ for _, status := range statuses {
+ if status.Status != model.STATUS_ONLINE {
+ t.Fatal("should not have returned offline statuses")
+ }
+ }
+ }
+
+ if result := <-ss.Status().GetByIds([]string{status.UserId, "junk"}); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ statuses := result.Data.([]*model.Status)
+ if len(statuses) != 1 {
+ t.Fatal("should only have 1 status")
+ }
+ }
+
+ if err := (<-ss.Status().ResetAll()).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if result := <-ss.Status().Get(status.UserId); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ status := result.Data.(*model.Status)
+ if status.Status != model.STATUS_OFFLINE {
+ t.Fatal("should be offline")
+ }
+ }
+
+ if result := <-ss.Status().UpdateLastActivityAt(status.UserId, 10); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+}
+
+func testActiveUserCount(t *testing.T, ss store.Store) {
+ status := &model.Status{UserId: model.NewId(), Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
+ store.Must(ss.Status().SaveOrUpdate(status))
+
+ if result := <-ss.Status().GetTotalActiveUsersCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ count := result.Data.(int64)
+ if count <= 0 {
+ t.Fatal()
+ }
+ }
+}
diff --git a/store/storetest/system_store.go b/store/storetest/system_store.go
new file mode 100644
index 000000000..32c39ee41
--- /dev/null
+++ b/store/storetest/system_store.go
@@ -0,0 +1,58 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestSystemStore(t *testing.T, ss store.Store) {
+ t.Run("", func(t *testing.T) { testSystemStore(t, ss) })
+ t.Run("SaveOrUpdate", func(t *testing.T) { testSystemStoreSaveOrUpdate(t, ss) })
+}
+
+func testSystemStore(t *testing.T, ss store.Store) {
+ system := &model.System{Name: model.NewId(), Value: "value"}
+ store.Must(ss.System().Save(system))
+
+ result := <-ss.System().Get()
+ systems := result.Data.(model.StringMap)
+
+ if systems[system.Name] != system.Value {
+ t.Fatal()
+ }
+
+ system.Value = "value2"
+ store.Must(ss.System().Update(system))
+
+ result2 := <-ss.System().Get()
+ systems2 := result2.Data.(model.StringMap)
+
+ if systems2[system.Name] != system.Value {
+ t.Fatal()
+ }
+
+ result3 := <-ss.System().GetByName(system.Name)
+ rsystem := result3.Data.(*model.System)
+ if rsystem.Value != system.Value {
+ t.Fatal()
+ }
+}
+
+func testSystemStoreSaveOrUpdate(t *testing.T, ss store.Store) {
+ system := &model.System{Name: model.NewId(), Value: "value"}
+
+ if err := (<-ss.System().SaveOrUpdate(system)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ system.Value = "value2"
+
+ if r := <-ss.System().SaveOrUpdate(system); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+}
diff --git a/store/storetest/team_store.go b/store/storetest/team_store.go
new file mode 100644
index 000000000..e48595780
--- /dev/null
+++ b/store/storetest/team_store.go
@@ -0,0 +1,1010 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+ "github.com/mattermost/mattermost-server/utils"
+)
+
+func TestTeamStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testTeamStoreSave(t, ss) })
+ t.Run("Update", func(t *testing.T) { testTeamStoreUpdate(t, ss) })
+ t.Run("UpdateDisplayName", func(t *testing.T) { testTeamStoreUpdateDisplayName(t, ss) })
+ t.Run("Get", func(t *testing.T) { testTeamStoreGet(t, ss) })
+ t.Run("GetByName", func(t *testing.T) { testTeamStoreGetByName(t, ss) })
+ t.Run("SearchByName", func(t *testing.T) { testTeamStoreSearchByName(t, ss) })
+ t.Run("SearchAll", func(t *testing.T) { testTeamStoreSearchAll(t, ss) })
+ t.Run("SearchOpen", func(t *testing.T) { testTeamStoreSearchOpen(t, ss) })
+ t.Run("GetByIniviteId", func(t *testing.T) { testTeamStoreGetByIniviteId(t, ss) })
+ t.Run("ByUserId", func(t *testing.T) { testTeamStoreByUserId(t, ss) })
+ t.Run("GetAllTeamListing", func(t *testing.T) { testGetAllTeamListing(t, ss) })
+ t.Run("GetAllTeamPageListing", func(t *testing.T) { testGetAllTeamPageListing(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testDelete(t, ss) })
+ t.Run("TeamCount", func(t *testing.T) { testTeamCount(t, ss) })
+ t.Run("TeamMembers", func(t *testing.T) { testTeamMembers(t, ss) })
+ t.Run("SaveTeamMemberMaxMembers", func(t *testing.T) { testSaveTeamMemberMaxMembers(t, ss) })
+ t.Run("GetTeamMember", func(t *testing.T) { testGetTeamMember(t, ss) })
+ t.Run("GetTeamMembersByIds", func(t *testing.T) { testGetTeamMembersByIds(t, ss) })
+ t.Run("MemberCount", func(t *testing.T) { testTeamStoreMemberCount(t, ss) })
+ t.Run("GetChannelUnreadsForAllTeams", func(t *testing.T) { testGetChannelUnreadsForAllTeams(t, ss) })
+ t.Run("GetChannelUnreadsForTeam", func(t *testing.T) { testGetChannelUnreadsForTeam(t, ss) })
+}
+
+func testTeamStoreSave(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Team().Save(&o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+
+ o1.Id = ""
+ if err := (<-ss.Team().Save(&o1)).Err; err == nil {
+ t.Fatal("should be unique domain")
+ }
+}
+
+func testTeamStoreUpdate(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := (<-ss.Team().Update(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ o1.Id = "missing"
+ if err := (<-ss.Team().Update(&o1)).Err; err == nil {
+ t.Fatal("Update should have failed because of missing key")
+ }
+
+ o1.Id = model.NewId()
+ if err := (<-ss.Team().Update(&o1)).Err; err == nil {
+ t.Fatal("Update should have faile because id change")
+ }
+}
+
+func testTeamStoreUpdateDisplayName(t *testing.T, ss store.Store) {
+ o1 := &model.Team{}
+ o1.DisplayName = "Display Name"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1 = (<-ss.Team().Save(o1)).Data.(*model.Team)
+
+ newDisplayName := "NewDisplayName"
+
+ if err := (<-ss.Team().UpdateDisplayName(newDisplayName, o1.Id)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ ro1 := (<-ss.Team().Get(o1.Id)).Data.(*model.Team)
+ if ro1.DisplayName != newDisplayName {
+ t.Fatal("DisplayName not updated")
+ }
+}
+
+func testTeamStoreGet(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ store.Must(ss.Team().Save(&o1))
+
+ if r1 := <-ss.Team().Get(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Team).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+ }
+
+ if err := (<-ss.Team().Get("")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testTeamStoreGetByName(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.Team().GetByName(o1.Name); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Team).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+ }
+
+ if err := (<-ss.Team().GetByName("")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testTeamStoreSearchByName(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ var name = "zzz" + model.NewId()
+ o1.Name = name + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.Team().SearchByName(name); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+ }
+}
+
+func testTeamStoreSearchAll(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "ADisplayName" + model.NewId()
+ o1.Name = "zz" + model.NewId() + "a"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ p2 := model.Team{}
+ p2.DisplayName = "BDisplayName" + model.NewId()
+ p2.Name = "b" + model.NewId() + "b"
+ p2.Email = model.NewId() + "@nowhere.com"
+ p2.Type = model.TEAM_INVITE
+
+ if err := (<-ss.Team().Save(&p2)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ r1 := <-ss.Team().SearchAll(o1.Name)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 1 {
+ t.Fatal("should have returned 1 team")
+ }
+ if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+
+ r1 = <-ss.Team().SearchAll(p2.DisplayName)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 1 {
+ t.Fatal("should have returned 1 team")
+ }
+ if r1.Data.([]*model.Team)[0].ToJson() != p2.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+
+ r1 = <-ss.Team().SearchAll("junk")
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 0 {
+ t.Fatal("should have not returned a team")
+ }
+}
+
+func testTeamStoreSearchOpen(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "ADisplayName" + model.NewId()
+ o1.Name = "zz" + model.NewId() + "a"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.AllowOpenInvite = true
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ o2 := model.Team{}
+ o2.DisplayName = "ADisplayName" + model.NewId()
+ o2.Name = "zz" + model.NewId() + "a"
+ o2.Email = model.NewId() + "@nowhere.com"
+ o2.Type = model.TEAM_OPEN
+ o2.AllowOpenInvite = false
+
+ if err := (<-ss.Team().Save(&o2)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ p2 := model.Team{}
+ p2.DisplayName = "BDisplayName" + model.NewId()
+ p2.Name = "b" + model.NewId() + "b"
+ p2.Email = model.NewId() + "@nowhere.com"
+ p2.Type = model.TEAM_INVITE
+ p2.AllowOpenInvite = true
+
+ if err := (<-ss.Team().Save(&p2)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ r1 := <-ss.Team().SearchOpen(o1.Name)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 1 {
+ t.Fatal("should have returned 1 team")
+ }
+ if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+
+ r1 = <-ss.Team().SearchOpen(o1.DisplayName)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 1 {
+ t.Fatal("should have returned 1 team")
+ }
+ if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+
+ r1 = <-ss.Team().SearchOpen(p2.Name)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 0 {
+ t.Fatal("should have not returned a team")
+ }
+
+ r1 = <-ss.Team().SearchOpen(p2.DisplayName)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 0 {
+ t.Fatal("should have not returned a team")
+ }
+
+ r1 = <-ss.Team().SearchOpen("junk")
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 0 {
+ t.Fatal("should have not returned a team")
+ }
+
+ r1 = <-ss.Team().SearchOpen(o2.DisplayName)
+ if r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+ if len(r1.Data.([]*model.Team)) != 0 {
+ t.Fatal("should have not returned a team")
+ }
+}
+
+func testTeamStoreGetByIniviteId(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.InviteId = model.NewId()
+
+ if err := (<-ss.Team().Save(&o1)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ o2 := model.Team{}
+ o2.DisplayName = "DisplayName"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Email = model.NewId() + "@nowhere.com"
+ o2.Type = model.TEAM_OPEN
+
+ if err := (<-ss.Team().Save(&o2)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.Team().GetByInviteId(o1.InviteId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Team).ToJson() != o1.ToJson() {
+ t.Fatal("invalid returned team")
+ }
+ }
+
+ o2.InviteId = ""
+ <-ss.Team().Update(&o2)
+
+ if r1 := <-ss.Team().GetByInviteId(o2.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.Team).Id != o2.Id {
+ t.Fatal("invalid returned team")
+ }
+ }
+
+ if err := (<-ss.Team().GetByInviteId("")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testTeamStoreByUserId(t *testing.T, ss store.Store) {
+ o1 := &model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.InviteId = model.NewId()
+ o1 = store.Must(ss.Team().Save(o1)).(*model.Team)
+
+ m1 := &model.TeamMember{TeamId: o1.Id, UserId: model.NewId()}
+ store.Must(ss.Team().SaveMember(m1))
+
+ if r1 := <-ss.Team().GetTeamsByUserId(m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ teams := r1.Data.([]*model.Team)
+ if len(teams) == 0 {
+ t.Fatal("Should return a team")
+ }
+
+ if teams[0].Id != o1.Id {
+ t.Fatal("should be a member")
+ }
+
+ }
+}
+
+func testGetAllTeamListing(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o1))
+
+ o2 := model.Team{}
+ o2.DisplayName = "DisplayName"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Email = model.NewId() + "@nowhere.com"
+ o2.Type = model.TEAM_OPEN
+ store.Must(ss.Team().Save(&o2))
+
+ o3 := model.Team{}
+ o3.DisplayName = "DisplayName"
+ o3.Name = "z-z-z" + model.NewId() + "b"
+ o3.Email = model.NewId() + "@nowhere.com"
+ o3.Type = model.TEAM_INVITE
+ o3.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o3))
+
+ o4 := model.Team{}
+ o4.DisplayName = "DisplayName"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Email = model.NewId() + "@nowhere.com"
+ o4.Type = model.TEAM_INVITE
+ store.Must(ss.Team().Save(&o4))
+
+ if r1 := <-ss.Team().GetAllTeamListing(); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ teams := r1.Data.([]*model.Team)
+
+ for _, team := range teams {
+ if !team.AllowOpenInvite {
+ t.Fatal("should have returned team with AllowOpenInvite as true")
+ }
+ }
+
+ if len(teams) == 0 {
+ t.Fatal("failed team listing")
+ }
+ }
+}
+
+func testGetAllTeamPageListing(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o1))
+
+ o2 := model.Team{}
+ o2.DisplayName = "DisplayName"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Email = model.NewId() + "@nowhere.com"
+ o2.Type = model.TEAM_OPEN
+ o2.AllowOpenInvite = false
+ store.Must(ss.Team().Save(&o2))
+
+ o3 := model.Team{}
+ o3.DisplayName = "DisplayName"
+ o3.Name = "z-z-z" + model.NewId() + "b"
+ o3.Email = model.NewId() + "@nowhere.com"
+ o3.Type = model.TEAM_INVITE
+ o3.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o3))
+
+ o4 := model.Team{}
+ o4.DisplayName = "DisplayName"
+ o4.Name = "zz" + model.NewId() + "b"
+ o4.Email = model.NewId() + "@nowhere.com"
+ o4.Type = model.TEAM_INVITE
+ o4.AllowOpenInvite = false
+ store.Must(ss.Team().Save(&o4))
+
+ if r1 := <-ss.Team().GetAllTeamPageListing(0, 10); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ teams := r1.Data.([]*model.Team)
+
+ for _, team := range teams {
+ if !team.AllowOpenInvite {
+ t.Fatal("should have returned team with AllowOpenInvite as true")
+ }
+ }
+
+ if len(teams) > 10 {
+ t.Fatal("should have returned max of 10 teams")
+ }
+ }
+
+ o5 := model.Team{}
+ o5.DisplayName = "DisplayName"
+ o5.Name = "z-z-z" + model.NewId() + "b"
+ o5.Email = model.NewId() + "@nowhere.com"
+ o5.Type = model.TEAM_OPEN
+ o5.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o5))
+
+ if r1 := <-ss.Team().GetAllTeamPageListing(0, 4); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ teams := r1.Data.([]*model.Team)
+
+ for _, team := range teams {
+ if !team.AllowOpenInvite {
+ t.Fatal("should have returned team with AllowOpenInvite as true")
+ }
+ }
+
+ if len(teams) > 4 {
+ t.Fatal("should have returned max of 4 teams")
+ }
+ }
+
+ if r1 := <-ss.Team().GetAllTeamPageListing(1, 1); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ teams := r1.Data.([]*model.Team)
+
+ for _, team := range teams {
+ if !team.AllowOpenInvite {
+ t.Fatal("should have returned team with AllowOpenInvite as true")
+ }
+ }
+
+ if len(teams) > 1 {
+ t.Fatal("should have returned max of 1 team")
+ }
+ }
+}
+
+func testDelete(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o1))
+
+ o2 := model.Team{}
+ o2.DisplayName = "DisplayName"
+ o2.Name = "zz" + model.NewId() + "b"
+ o2.Email = model.NewId() + "@nowhere.com"
+ o2.Type = model.TEAM_OPEN
+ store.Must(ss.Team().Save(&o2))
+
+ if r1 := <-ss.Team().PermanentDelete(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+}
+
+func testTeamCount(t *testing.T, ss store.Store) {
+ o1 := model.Team{}
+ o1.DisplayName = "DisplayName"
+ o1.Name = "z-z-z" + model.NewId() + "b"
+ o1.Email = model.NewId() + "@nowhere.com"
+ o1.Type = model.TEAM_OPEN
+ o1.AllowOpenInvite = true
+ store.Must(ss.Team().Save(&o1))
+
+ if r1 := <-ss.Team().AnalyticsTeamCount(); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(int64) == 0 {
+ t.Fatal("should be at least 1 team")
+ }
+ }
+}
+
+func testTeamMembers(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+ teamId2 := model.NewId()
+
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ m3 := &model.TeamMember{TeamId: teamId2, UserId: model.NewId()}
+
+ if r1 := <-ss.Team().SaveMember(m1); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ store.Must(ss.Team().SaveMember(m2))
+ store.Must(ss.Team().SaveMember(m3))
+
+ if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 2 {
+ t.Fatal()
+ }
+ }
+
+ if r1 := <-ss.Team().GetMembers(teamId2, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 1 {
+ t.Fatal()
+ }
+
+ if ms[0].UserId != m3.UserId {
+ t.Fatal()
+
+ }
+ }
+
+ if r1 := <-ss.Team().GetTeamsForUser(m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 1 {
+ t.Fatal()
+ }
+
+ if ms[0].TeamId != m1.TeamId {
+ t.Fatal()
+
+ }
+ }
+
+ if r1 := <-ss.Team().RemoveMember(teamId1, m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 1 {
+ t.Fatal()
+ }
+
+ if ms[0].UserId != m2.UserId {
+ t.Fatal()
+
+ }
+ }
+
+ store.Must(ss.Team().SaveMember(m1))
+
+ if r1 := <-ss.Team().RemoveAllMembersByTeam(teamId1); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 0 {
+ t.Fatal()
+ }
+ }
+
+ uid := model.NewId()
+ m4 := &model.TeamMember{TeamId: teamId1, UserId: uid}
+ m5 := &model.TeamMember{TeamId: teamId2, UserId: uid}
+ store.Must(ss.Team().SaveMember(m4))
+ store.Must(ss.Team().SaveMember(m5))
+
+ if r1 := <-ss.Team().GetTeamsForUser(uid); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 2 {
+ t.Fatal()
+ }
+ }
+
+ if r1 := <-ss.Team().RemoveAllMembersByUser(uid); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ if r1 := <-ss.Team().GetTeamsForUser(m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.TeamMember)
+
+ if len(ms) != 0 {
+ t.Fatal()
+ }
+ }
+}
+
+func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
+ MaxUsersPerTeam := *utils.Cfg.TeamSettings.MaxUsersPerTeam
+ defer func() {
+ *utils.Cfg.TeamSettings.MaxUsersPerTeam = MaxUsersPerTeam
+ }()
+ *utils.Cfg.TeamSettings.MaxUsersPerTeam = 5
+
+ team := store.Must(ss.Team().Save(&model.Team{
+ DisplayName: "DisplayName",
+ Name: "z-z-z" + model.NewId() + "b",
+ Type: model.TEAM_OPEN,
+ })).(*model.Team)
+ defer func() {
+ <-ss.Team().PermanentDelete(team.Id)
+ }()
+
+ userIds := make([]string, *utils.Cfg.TeamSettings.MaxUsersPerTeam)
+
+ for i := 0; i < *utils.Cfg.TeamSettings.MaxUsersPerTeam; i++ {
+ userIds[i] = store.Must(ss.User().Save(&model.User{
+ Username: model.NewId(),
+ Email: model.NewId(),
+ })).(*model.User).Id
+
+ defer func(userId string) {
+ <-ss.User().PermanentDelete(userId)
+ }(userIds[i])
+
+ store.Must(ss.Team().SaveMember(&model.TeamMember{
+ TeamId: team.Id,
+ UserId: userIds[i],
+ }))
+
+ defer func(userId string) {
+ <-ss.Team().RemoveMember(team.Id, userId)
+ }(userIds[i])
+ }
+
+ if result := <-ss.Team().GetTotalMemberCount(team.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if count := result.Data.(int64); int(count) != *utils.Cfg.TeamSettings.MaxUsersPerTeam {
+ t.Fatalf("should start with 5 team members, had %v instead", count)
+ }
+
+ newUserId := store.Must(ss.User().Save(&model.User{
+ Username: model.NewId(),
+ Email: model.NewId(),
+ })).(*model.User).Id
+ defer func() {
+ <-ss.User().PermanentDelete(newUserId)
+ }()
+
+ if result := <-ss.Team().SaveMember(&model.TeamMember{
+ TeamId: team.Id,
+ UserId: newUserId,
+ }); result.Err == nil {
+ t.Fatal("shouldn't be able to save member when at maximum members per team")
+ }
+
+ if result := <-ss.Team().GetTotalMemberCount(team.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if count := result.Data.(int64); int(count) != *utils.Cfg.TeamSettings.MaxUsersPerTeam {
+ t.Fatalf("should still have 5 team members, had %v instead", count)
+ }
+
+ // Leaving the team from the UI sets DeleteAt instead of using TeamStore.RemoveMember
+ store.Must(ss.Team().UpdateMember(&model.TeamMember{
+ TeamId: team.Id,
+ UserId: userIds[0],
+ DeleteAt: 1234,
+ }))
+
+ if result := <-ss.Team().GetTotalMemberCount(team.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if count := result.Data.(int64); int(count) != *utils.Cfg.TeamSettings.MaxUsersPerTeam-1 {
+ t.Fatalf("should now only have 4 team members, had %v instead", count)
+ }
+
+ if result := <-ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId}); result.Err != nil {
+ t.Fatal("should've been able to save new member after deleting one", result.Err)
+ } else {
+ defer func(userId string) {
+ <-ss.Team().RemoveMember(team.Id, userId)
+ }(newUserId)
+ }
+
+ if result := <-ss.Team().GetTotalMemberCount(team.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if count := result.Data.(int64); int(count) != *utils.Cfg.TeamSettings.MaxUsersPerTeam {
+ t.Fatalf("should have 5 team members again, had %v instead", count)
+ }
+
+ // Deactivating a user should make them stop counting against max members
+ user2 := store.Must(ss.User().Get(userIds[1])).(*model.User)
+ user2.DeleteAt = 1234
+ store.Must(ss.User().Update(user2, true))
+
+ newUserId2 := store.Must(ss.User().Save(&model.User{
+ Username: model.NewId(),
+ Email: model.NewId(),
+ })).(*model.User).Id
+ if result := <-ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId2}); result.Err != nil {
+ t.Fatal("should've been able to save new member after deleting one", result.Err)
+ } else {
+ defer func(userId string) {
+ <-ss.Team().RemoveMember(team.Id, userId)
+ }(newUserId2)
+ }
+}
+
+func testGetTeamMember(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ store.Must(ss.Team().SaveMember(m1))
+
+ if r := <-ss.Team().GetMember(m1.TeamId, m1.UserId); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ rm1 := r.Data.(*model.TeamMember)
+
+ if rm1.TeamId != m1.TeamId {
+ t.Fatal("bad team id")
+ }
+
+ if rm1.UserId != m1.UserId {
+ t.Fatal("bad user id")
+ }
+ }
+
+ if r := <-ss.Team().GetMember(m1.TeamId, ""); r.Err == nil {
+ t.Fatal("empty user id - should have failed")
+ }
+
+ if r := <-ss.Team().GetMember("", m1.UserId); r.Err == nil {
+ t.Fatal("empty team id - should have failed")
+ }
+}
+
+func testGetTeamMembersByIds(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ store.Must(ss.Team().SaveMember(m1))
+
+ if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId}); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ rm1 := r.Data.([]*model.TeamMember)[0]
+
+ if rm1.TeamId != m1.TeamId {
+ t.Fatal("bad team id")
+ }
+
+ if rm1.UserId != m1.UserId {
+ t.Fatal("bad user id")
+ }
+ }
+
+ m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ store.Must(ss.Team().SaveMember(m2))
+
+ if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId, m2.UserId, model.NewId()}); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ rm := r.Data.([]*model.TeamMember)
+
+ if len(rm) != 2 {
+ t.Fatal("return wrong number of results")
+ }
+ }
+
+ if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{}); r.Err == nil {
+ t.Fatal("empty user ids - should have failed")
+ }
+}
+
+func testTeamStoreMemberCount(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.DeleteAt = 1
+ store.Must(ss.User().Save(u2))
+
+ teamId1 := model.NewId()
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: u1.Id}
+ store.Must(ss.Team().SaveMember(m1))
+
+ m2 := &model.TeamMember{TeamId: teamId1, UserId: u2.Id}
+ store.Must(ss.Team().SaveMember(m2))
+
+ if result := <-ss.Team().GetTotalMemberCount(teamId1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if result.Data.(int64) != 2 {
+ t.Fatal("wrong count")
+ }
+ }
+
+ if result := <-ss.Team().GetActiveMemberCount(teamId1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if result.Data.(int64) != 1 {
+ t.Fatal("wrong count")
+ }
+ }
+
+ m3 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
+ store.Must(ss.Team().SaveMember(m3))
+
+ if result := <-ss.Team().GetTotalMemberCount(teamId1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if result.Data.(int64) != 2 {
+ t.Fatal("wrong count")
+ }
+ }
+
+ if result := <-ss.Team().GetActiveMemberCount(teamId1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if result.Data.(int64) != 1 {
+ t.Fatal("wrong count")
+ }
+ }
+}
+
+func testGetChannelUnreadsForAllTeams(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+ teamId2 := model.NewId()
+
+ uid := model.NewId()
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: uid}
+ m2 := &model.TeamMember{TeamId: teamId2, UserId: uid}
+ store.Must(ss.Team().SaveMember(m1))
+ store.Must(ss.Team().SaveMember(m2))
+
+ c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c1))
+ c2 := &model.Channel{TeamId: m2.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c2))
+
+ cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90}
+ store.Must(ss.Channel().SaveMember(cm1))
+ cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m2.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90}
+ store.Must(ss.Channel().SaveMember(cm2))
+
+ if r1 := <-ss.Team().GetChannelUnreadsForAllTeams("", uid); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.ChannelUnread)
+ membersMap := make(map[string]bool)
+ for i := range ms {
+ id := ms[i].TeamId
+ if _, ok := membersMap[id]; !ok {
+ membersMap[id] = true
+ }
+ }
+ if len(membersMap) != 2 {
+ t.Fatal("Should be the unreads for all the teams")
+ }
+
+ if ms[0].MsgCount != 10 {
+ t.Fatal("subtraction failed")
+ }
+ }
+
+ if r2 := <-ss.Team().GetChannelUnreadsForAllTeams(teamId1, uid); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ ms := r2.Data.([]*model.ChannelUnread)
+ membersMap := make(map[string]bool)
+ for i := range ms {
+ id := ms[i].TeamId
+ if _, ok := membersMap[id]; !ok {
+ membersMap[id] = true
+ }
+ }
+
+ if len(membersMap) != 1 {
+ t.Fatal("Should be the unreads for just one team")
+ }
+
+ if ms[0].MsgCount != 10 {
+ t.Fatal("subtraction failed")
+ }
+ }
+
+ if r1 := <-ss.Team().RemoveAllMembersByUser(uid); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+}
+
+func testGetChannelUnreadsForTeam(t *testing.T, ss store.Store) {
+ teamId1 := model.NewId()
+
+ uid := model.NewId()
+ m1 := &model.TeamMember{TeamId: teamId1, UserId: uid}
+ store.Must(ss.Team().SaveMember(m1))
+
+ c1 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c1))
+ c2 := &model.Channel{TeamId: m1.TeamId, Name: model.NewId(), DisplayName: "Town Square", Type: model.CHANNEL_OPEN, TotalMsgCount: 100}
+ store.Must(ss.Channel().Save(c2))
+
+ cm1 := &model.ChannelMember{ChannelId: c1.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90}
+ store.Must(ss.Channel().SaveMember(cm1))
+ cm2 := &model.ChannelMember{ChannelId: c2.Id, UserId: m1.UserId, NotifyProps: model.GetDefaultChannelNotifyProps(), MsgCount: 90}
+ store.Must(ss.Channel().SaveMember(cm2))
+
+ if r1 := <-ss.Team().GetChannelUnreadsForTeam(m1.TeamId, m1.UserId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ ms := r1.Data.([]*model.ChannelUnread)
+ if len(ms) != 2 {
+ t.Fatal("wrong length")
+ }
+
+ if ms[0].MsgCount != 10 {
+ t.Fatal("subtraction failed")
+ }
+ }
+}
diff --git a/store/storetest/user_access_token_store.go b/store/storetest/user_access_token_store.go
new file mode 100644
index 000000000..292929419
--- /dev/null
+++ b/store/storetest/user_access_token_store.go
@@ -0,0 +1,89 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestUserAccessTokenStore(t *testing.T, ss store.Store) {
+ t.Run("UserAccessTokenSaveGetDelete", func(t *testing.T) { testUserAccessTokenSaveGetDelete(t, ss) })
+}
+
+func testUserAccessTokenSaveGetDelete(t *testing.T, ss store.Store) {
+ uat := &model.UserAccessToken{
+ Token: model.NewId(),
+ UserId: model.NewId(),
+ Description: "testtoken",
+ }
+
+ s1 := model.Session{}
+ s1.UserId = uat.UserId
+ s1.Token = uat.Token
+
+ store.Must(ss.Session().Save(&s1))
+
+ if result := <-ss.UserAccessToken().Save(uat); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.UserAccessToken().Get(uat.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.(*model.UserAccessToken); received.Token != uat.Token {
+ t.Fatal("received incorrect token after save")
+ }
+
+ if result := <-ss.UserAccessToken().GetByToken(uat.Token); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.(*model.UserAccessToken); received.Token != uat.Token {
+ t.Fatal("received incorrect token after save")
+ }
+
+ if result := <-ss.UserAccessToken().GetByToken("notarealtoken"); result.Err == nil {
+ t.Fatal("should have failed on bad token")
+ }
+
+ if result := <-ss.UserAccessToken().GetByUser(uat.UserId, 0, 100); result.Err != nil {
+ t.Fatal(result.Err)
+ } else if received := result.Data.([]*model.UserAccessToken); len(received) != 1 {
+ t.Fatal("received incorrect number of tokens after save")
+ }
+
+ if result := <-ss.UserAccessToken().Delete(uat.Id); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if err := (<-ss.Session().Get(s1.Token)).Err; err == nil {
+ t.Fatal("should error - session should be deleted")
+ }
+
+ if err := (<-ss.UserAccessToken().GetByToken(s1.Token)).Err; err == nil {
+ t.Fatal("should error - access token should be deleted")
+ }
+
+ s2 := model.Session{}
+ s2.UserId = uat.UserId
+ s2.Token = uat.Token
+
+ store.Must(ss.Session().Save(&s2))
+
+ if result := <-ss.UserAccessToken().Save(uat); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if result := <-ss.UserAccessToken().DeleteAllForUser(uat.UserId); result.Err != nil {
+ t.Fatal(result.Err)
+ }
+
+ if err := (<-ss.Session().Get(s2.Token)).Err; err == nil {
+ t.Fatal("should error - session should be deleted")
+ }
+
+ if err := (<-ss.UserAccessToken().GetByToken(s2.Token)).Err; err == nil {
+ t.Fatal("should error - access token should be deleted")
+ }
+}
diff --git a/store/storetest/user_store.go b/store/storetest/user_store.go
new file mode 100644
index 000000000..d00e88f56
--- /dev/null
+++ b/store/storetest/user_store.go
@@ -0,0 +1,2074 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestUserStore(t *testing.T, ss store.Store) {
+ t.Run("Save", func(t *testing.T) { testUserStoreSave(t, ss) })
+ t.Run("Update", func(t *testing.T) { testUserStoreUpdate(t, ss) })
+ t.Run("UpdateUpdateAt", func(t *testing.T) { testUserStoreUpdateUpdateAt(t, ss) })
+ t.Run("UpdateFailedPasswordAttempts", func(t *testing.T) { testUserStoreUpdateFailedPasswordAttempts(t, ss) })
+ t.Run("Get", func(t *testing.T) { testUserStoreGet(t, ss) })
+ t.Run("UserCount", func(t *testing.T) { testUserCount(t, ss) })
+ t.Run("GetAllUsingAuthService", func(t *testing.T) { testGetAllUsingAuthService(t, ss) })
+ t.Run("GetAllProfiles", func(t *testing.T) { testUserStoreGetAllProfiles(t, ss) })
+ t.Run("GetProfiles", func(t *testing.T) { testUserStoreGetProfiles(t, ss) })
+ t.Run("GetProfilesInChannel", func(t *testing.T) { testUserStoreGetProfilesInChannel(t, ss) })
+ t.Run("GetProfilesWithoutTeam", func(t *testing.T) { testUserStoreGetProfilesWithoutTeam(t, ss) })
+ t.Run("GetAllProfilesInChannel", func(t *testing.T) { testUserStoreGetAllProfilesInChannel(t, ss) })
+ t.Run("GetProfilesNotInChannel", func(t *testing.T) { testUserStoreGetProfilesNotInChannel(t, ss) })
+ t.Run("GetProfilesByIds", func(t *testing.T) { testUserStoreGetProfilesByIds(t, ss) })
+ t.Run("GetProfilesByUsernames", func(t *testing.T) { testUserStoreGetProfilesByUsernames(t, ss) })
+ t.Run("GetSystemAdminProfiles", func(t *testing.T) { testUserStoreGetSystemAdminProfiles(t, ss) })
+ t.Run("GetByEmail", func(t *testing.T) { testUserStoreGetByEmail(t, ss) })
+ t.Run("GetByAuthData", func(t *testing.T) { testUserStoreGetByAuthData(t, ss) })
+ t.Run("GetByUsername", func(t *testing.T) { testUserStoreGetByUsername(t, ss) })
+ t.Run("GetForLogin", func(t *testing.T) { testUserStoreGetForLogin(t, ss) })
+ t.Run("UpdatePassword", func(t *testing.T) { testUserStoreUpdatePassword(t, ss) })
+ t.Run("Delete", func(t *testing.T) { testUserStoreDelete(t, ss) })
+ t.Run("UpdateAuthData", func(t *testing.T) { testUserStoreUpdateAuthData(t, ss) })
+ t.Run("UserUnreadCount", func(t *testing.T) { testUserUnreadCount(t, ss) })
+ t.Run("UpdateMfaSecret", func(t *testing.T) { testUserStoreUpdateMfaSecret(t, ss) })
+ t.Run("UpdateMfaActive", func(t *testing.T) { testUserStoreUpdateMfaActive(t, ss) })
+ t.Run("GetRecentlyActiveUsersForTeam", func(t *testing.T) { testUserStoreGetRecentlyActiveUsersForTeam(t, ss) })
+ t.Run("GetNewUsersForTeam", func(t *testing.T) { testUserStoreGetNewUsersForTeam(t, ss) })
+ t.Run("Search", func(t *testing.T) { testUserStoreSearch(t, ss) })
+ t.Run("SearchWithoutTeam", func(t *testing.T) { testUserStoreSearchWithoutTeam(t, ss) })
+ t.Run("AnalyticsGetInactiveUsersCount", func(t *testing.T) { testUserStoreAnalyticsGetInactiveUsersCount(t, ss) })
+ t.Run("AnalyticsGetSystemAdminCount", func(t *testing.T) { testUserStoreAnalyticsGetSystemAdminCount(t, ss) })
+ t.Run("GetProfilesNotInTeam", func(t *testing.T) { testUserStoreGetProfilesNotInTeam(t, ss) })
+}
+
+func testUserStoreSave(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+
+ if err := (<-ss.User().Save(&u1)).Err; err != nil {
+ t.Fatal("couldn't save user", err)
+ }
+
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ if err := (<-ss.User().Save(&u1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update user from save")
+ }
+
+ u1.Id = ""
+ if err := (<-ss.User().Save(&u1)).Err; err == nil {
+ t.Fatal("should be unique email")
+ }
+
+ u1.Email = ""
+ if err := (<-ss.User().Save(&u1)).Err; err == nil {
+ t.Fatal("should be unique username")
+ }
+
+ u1.Email = strings.Repeat("0123456789", 20)
+ u1.Username = ""
+ if err := (<-ss.User().Save(&u1)).Err; err == nil {
+ t.Fatal("should be unique username")
+ }
+
+ for i := 0; i < 49; i++ {
+ u1.Id = ""
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ if err := (<-ss.User().Save(&u1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+ }
+
+ u1.Id = ""
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ if err := (<-ss.User().Save(&u1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})).Err; err == nil {
+ t.Fatal("should be the limit")
+ }
+
+}
+
+func testUserStoreUpdate(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.AuthService = "ldap"
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := (<-ss.User().Update(u1, false)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ u1.Id = "missing"
+ if err := (<-ss.User().Update(u1, false)).Err; err == nil {
+ t.Fatal("Update should have failed because of missing key")
+ }
+
+ u1.Id = model.NewId()
+ if err := (<-ss.User().Update(u1, false)).Err; err == nil {
+ t.Fatal("Update should have faile because id change")
+ }
+
+ u2.Email = model.NewId()
+ if err := (<-ss.User().Update(u2, false)).Err; err == nil {
+ t.Fatal("Update should have failed because you can't modify AD/LDAP fields")
+ }
+
+ u3 := &model.User{}
+ u3.Email = model.NewId()
+ oldEmail := u3.Email
+ u3.AuthService = "gitlab"
+ store.Must(ss.User().Save(u3))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u3.Id}))
+
+ u3.Email = model.NewId()
+ if result := <-ss.User().Update(u3, false); result.Err != nil {
+ t.Fatal("Update should not have failed")
+ } else {
+ newUser := result.Data.([2]*model.User)[0]
+ if newUser.Email != oldEmail {
+ t.Fatal("Email should not have been updated as the update is not trusted")
+ }
+ }
+
+ if result := <-ss.User().Update(u3, true); result.Err != nil {
+ t.Fatal("Update should not have failed")
+ } else {
+ newUser := result.Data.([2]*model.User)[0]
+ if newUser.Email != u3.Email {
+ t.Fatal("Email should have been updated as the update is trusted")
+ }
+ }
+
+ if result := <-ss.User().UpdateLastPictureUpdate(u1.Id); result.Err != nil {
+ t.Fatal("Update should not have failed")
+ }
+}
+
+func testUserStoreUpdateUpdateAt(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ time.Sleep(10 * time.Millisecond)
+
+ if err := (<-ss.User().UpdateUpdateAt(u1.Id)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.User().Get(u1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.User).UpdateAt <= u1.UpdateAt {
+ t.Fatal("UpdateAt not updated correctly")
+ }
+ }
+
+}
+
+func testUserStoreUpdateFailedPasswordAttempts(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ if err := (<-ss.User().UpdateFailedPasswordAttempts(u1.Id, 3)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.User().Get(u1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.User).FailedAttempts != 3 {
+ t.Fatal("FailedAttempts not updated correctly")
+ }
+ }
+
+}
+
+func testUserStoreGet(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ if r1 := <-ss.User().Get(u1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.User).ToJson() != u1.ToJson() {
+ t.Fatal("invalid returned user")
+ }
+ }
+
+ if err := (<-ss.User().Get("")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testUserCount(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ if result := <-ss.User().GetTotalUsersCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ count := result.Data.(int64)
+ if count <= 0 {
+ t.Fatal()
+ }
+ }
+}
+
+func testGetAllUsingAuthService(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.AuthService = "someservice"
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.AuthService = "someservice"
+ store.Must(ss.User().Save(u2))
+
+ if r1 := <-ss.User().GetAllUsingAuthService(u1.AuthService); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) < 2 {
+ t.Fatal("invalid returned users")
+ }
+ }
+}
+
+func testUserStoreGetAllProfiles(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+
+ if r1 := <-ss.User().GetAllProfiles(0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) < 2 {
+ t.Fatal("invalid returned users")
+ }
+ }
+
+ if r2 := <-ss.User().GetAllProfiles(0, 1); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ users := r2.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users, limit did not work")
+ }
+ }
+
+ if r2 := <-ss.User().GetAll(); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ users := r2.Data.([]*model.User)
+ if len(users) < 2 {
+ t.Fatal("invalid returned users")
+ }
+ }
+
+ etag := ""
+ if r2 := <-ss.User().GetEtagForAllProfiles(); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ etag = r2.Data.(string)
+ }
+
+ u3 := &model.User{}
+ u3.Email = model.NewId()
+ store.Must(ss.User().Save(u3))
+
+ if r2 := <-ss.User().GetEtagForAllProfiles(); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if etag == r2.Data.(string) {
+ t.Fatal("etags should not match")
+ }
+ }
+}
+
+func testUserStoreGetProfiles(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ if r1 := <-ss.User().GetProfiles(teamId, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfiles("123", 0, 100); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.([]*model.User)) != 0 {
+ t.Fatal("should have returned empty map")
+ }
+ }
+
+ etag := ""
+ if r2 := <-ss.User().GetEtagForProfiles(teamId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ etag = r2.Data.(string)
+ }
+
+ u3 := &model.User{}
+ u3.Email = model.NewId()
+ store.Must(ss.User().Save(u3))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u3.Id}))
+
+ if r2 := <-ss.User().GetEtagForProfiles(teamId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if etag == r2.Data.(string) {
+ t.Fatal("etags should not match")
+ }
+ }
+}
+
+func testUserStoreGetProfilesInChannel(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ c1 := model.Channel{}
+ c1.TeamId = teamId
+ c1.DisplayName = "Profiles in channel"
+ c1.Name = "profiles-" + model.NewId()
+ c1.Type = model.CHANNEL_OPEN
+
+ c2 := model.Channel{}
+ c2.TeamId = teamId
+ c2.DisplayName = "Profiles in private"
+ c2.Name = "profiles-" + model.NewId()
+ c2.Type = model.CHANNEL_PRIVATE
+
+ store.Must(ss.Channel().Save(&c1))
+ store.Must(ss.Channel().Save(&c2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = c1.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = c1.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = c2.Id
+ m3.UserId = u1.Id
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ store.Must(ss.Channel().SaveMember(&m1))
+ store.Must(ss.Channel().SaveMember(&m2))
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ if r1 := <-ss.User().GetProfilesInChannel(c1.Id, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfilesInChannel(c2.Id, 0, 1); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.([]*model.User)) != 1 {
+ t.Fatal("should have returned only 1 user")
+ }
+ }
+}
+
+func testUserStoreGetProfilesWithoutTeam(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ // These usernames need to appear in the first 100 users for this to work
+
+ u1 := &model.User{}
+ u1.Username = "a000000000" + model.NewId()
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+ defer ss.User().PermanentDelete(u1.Id)
+
+ u2 := &model.User{}
+ u2.Username = "a000000001" + model.NewId()
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ defer ss.User().PermanentDelete(u2.Id)
+
+ if r1 := <-ss.User().GetProfilesWithoutTeam(0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+
+ found1 := false
+ found2 := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found1 = true
+ } else if u.Id == u2.Id {
+ found2 = true
+ }
+ }
+
+ if found1 {
+ t.Fatal("shouldn't have returned user on team")
+ } else if !found2 {
+ t.Fatal("should've returned user without any teams")
+ }
+ }
+}
+
+func testUserStoreGetAllProfilesInChannel(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ c1 := model.Channel{}
+ c1.TeamId = teamId
+ c1.DisplayName = "Profiles in channel"
+ c1.Name = "profiles-" + model.NewId()
+ c1.Type = model.CHANNEL_OPEN
+
+ c2 := model.Channel{}
+ c2.TeamId = teamId
+ c2.DisplayName = "Profiles in private"
+ c2.Name = "profiles-" + model.NewId()
+ c2.Type = model.CHANNEL_PRIVATE
+
+ store.Must(ss.Channel().Save(&c1))
+ store.Must(ss.Channel().Save(&c2))
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = c1.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = c1.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = c2.Id
+ m3.UserId = u1.Id
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ store.Must(ss.Channel().SaveMember(&m1))
+ store.Must(ss.Channel().SaveMember(&m2))
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ if r1 := <-ss.User().GetAllProfilesInChannel(c1.Id, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.(map[string]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ if users[u1.Id].Id != u1.Id {
+ t.Fatal("invalid returned user")
+ }
+ }
+
+ if r2 := <-ss.User().GetAllProfilesInChannel(c2.Id, false); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.(map[string]*model.User)) != 1 {
+ t.Fatal("should have returned empty map")
+ }
+ }
+
+ if r2 := <-ss.User().GetAllProfilesInChannel(c2.Id, true); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.(map[string]*model.User)) != 1 {
+ t.Fatal("should have returned empty map")
+ }
+ }
+
+ if r2 := <-ss.User().GetAllProfilesInChannel(c2.Id, true); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.(map[string]*model.User)) != 1 {
+ t.Fatal("should have returned empty map")
+ }
+ }
+
+ ss.User().InvalidateProfilesInChannelCacheByUser(u1.Id)
+ ss.User().InvalidateProfilesInChannelCache(c2.Id)
+}
+
+func testUserStoreGetProfilesNotInChannel(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ c1 := model.Channel{}
+ c1.TeamId = teamId
+ c1.DisplayName = "Profiles in channel"
+ c1.Name = "profiles-" + model.NewId()
+ c1.Type = model.CHANNEL_OPEN
+
+ c2 := model.Channel{}
+ c2.TeamId = teamId
+ c2.DisplayName = "Profiles in private"
+ c2.Name = "profiles-" + model.NewId()
+ c2.Type = model.CHANNEL_PRIVATE
+
+ store.Must(ss.Channel().Save(&c1))
+ store.Must(ss.Channel().Save(&c2))
+
+ if r1 := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.([]*model.User)) != 2 {
+ t.Fatal("invalid returned users")
+ }
+ }
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = c1.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = c1.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m3 := model.ChannelMember{}
+ m3.ChannelId = c2.Id
+ m3.UserId = u1.Id
+ m3.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ store.Must(ss.Channel().SaveMember(&m1))
+ store.Must(ss.Channel().SaveMember(&m2))
+ store.Must(ss.Channel().SaveMember(&m3))
+
+ if r1 := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 0 {
+ t.Fatal("invalid returned users")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.([]*model.User)) != 1 {
+ t.Fatal("should have had 1 user not in channel")
+ }
+ }
+}
+
+func testUserStoreGetProfilesByIds(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id}, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id}, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id}, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id}, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id}, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfileByIds([]string{u1.Id}, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u1.Id {
+ found = true
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfiles("123", 0, 100); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ if len(r2.Data.([]*model.User)) != 0 {
+ t.Fatal("should have returned empty array")
+ }
+ }
+}
+
+func testUserStoreGetProfilesByUsernames(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Username = "username1" + model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Username = "username2" + model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ if r1 := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u2.Username}, teamId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ if users[0].Id != u1.Id && users[1].Id != u1.Id {
+ t.Fatal("invalid returned user 1")
+ }
+
+ if users[0].Id != u2.Id && users[1].Id != u2.Id {
+ t.Fatal("invalid returned user 2")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfilesByUsernames([]string{u1.Username}, teamId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users")
+ }
+
+ if users[0].Id != u1.Id {
+ t.Fatal("invalid returned user")
+ }
+ }
+
+ team2Id := model.NewId()
+
+ u3 := &model.User{}
+ u3.Email = model.NewId()
+ u3.Username = "username3" + model.NewId()
+ store.Must(ss.User().Save(u3))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: team2Id, UserId: u3.Id}))
+
+ if r1 := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, ""); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 2 {
+ t.Fatal("invalid returned users")
+ }
+
+ if users[0].Id != u1.Id && users[1].Id != u1.Id {
+ t.Fatal("invalid returned user 1")
+ }
+
+ if users[0].Id != u3.Id && users[1].Id != u3.Id {
+ t.Fatal("invalid returned user 3")
+ }
+ }
+
+ if r1 := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, teamId); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ if len(users) != 1 {
+ t.Fatal("invalid returned users")
+ }
+
+ if users[0].Id != u1.Id {
+ t.Fatal("invalid returned user")
+ }
+ }
+}
+
+func testUserStoreGetSystemAdminProfiles(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Roles = model.ROLE_SYSTEM_USER.Id + " " + model.ROLE_SYSTEM_ADMIN.Id
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ if r1 := <-ss.User().GetSystemAdminProfiles(); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.(map[string]*model.User)
+ if len(users) <= 0 {
+ t.Fatal("invalid returned system admin users")
+ }
+ }
+}
+
+func testUserStoreGetByEmail(t *testing.T, ss store.Store) {
+ teamid := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamid, UserId: u1.Id}))
+
+ if err := (<-ss.User().GetByEmail(u1.Email)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.User().GetByEmail("")).Err; err == nil {
+ t.Fatal("Should have failed because of missing email")
+ }
+}
+
+func testUserStoreGetByAuthData(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ auth := "123" + model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.AuthData = &auth
+ u1.AuthService = "service"
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ if err := (<-ss.User().GetByAuth(u1.AuthData, u1.AuthService)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ rauth := ""
+ if err := (<-ss.User().GetByAuth(&rauth, "")).Err; err == nil {
+ t.Fatal("Should have failed because of missing auth data")
+ }
+}
+
+func testUserStoreGetByUsername(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ if err := (<-ss.User().GetByUsername(u1.Username)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.User().GetByUsername("")).Err; err == nil {
+ t.Fatal("Should have failed because of missing username")
+ }
+}
+
+func testUserStoreGetForLogin(t *testing.T, ss store.Store) {
+ auth := model.NewId()
+
+ u1 := &model.User{
+ Email: model.NewId(),
+ Username: model.NewId(),
+ AuthService: model.USER_AUTH_SERVICE_GITLAB,
+ AuthData: &auth,
+ }
+ store.Must(ss.User().Save(u1))
+
+ auth2 := model.NewId()
+
+ u2 := &model.User{
+ Email: model.NewId(),
+ Username: model.NewId(),
+ AuthService: model.USER_AUTH_SERVICE_LDAP,
+ AuthData: &auth2,
+ }
+ store.Must(ss.User().Save(u2))
+
+ if result := <-ss.User().GetForLogin(u1.Username, true, true, true); result.Err != nil {
+ t.Fatal("Should have gotten user by username", result.Err)
+ } else if result.Data.(*model.User).Id != u1.Id {
+ t.Fatal("Should have gotten user1 by username")
+ }
+
+ if result := <-ss.User().GetForLogin(u1.Email, true, true, true); result.Err != nil {
+ t.Fatal("Should have gotten user by email", result.Err)
+ } else if result.Data.(*model.User).Id != u1.Id {
+ t.Fatal("Should have gotten user1 by email")
+ }
+
+ if result := <-ss.User().GetForLogin(*u2.AuthData, true, true, true); result.Err != nil {
+ t.Fatal("Should have gotten user by AD/LDAP AuthData", result.Err)
+ } else if result.Data.(*model.User).Id != u2.Id {
+ t.Fatal("Should have gotten user2 by AD/LDAP AuthData")
+ }
+
+ // prevent getting user by AuthData when they're not an LDAP user
+ if result := <-ss.User().GetForLogin(*u1.AuthData, true, true, true); result.Err == nil {
+ t.Fatal("Should not have gotten user by non-AD/LDAP AuthData")
+ }
+
+ // prevent getting user when different login methods are disabled
+ if result := <-ss.User().GetForLogin(u1.Username, false, true, true); result.Err == nil {
+ t.Fatal("Should have failed to get user1 by username")
+ }
+
+ if result := <-ss.User().GetForLogin(u1.Email, true, false, true); result.Err == nil {
+ t.Fatal("Should have failed to get user1 by email")
+ }
+
+ if result := <-ss.User().GetForLogin(*u2.AuthData, true, true, false); result.Err == nil {
+ t.Fatal("Should have failed to get user3 by AD/LDAP AuthData")
+ }
+
+ auth3 := model.NewId()
+
+ // test a special case where two users will have conflicting login information so we throw a special error
+ u3 := &model.User{
+ Email: model.NewId(),
+ Username: model.NewId(),
+ AuthService: model.USER_AUTH_SERVICE_LDAP,
+ AuthData: &auth3,
+ }
+ store.Must(ss.User().Save(u3))
+
+ u4 := &model.User{
+ Email: model.NewId(),
+ Username: model.NewId(),
+ AuthService: model.USER_AUTH_SERVICE_LDAP,
+ AuthData: &u3.Username,
+ }
+ store.Must(ss.User().Save(u4))
+
+ if err := (<-ss.User().GetForLogin(u3.Username, true, true, true)).Err; err == nil {
+ t.Fatal("Should have failed to get users with conflicting login information")
+ }
+}
+
+func testUserStoreUpdatePassword(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ hashedPassword := model.HashPassword("newpwd")
+
+ if err := (<-ss.User().UpdatePassword(u1.Id, hashedPassword)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.User().GetByEmail(u1.Email); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ user := r1.Data.(*model.User)
+ if user.Password != hashedPassword {
+ t.Fatal("Password was not updated correctly")
+ }
+ }
+}
+
+func testUserStoreDelete(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
+
+ if err := (<-ss.User().PermanentDelete(u1.Id)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testUserStoreUpdateAuthData(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ service := "someservice"
+ authData := model.NewId()
+
+ if err := (<-ss.User().UpdateAuthData(u1.Id, service, &authData, "", true)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if r1 := <-ss.User().GetByEmail(u1.Email); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ user := r1.Data.(*model.User)
+ if user.AuthService != service {
+ t.Fatal("AuthService was not updated correctly")
+ }
+ if *user.AuthData != authData {
+ t.Fatal("AuthData was not updated correctly")
+ }
+ if user.Password != "" {
+ t.Fatal("Password was not cleared properly")
+ }
+ }
+}
+
+func testUserUnreadCount(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ c1 := model.Channel{}
+ c1.TeamId = teamId
+ c1.DisplayName = "Unread Messages"
+ c1.Name = "unread-messages-" + model.NewId()
+ c1.Type = model.CHANNEL_OPEN
+
+ c2 := model.Channel{}
+ c2.TeamId = teamId
+ c2.DisplayName = "Unread Direct"
+ c2.Name = "unread-direct-" + model.NewId()
+ c2.Type = model.CHANNEL_DIRECT
+
+ u1 := &model.User{}
+ u1.Username = "user1" + model.NewId()
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.Username = "user2" + model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+
+ if err := (<-ss.Channel().Save(&c1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ m1 := model.ChannelMember{}
+ m1.ChannelId = c1.Id
+ m1.UserId = u1.Id
+ m1.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ m2 := model.ChannelMember{}
+ m2.ChannelId = c1.Id
+ m2.UserId = u2.Id
+ m2.NotifyProps = model.GetDefaultChannelNotifyProps()
+
+ store.Must(ss.Channel().SaveMember(&m1))
+ store.Must(ss.Channel().SaveMember(&m2))
+
+ m1.ChannelId = c2.Id
+ m2.ChannelId = c2.Id
+
+ if err := (<-ss.Channel().SaveDirectChannel(&c2, &m1, &m2)).Err; err != nil {
+ t.Fatal("couldn't save direct channel", err)
+ }
+
+ p1 := model.Post{}
+ p1.ChannelId = c1.Id
+ p1.UserId = u1.Id
+ p1.Message = "this is a message for @" + u2.Username
+
+ // Post one message with mention to open channel
+ store.Must(ss.Post().Save(&p1))
+ store.Must(ss.Channel().IncrementMentionCount(c1.Id, u2.Id))
+
+ // Post 2 messages without mention to direct channel
+ p2 := model.Post{}
+ p2.ChannelId = c2.Id
+ p2.UserId = u1.Id
+ p2.Message = "first message"
+ store.Must(ss.Post().Save(&p2))
+ store.Must(ss.Channel().IncrementMentionCount(c2.Id, u2.Id))
+
+ p3 := model.Post{}
+ p3.ChannelId = c2.Id
+ p3.UserId = u1.Id
+ p3.Message = "second message"
+ store.Must(ss.Post().Save(&p3))
+ store.Must(ss.Channel().IncrementMentionCount(c2.Id, u2.Id))
+
+ badge := (<-ss.User().GetUnreadCount(u2.Id)).Data.(int64)
+ if badge != 3 {
+ t.Fatal("should have 3 unread messages")
+ }
+
+ badge = (<-ss.User().GetUnreadCountForChannel(u2.Id, c1.Id)).Data.(int64)
+ if badge != 1 {
+ t.Fatal("should have 1 unread messages for that channel")
+ }
+
+ badge = (<-ss.User().GetUnreadCountForChannel(u2.Id, c2.Id)).Data.(int64)
+ if badge != 2 {
+ t.Fatal("should have 2 unread messages for that channel")
+ }
+}
+
+func testUserStoreUpdateMfaSecret(t *testing.T, ss store.Store) {
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(&u1))
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := (<-ss.User().UpdateMfaSecret(u1.Id, "12345")).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ // should pass, no update will occur though
+ if err := (<-ss.User().UpdateMfaSecret("junk", "12345")).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testUserStoreUpdateMfaActive(t *testing.T, ss store.Store) {
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(&u1))
+
+ time.Sleep(100 * time.Millisecond)
+
+ if err := (<-ss.User().UpdateMfaActive(u1.Id, true)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ if err := (<-ss.User().UpdateMfaActive(u1.Id, false)).Err; err != nil {
+ t.Fatal(err)
+ }
+
+ // should pass, no update will occur though
+ if err := (<-ss.User().UpdateMfaActive("junk", true)).Err; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testUserStoreGetRecentlyActiveUsersForTeam(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Status().SaveOrUpdate(&model.Status{UserId: u1.Id, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}))
+ tid := model.NewId()
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u1.Id}))
+
+ if r1 := <-ss.User().GetRecentlyActiveUsersForTeam(tid, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+}
+
+func testUserStoreGetNewUsersForTeam(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Status().SaveOrUpdate(&model.Status{UserId: u1.Id, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}))
+ tid := model.NewId()
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u1.Id}))
+
+ if r1 := <-ss.User().GetNewUsersForTeam(tid, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+}
+
+func testUserStoreSearch(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Username = "jimbo" + model.NewId()
+ u1.FirstName = "Tim"
+ u1.LastName = "Bill"
+ u1.Nickname = "Rob"
+ u1.Email = "harold" + model.NewId() + "@simulator.amazonses.com"
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Username = "jim-bobby" + model.NewId()
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+
+ u3 := &model.User{}
+ u3.Username = "jimbo" + model.NewId()
+ u3.Email = model.NewId()
+ u3.DeleteAt = 1
+ store.Must(ss.User().Save(u3))
+
+ u5 := &model.User{}
+ u5.Username = "yu" + model.NewId()
+ u5.FirstName = "En"
+ u5.LastName = "Yu"
+ u5.Nickname = "enyu"
+ u5.Email = model.NewId() + "@simulator.amazonses.com"
+ store.Must(ss.User().Save(u5))
+
+ u6 := &model.User{}
+ u6.Username = "underscore" + model.NewId()
+ u6.FirstName = "Du_"
+ u6.LastName = "_DE"
+ u6.Nickname = "lodash"
+ u6.Email = model.NewId() + "@simulator.amazonses.com"
+ store.Must(ss.User().Save(u6))
+
+ tid := model.NewId()
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u1.Id}))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u2.Id}))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u3.Id}))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u5.Id}))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u6.Id}))
+
+ searchOptions := map[string]bool{}
+ searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
+
+ if r1 := <-ss.User().Search(tid, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ found2 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+
+ if profile.Id == u3.Id {
+ found2 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+
+ if found2 {
+ t.Fatal("should not have found inactive user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "en", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ for _, profile := range profiles {
+ if profile.Id == u5.Id {
+ found1 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+ }
+
+ searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = false
+
+ if r1 := <-ss.User().Search(tid, u1.Email, searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+ }
+
+ searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
+
+ // * should be treated as a space
+ if r1 := <-ss.User().Search(tid, "jimb*", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ found2 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+
+ if profile.Id == u3.Id {
+ found2 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+
+ if found2 {
+ t.Fatal("should not have found inactive user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "harol", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+ }
+
+ if found1 {
+ t.Fatal("should not have found user")
+ }
+ }
+
+ // % should be escaped and searched for.
+ if r1 := <-ss.User().Search(tid, "h%", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ if len(profiles) != 0 {
+ t.Fatal("shouldn't have found anything")
+ }
+ }
+
+ // "_" should be properly escaped and searched for.
+ if r1 := <-ss.User().Search(tid, "h_", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ if len(profiles) != 0 {
+ t.Fatal("shouldn't have found anything")
+ }
+ }
+ if r1 := <-ss.User().Search(tid, "Du_", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found6 := false
+ for _, profile := range profiles {
+ if profile.Id == u6.Id {
+ found6 = true
+ }
+ }
+
+ if !found6 {
+ t.Fatal("should have found user")
+ }
+ }
+ if r1 := <-ss.User().Search(tid, "_dE", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found6 := false
+ for _, profile := range profiles {
+ if profile.Id == u6.Id {
+ found6 = true
+ }
+ }
+
+ if !found6 {
+ t.Fatal("should have found user")
+ }
+ }
+
+ searchOptions[store.USER_SEARCH_OPTION_ALLOW_INACTIVE] = true
+
+ if r1 := <-ss.User().Search(tid, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ found2 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+
+ if profile.Id == u3.Id {
+ found2 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+
+ if !found2 {
+ t.Fatal("should have found inactive user")
+ }
+ }
+
+ searchOptions[store.USER_SEARCH_OPTION_ALLOW_INACTIVE] = false
+
+ if r1 := <-ss.User().Search(tid, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search("", "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search("", "jim-bobb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ t.Log(profile.Username)
+ if profile.Id == u2.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ c1 := model.Channel{}
+ c1.TeamId = tid
+ c1.DisplayName = "NameName"
+ c1.Name = "zz" + model.NewId() + "b"
+ c1.Type = model.CHANNEL_OPEN
+ c1 = *store.Must(ss.Channel().Save(&c1)).(*model.Channel)
+
+ if r1 := <-ss.User().SearchNotInChannel(tid, c1.Id, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().SearchNotInChannel("", c1.Id, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().SearchNotInChannel("junk", c1.Id, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if found {
+ t.Fatal("should not have found user")
+ }
+ }
+
+ if r1 := <-ss.User().SearchInChannel(c1.Id, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if found {
+ t.Fatal("should not have found user")
+ }
+ }
+
+ store.Must(ss.Channel().SaveMember(&model.ChannelMember{ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps()}))
+
+ if r1 := <-ss.User().SearchInChannel(c1.Id, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ searchOptions = map[string]bool{}
+
+ if r1 := <-ss.User().Search(tid, "harol", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found1 := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "Tim", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "Bill", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().Search(tid, "Rob", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ // Search Users not in Team.
+ u4 := &model.User{}
+ u4.Username = "simon" + model.NewId()
+ u4.Email = model.NewId()
+ u4.DeleteAt = 0
+ store.Must(ss.User().Save(u4))
+
+ if r1 := <-ss.User().SearchNotInTeam(tid, "simo", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u4.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+
+ if r1 := <-ss.User().SearchNotInTeam(tid, "jimb", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found = true
+ break
+ }
+ }
+
+ if found {
+ t.Fatal("should not have found user")
+ }
+ }
+
+ // Check SearchNotInTeam finds previously deleted team members.
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u4.Id}))
+
+ if r1 := <-ss.User().SearchNotInTeam(tid, "simo", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u4.Id {
+ found = true
+ break
+ }
+ }
+
+ if found {
+ t.Fatal("should not have found user")
+ }
+ }
+
+ store.Must(ss.Team().UpdateMember(&model.TeamMember{TeamId: tid, UserId: u4.Id, DeleteAt: model.GetMillis() - 1000}))
+ if r1 := <-ss.User().SearchNotInTeam(tid, "simo", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+ found := false
+ for _, profile := range profiles {
+ if profile.Id == u4.Id {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Fatal("should have found user")
+ }
+ }
+}
+
+func testUserStoreSearchWithoutTeam(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Username = "jimbo" + model.NewId()
+ u1.FirstName = "Tim"
+ u1.LastName = "Bill"
+ u1.Nickname = "Rob"
+ u1.Email = "harold" + model.NewId() + "@simulator.amazonses.com"
+ store.Must(ss.User().Save(u1))
+
+ u2 := &model.User{}
+ u2.Username = "jim-bobby" + model.NewId()
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+
+ u3 := &model.User{}
+ u3.Username = "jimbo" + model.NewId()
+ u3.Email = model.NewId()
+ u3.DeleteAt = 1
+ store.Must(ss.User().Save(u3))
+
+ tid := model.NewId()
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: tid, UserId: u3.Id}))
+
+ searchOptions := map[string]bool{}
+ searchOptions[store.USER_SEARCH_OPTION_NAMES_ONLY] = true
+
+ if r1 := <-ss.User().SearchWithoutTeam("", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ }
+
+ if r1 := <-ss.User().SearchWithoutTeam("jim", searchOptions); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ profiles := r1.Data.([]*model.User)
+
+ found1 := false
+ found2 := false
+ found3 := false
+
+ for _, profile := range profiles {
+ if profile.Id == u1.Id {
+ found1 = true
+ } else if profile.Id == u2.Id {
+ found2 = true
+ } else if profile.Id == u3.Id {
+ found3 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("should have found user1")
+ } else if !found2 {
+ t.Fatal("should have found user2")
+ } else if found3 {
+ t.Fatal("should not have found user3")
+ }
+ }
+}
+
+func testUserStoreAnalyticsGetInactiveUsersCount(t *testing.T, ss store.Store) {
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+
+ var count int64
+
+ if result := <-ss.User().AnalyticsGetInactiveUsersCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ count = result.Data.(int64)
+ }
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ u2.DeleteAt = model.GetMillis()
+ store.Must(ss.User().Save(u2))
+
+ if result := <-ss.User().AnalyticsGetInactiveUsersCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ newCount := result.Data.(int64)
+ if count != newCount-1 {
+ t.Fatal("Expected 1 more inactive users but found otherwise.", count, newCount)
+ }
+ }
+}
+
+func testUserStoreAnalyticsGetSystemAdminCount(t *testing.T, ss store.Store) {
+ var countBefore int64
+ if result := <-ss.User().AnalyticsGetSystemAdminCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ countBefore = result.Data.(int64)
+ }
+
+ u1 := model.User{}
+ u1.Email = model.NewId()
+ u1.Username = model.NewId()
+ u1.Roles = "system_user system_admin"
+
+ u2 := model.User{}
+ u2.Email = model.NewId()
+ u2.Username = model.NewId()
+
+ if err := (<-ss.User().Save(&u1)).Err; err != nil {
+ t.Fatal("couldn't save user", err)
+ }
+
+ if err := (<-ss.User().Save(&u2)).Err; err != nil {
+ t.Fatal("couldn't save user", err)
+ }
+
+ if result := <-ss.User().AnalyticsGetSystemAdminCount(); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ // We expect to find 1 more system admin than there was at the start of this test function.
+ if count := result.Data.(int64); count != countBefore+1 {
+ t.Fatal("Did not get the expected number of system admins. Expected, got: ", countBefore+1, count)
+ }
+ }
+}
+
+func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
+ teamId := model.NewId()
+
+ u1 := &model.User{}
+ u1.Email = model.NewId()
+ store.Must(ss.User().Save(u1))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
+ store.Must(ss.User().UpdateUpdateAt(u1.Id))
+
+ u2 := &model.User{}
+ u2.Email = model.NewId()
+ store.Must(ss.User().Save(u2))
+ store.Must(ss.User().UpdateUpdateAt(u2.Id))
+
+ var initialUsersNotInTeam int
+ var etag1, etag2, etag3 string
+
+ if er1 := <-ss.User().GetEtagForProfilesNotInTeam(teamId); er1.Err != nil {
+ t.Fatal(er1.Err)
+ } else {
+ etag1 = er1.Data.(string)
+ }
+
+ if r1 := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ users := r1.Data.([]*model.User)
+ initialUsersNotInTeam = len(users)
+ if initialUsersNotInTeam < 1 {
+ t.Fatalf("Should be at least 1 user not in the team")
+ }
+
+ found := false
+ for _, u := range users {
+ if u.Id == u2.Id {
+ found = true
+ }
+ if u.Id == u1.Id {
+ t.Fatalf("Should not have found user1")
+ }
+ }
+
+ if !found {
+ t.Fatal("missing user2")
+ }
+ }
+
+ time.Sleep(time.Millisecond * 10)
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
+ store.Must(ss.User().UpdateUpdateAt(u2.Id))
+
+ if er2 := <-ss.User().GetEtagForProfilesNotInTeam(teamId); er2.Err != nil {
+ t.Fatal(er2.Err)
+ } else {
+ etag2 = er2.Data.(string)
+ if etag1 == etag2 {
+ t.Fatalf("etag should have changed")
+ }
+ }
+
+ if r2 := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000); r2.Err != nil {
+ t.Fatal(r2.Err)
+ } else {
+ users := r2.Data.([]*model.User)
+
+ if len(users) != initialUsersNotInTeam-1 {
+ t.Fatalf("Should be one less user not in team")
+ }
+
+ for _, u := range users {
+ if u.Id == u2.Id {
+ t.Fatalf("Should not have found user2")
+ }
+ if u.Id == u1.Id {
+ t.Fatalf("Should not have found user1")
+ }
+ }
+ }
+
+ time.Sleep(time.Millisecond * 10)
+ store.Must(ss.Team().RemoveMember(teamId, u1.Id))
+ store.Must(ss.Team().RemoveMember(teamId, u2.Id))
+ store.Must(ss.User().UpdateUpdateAt(u1.Id))
+ store.Must(ss.User().UpdateUpdateAt(u2.Id))
+
+ if er3 := <-ss.User().GetEtagForProfilesNotInTeam(teamId); er3.Err != nil {
+ t.Fatal(er3.Err)
+ } else {
+ etag3 = er3.Data.(string)
+ t.Log(etag3)
+ if etag1 == etag3 || etag3 == etag2 {
+ t.Fatalf("etag should have changed")
+ }
+ }
+
+ if r3 := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000); r3.Err != nil {
+ t.Fatal(r3.Err)
+ } else {
+ users := r3.Data.([]*model.User)
+ found1, found2 := false, false
+ for _, u := range users {
+ if u.Id == u2.Id {
+ found2 = true
+ }
+ if u.Id == u1.Id {
+ found1 = true
+ }
+ }
+
+ if !found1 || !found2 {
+ t.Fatal("missing user1 or user2")
+ }
+ }
+
+ time.Sleep(time.Millisecond * 10)
+ u3 := &model.User{}
+ u3.Email = model.NewId()
+ store.Must(ss.User().Save(u3))
+ store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u3.Id}))
+ store.Must(ss.User().UpdateUpdateAt(u3.Id))
+
+ if er4 := <-ss.User().GetEtagForProfilesNotInTeam(teamId); er4.Err != nil {
+ t.Fatal(er4.Err)
+ } else {
+ etag4 := er4.Data.(string)
+ t.Log(etag4)
+ if etag4 != etag3 {
+ t.Fatalf("etag should be the same")
+ }
+ }
+}
diff --git a/store/storetest/webhook_store.go b/store/storetest/webhook_store.go
new file mode 100644
index 000000000..7f87ec29d
--- /dev/null
+++ b/store/storetest/webhook_store.go
@@ -0,0 +1,507 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package storetest
+
+import (
+ "testing"
+ "time"
+
+ "net/http"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/store"
+)
+
+func TestWebhookStore(t *testing.T, ss store.Store) {
+ t.Run("SaveIncoming", func(t *testing.T) { testWebhookStoreSaveIncoming(t, ss) })
+ t.Run("UpdateIncoming", func(t *testing.T) { testWebhookStoreUpdateIncoming(t, ss) })
+ t.Run("GetIncoming", func(t *testing.T) { testWebhookStoreGetIncoming(t, ss) })
+ t.Run("GetIncomingList", func(t *testing.T) { testWebhookStoreGetIncomingList(t, ss) })
+ t.Run("GetIncomingByTeam", func(t *testing.T) { testWebhookStoreGetIncomingByTeam(t, ss) })
+ t.Run("DeleteIncoming", func(t *testing.T) { testWebhookStoreDeleteIncoming(t, ss) })
+ t.Run("DeleteIncomingByChannel", func(t *testing.T) { testWebhookStoreDeleteIncomingByChannel(t, ss) })
+ t.Run("DeleteIncomingByUser", func(t *testing.T) { testWebhookStoreDeleteIncomingByUser(t, ss) })
+ t.Run("SaveOutgoing", func(t *testing.T) { testWebhookStoreSaveOutgoing(t, ss) })
+ t.Run("GetOutgoing", func(t *testing.T) { testWebhookStoreGetOutgoing(t, ss) })
+ t.Run("GetOutgoingList", func(t *testing.T) { testWebhookStoreGetOutgoingList(t, ss) })
+ t.Run("GetOutgoingByChannel", func(t *testing.T) { testWebhookStoreGetOutgoingByChannel(t, ss) })
+ t.Run("GetOutgoingByTeam", func(t *testing.T) { testWebhookStoreGetOutgoingByTeam(t, ss) })
+ t.Run("DeleteOutgoing", func(t *testing.T) { testWebhookStoreDeleteOutgoing(t, ss) })
+ t.Run("DeleteOutgoingByChannel", func(t *testing.T) { testWebhookStoreDeleteOutgoingByChannel(t, ss) })
+ t.Run("DeleteOutgoingByUser", func(t *testing.T) { testWebhookStoreDeleteOutgoingByUser(t, ss) })
+ t.Run("UpdateOutgoing", func(t *testing.T) { testWebhookStoreUpdateOutgoing(t, ss) })
+ t.Run("CountIncoming", func(t *testing.T) { testWebhookStoreCountIncoming(t, ss) })
+ t.Run("CountOutgoing", func(t *testing.T) { testWebhookStoreCountOutgoing(t, ss) })
+}
+
+func testWebhookStoreSaveIncoming(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+
+ if err := (<-ss.Webhook().SaveIncoming(o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Webhook().SaveIncoming(o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+}
+
+func testWebhookStoreUpdateIncoming(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+ previousUpdatedAt := o1.UpdateAt
+
+ o1.DisplayName = "TestHook"
+ time.Sleep(10 * time.Millisecond)
+
+ if result := (<-ss.Webhook().UpdateIncoming(o1)); result.Err != nil {
+ t.Fatal("updation of incoming hook failed", result.Err)
+ } else {
+ if result.Data.(*model.IncomingWebhook).UpdateAt == previousUpdatedAt {
+ t.Fatal("should have updated the UpdatedAt of the hook")
+ }
+
+ if result.Data.(*model.IncomingWebhook).DisplayName != "TestHook" {
+ t.Fatal("display name is not updated")
+ }
+ }
+}
+
+func testWebhookStoreGetIncoming(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncoming(o1.Id, false); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r1 := <-ss.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if err := (<-ss.Webhook().GetIncoming("123", false)).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ if err := (<-ss.Webhook().GetIncoming("123", true)).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+
+ if err := (<-ss.Webhook().GetIncoming("123", true)).Err; err.StatusCode != http.StatusNotFound {
+ t.Fatal("Should have set the status as not found for missing id")
+ }
+}
+
+func testWebhookStoreGetIncomingList(t *testing.T, ss store.Store) {
+ o1 := &model.IncomingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.TeamId = model.NewId()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncomingList(0, 1000); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ found := false
+ hooks := r1.Data.([]*model.IncomingWebhook)
+ for _, hook := range hooks {
+ if hook.Id == o1.Id {
+ found = true
+ }
+ }
+ if !found {
+ t.Fatal("missing webhook")
+ }
+ }
+
+ if result := <-ss.Webhook().GetIncomingList(0, 1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.IncomingWebhook)) != 1 {
+ t.Fatal("only 1 should be returned")
+ }
+ }
+}
+
+func testWebhookStoreGetIncomingByTeam(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncomingByTeam(o1.TeamId, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.([]*model.IncomingWebhook)[0].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if result := <-ss.Webhook().GetIncomingByTeam("123", 0, 100); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.IncomingWebhook)) != 0 {
+ t.Fatal("no webhooks should have returned")
+ }
+ }
+}
+
+func testWebhookStoreDeleteIncoming(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().DeleteIncoming(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreDeleteIncomingByChannel(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().PermanentDeleteIncomingByChannel(o1.ChannelId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreDeleteIncomingByUser(t *testing.T, ss store.Store) {
+ o1 := buildIncomingWebhook()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r1 := <-ss.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().PermanentDeleteIncomingByUser(o1.UserId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func buildIncomingWebhook() *model.IncomingWebhook {
+ o1 := &model.IncomingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.TeamId = model.NewId()
+
+ return o1
+}
+
+func testWebhookStoreSaveOutgoing(t *testing.T, ss store.Store) {
+ o1 := model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ if err := (<-ss.Webhook().SaveOutgoing(&o1)).Err; err != nil {
+ t.Fatal("couldn't save item", err)
+ }
+
+ if err := (<-ss.Webhook().SaveOutgoing(&o1)).Err; err == nil {
+ t.Fatal("shouldn't be able to update from save")
+ }
+}
+
+func testWebhookStoreGetOutgoing(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoing(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if err := (<-ss.Webhook().GetOutgoing("123")).Err; err == nil {
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreGetOutgoingList(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ o2 := &model.OutgoingWebhook{}
+ o2.ChannelId = model.NewId()
+ o2.CreatorId = model.NewId()
+ o2.TeamId = model.NewId()
+ o2.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o2 = (<-ss.Webhook().SaveOutgoing(o2)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoingList(0, 1000); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ hooks := r1.Data.([]*model.OutgoingWebhook)
+ found1 := false
+ found2 := false
+
+ for _, hook := range hooks {
+ if hook.CreateAt != o1.CreateAt {
+ found1 = true
+ }
+
+ if hook.CreateAt != o2.CreateAt {
+ found2 = true
+ }
+ }
+
+ if !found1 {
+ t.Fatal("missing hook1")
+ }
+ if !found2 {
+ t.Fatal("missing hook2")
+ }
+ }
+
+ if result := <-ss.Webhook().GetOutgoingList(0, 2); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.OutgoingWebhook)) != 2 {
+ t.Fatal("wrong number of hooks returned")
+ }
+ }
+}
+
+func testWebhookStoreGetOutgoingByChannel(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoingByChannel(o1.ChannelId, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.([]*model.OutgoingWebhook)[0].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if result := <-ss.Webhook().GetOutgoingByChannel("123", -1, -1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.OutgoingWebhook)) != 0 {
+ t.Fatal("no webhooks should have returned")
+ }
+ }
+}
+
+func testWebhookStoreGetOutgoingByTeam(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoingByTeam(o1.TeamId, 0, 100); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.([]*model.OutgoingWebhook)[0].CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if result := <-ss.Webhook().GetOutgoingByTeam("123", -1, -1); result.Err != nil {
+ t.Fatal(result.Err)
+ } else {
+ if len(result.Data.([]*model.OutgoingWebhook)) != 0 {
+ t.Fatal("no webhooks should have returned")
+ }
+ }
+}
+
+func testWebhookStoreDeleteOutgoing(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoing(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().DeleteOutgoing(o1.Id, model.GetMillis()); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetOutgoing(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreDeleteOutgoingByChannel(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoing(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().PermanentDeleteOutgoingByChannel(o1.ChannelId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetOutgoing(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreDeleteOutgoingByUser(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r1 := <-ss.Webhook().GetOutgoing(o1.Id); r1.Err != nil {
+ t.Fatal(r1.Err)
+ } else {
+ if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt {
+ t.Fatal("invalid returned webhook")
+ }
+ }
+
+ if r2 := <-ss.Webhook().PermanentDeleteOutgoingByUser(o1.CreatorId); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+
+ if r3 := (<-ss.Webhook().GetOutgoing(o1.Id)); r3.Err == nil {
+ t.Log(r3.Data)
+ t.Fatal("Missing id should have failed")
+ }
+}
+
+func testWebhookStoreUpdateOutgoing(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ o1.Token = model.NewId()
+
+ if r2 := <-ss.Webhook().UpdateOutgoing(o1); r2.Err != nil {
+ t.Fatal(r2.Err)
+ }
+}
+
+func testWebhookStoreCountIncoming(t *testing.T, ss store.Store) {
+ o1 := &model.IncomingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.UserId = model.NewId()
+ o1.TeamId = model.NewId()
+
+ o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
+
+ if r := <-ss.Webhook().AnalyticsIncomingCount(""); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ if r.Data.(int64) == 0 {
+ t.Fatal("should have at least 1 incoming hook")
+ }
+ }
+}
+
+func testWebhookStoreCountOutgoing(t *testing.T, ss store.Store) {
+ o1 := &model.OutgoingWebhook{}
+ o1.ChannelId = model.NewId()
+ o1.CreatorId = model.NewId()
+ o1.TeamId = model.NewId()
+ o1.CallbackURLs = []string{"http://nowhere.com/"}
+
+ o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
+
+ if r := <-ss.Webhook().AnalyticsOutgoingCount(""); r.Err != nil {
+ t.Fatal(r.Err)
+ } else {
+ if r.Data.(int64) == 0 {
+ t.Fatal("should have at least 1 outgoing hook")
+ }
+ }
+}