mirror of
https://github.com/mattermost/focalboard.git
synced 2024-12-12 09:04:14 +02:00
75bd409ba0
Backend support for subscribing/unsubscribing to blocks, typically cards and boards. Notifies subscribers when changes are made to cards they are subscribed to.
334 lines
11 KiB
Go
334 lines
11 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package storetests
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/focalboard/server/model"
|
|
"github.com/mattermost/focalboard/server/services/store"
|
|
)
|
|
|
|
func StoreTestSubscriptionsStore(t *testing.T, setup func(t *testing.T) (store.Store, func())) {
|
|
container := store.Container{
|
|
WorkspaceID: "0",
|
|
}
|
|
|
|
t.Run("CreateSubscription", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testCreateSubscription(t, store, container)
|
|
})
|
|
|
|
t.Run("DeleteSubscription", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testDeleteSubscription(t, store, container)
|
|
})
|
|
|
|
t.Run("UndeleteSubscription", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testUndeleteSubscription(t, store, container)
|
|
})
|
|
|
|
t.Run("GetSubscription", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testGetSubscription(t, store, container)
|
|
})
|
|
|
|
t.Run("GetSubscriptions", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testGetSubscriptions(t, store, container)
|
|
})
|
|
|
|
t.Run("GetSubscribersForBlock", func(t *testing.T) {
|
|
store, tearDown := setup(t)
|
|
defer tearDown()
|
|
testGetSubscribersForBlock(t, store, container)
|
|
})
|
|
}
|
|
|
|
func testCreateSubscription(t *testing.T, store store.Store, container store.Container) {
|
|
t.Run("create subscriptions", func(t *testing.T) {
|
|
users := createTestUsers(t, store, 10)
|
|
blocks := createTestBlocks(t, store, container, users[0].ID, 50)
|
|
|
|
for i, user := range users {
|
|
for j := 0; j < i; j++ {
|
|
sub := &model.Subscription{
|
|
BlockType: blocks[j].Type,
|
|
BlockID: blocks[j].ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
subNew, err := store.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
assert.NotZero(t, subNew.NotifiedAt)
|
|
assert.NotZero(t, subNew.CreateAt)
|
|
assert.Zero(t, subNew.DeleteAt)
|
|
}
|
|
}
|
|
|
|
// ensure each user has the right number of subscriptions
|
|
for i, user := range users {
|
|
subs, err := store.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Len(t, subs, i)
|
|
}
|
|
})
|
|
|
|
t.Run("duplicate subscription", func(t *testing.T) {
|
|
admin := createTestUsers(t, store, 1)[0]
|
|
user := createTestUsers(t, store, 1)[0]
|
|
block := createTestBlocks(t, store, container, admin.ID, 1)[0]
|
|
|
|
sub := &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
subNew, err := store.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
sub = &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
|
|
subDup, err := store.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create duplicate subscription should not error")
|
|
|
|
assert.Equal(t, subNew.BlockID, subDup.BlockID)
|
|
assert.Equal(t, subNew.WorkspaceID, subDup.WorkspaceID)
|
|
assert.Equal(t, subNew.SubscriberID, subDup.SubscriberID)
|
|
})
|
|
|
|
t.Run("invalid subscription", func(t *testing.T) {
|
|
admin := createTestUsers(t, store, 1)[0]
|
|
user := createTestUsers(t, store, 1)[0]
|
|
block := createTestBlocks(t, store, container, admin.ID, 1)[0]
|
|
|
|
sub := &model.Subscription{}
|
|
|
|
_, err := store.CreateSubscription(container, sub)
|
|
assert.ErrorAs(t, err, &model.ErrInvalidSubscription{}, "invalid subscription should error")
|
|
|
|
sub.BlockType = block.Type
|
|
_, err = store.CreateSubscription(container, sub)
|
|
assert.ErrorAs(t, err, &model.ErrInvalidSubscription{}, "invalid subscription should error")
|
|
|
|
sub.BlockID = block.ID
|
|
_, err = store.CreateSubscription(container, sub)
|
|
assert.ErrorAs(t, err, &model.ErrInvalidSubscription{}, "invalid subscription should error")
|
|
|
|
sub.SubscriberType = "user"
|
|
_, err = store.CreateSubscription(container, sub)
|
|
assert.ErrorAs(t, err, &model.ErrInvalidSubscription{}, "invalid subscription should error")
|
|
|
|
sub.SubscriberID = user.ID
|
|
subNew, err := store.CreateSubscription(container, sub)
|
|
assert.NoError(t, err, "valid subscription should not error")
|
|
|
|
assert.NoError(t, subNew.IsValid(), "created subscription should be valid")
|
|
})
|
|
}
|
|
|
|
func testDeleteSubscription(t *testing.T, s store.Store, container store.Container) {
|
|
t.Run("delete subscription", func(t *testing.T) {
|
|
user := createTestUsers(t, s, 1)[0]
|
|
block := createTestBlocks(t, s, container, user.ID, 1)[0]
|
|
|
|
sub := &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
subNew, err := s.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
// check the subscription exists
|
|
subs, err := s.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Len(t, subs, 1)
|
|
assert.Equal(t, subNew.BlockID, subs[0].BlockID)
|
|
assert.Equal(t, subNew.SubscriberID, subs[0].SubscriberID)
|
|
|
|
err = s.DeleteSubscription(container, block.ID, user.ID)
|
|
require.NoError(t, err, "delete subscription should not error")
|
|
|
|
// check the subscription was deleted
|
|
subs, err = s.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Empty(t, subs)
|
|
})
|
|
|
|
t.Run("delete non-existent subscription", func(t *testing.T) {
|
|
err := s.DeleteSubscription(container, "bogus", "bogus")
|
|
require.Error(t, err, "delete non-existent subscription should error")
|
|
var nf *store.ErrNotFound
|
|
require.ErrorAs(t, err, &nf, "error should be of type store.ErrNotFound")
|
|
require.True(t, store.IsErrNotFound(err))
|
|
})
|
|
}
|
|
|
|
func testUndeleteSubscription(t *testing.T, s store.Store, container store.Container) {
|
|
t.Run("undelete subscription", func(t *testing.T) {
|
|
user := createTestUsers(t, s, 1)[0]
|
|
block := createTestBlocks(t, s, container, user.ID, 1)[0]
|
|
|
|
sub := &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
subNew, err := s.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
// check the subscription exists
|
|
subs, err := s.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Len(t, subs, 1)
|
|
assert.Equal(t, subNew.BlockID, subs[0].BlockID)
|
|
assert.Equal(t, subNew.SubscriberID, subs[0].SubscriberID)
|
|
|
|
err = s.DeleteSubscription(container, block.ID, user.ID)
|
|
require.NoError(t, err, "delete subscription should not error")
|
|
|
|
// check the subscription was deleted
|
|
subs, err = s.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Empty(t, subs)
|
|
|
|
// re-create the subscription
|
|
subUndeleted, err := s.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
// check the undeleted subscription exists
|
|
subs, err = s.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Len(t, subs, 1)
|
|
assert.Equal(t, subUndeleted.BlockID, subs[0].BlockID)
|
|
assert.Equal(t, subUndeleted.SubscriberID, subs[0].SubscriberID)
|
|
})
|
|
}
|
|
|
|
func testGetSubscription(t *testing.T, s store.Store, container store.Container) {
|
|
t.Run("get subscription", func(t *testing.T) {
|
|
user := createTestUsers(t, s, 1)[0]
|
|
block := createTestBlocks(t, s, container, user.ID, 1)[0]
|
|
|
|
sub := &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
subNew, err := s.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
|
|
// make sure subscription can be fetched
|
|
sub, err = s.GetSubscription(container, block.ID, user.ID)
|
|
require.NoError(t, err, "get subscription should not error")
|
|
assert.Equal(t, subNew, sub)
|
|
})
|
|
|
|
t.Run("get non-existent subscription", func(t *testing.T) {
|
|
sub, err := s.GetSubscription(container, "bogus", "bogus")
|
|
require.Error(t, err, "get non-existent subscription should error")
|
|
var nf *store.ErrNotFound
|
|
require.ErrorAs(t, err, &nf, "error should be of type store.ErrNotFound")
|
|
require.True(t, store.IsErrNotFound(err))
|
|
require.Nil(t, sub, "get subscription should return nil")
|
|
})
|
|
}
|
|
|
|
func testGetSubscriptions(t *testing.T, store store.Store, container store.Container) {
|
|
t.Run("get subscriptions", func(t *testing.T) {
|
|
author := createTestUsers(t, store, 1)[0]
|
|
user := createTestUsers(t, store, 1)[0]
|
|
blocks := createTestBlocks(t, store, container, author.ID, 50)
|
|
|
|
for _, block := range blocks {
|
|
sub := &model.Subscription{
|
|
BlockType: block.Type,
|
|
BlockID: block.ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
_, err := store.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
}
|
|
|
|
// ensure user has the right number of subscriptions
|
|
subs, err := store.GetSubscriptions(container, user.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Len(t, subs, len(blocks))
|
|
|
|
// ensure author has no subscriptions
|
|
subs, err = store.GetSubscriptions(container, author.ID)
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Empty(t, subs)
|
|
})
|
|
|
|
t.Run("get subscriptions for invalid user", func(t *testing.T) {
|
|
subs, err := store.GetSubscriptions(container, "bogus")
|
|
require.NoError(t, err, "get subscriptions should not error")
|
|
assert.Empty(t, subs)
|
|
})
|
|
}
|
|
|
|
func testGetSubscribersForBlock(t *testing.T, store store.Store, container store.Container) {
|
|
t.Run("get subscribers for block", func(t *testing.T) {
|
|
users := createTestUsers(t, store, 50)
|
|
blocks := createTestBlocks(t, store, container, users[0].ID, 2)
|
|
|
|
for _, user := range users {
|
|
sub := &model.Subscription{
|
|
BlockType: blocks[1].Type,
|
|
BlockID: blocks[1].ID,
|
|
SubscriberType: "user",
|
|
SubscriberID: user.ID,
|
|
}
|
|
_, err := store.CreateSubscription(container, sub)
|
|
require.NoError(t, err, "create subscription should not error")
|
|
}
|
|
|
|
// make sure block[1] has the right number of users subscribed
|
|
subs, err := store.GetSubscribersForBlock(container, blocks[1].ID)
|
|
require.NoError(t, err, "get subscribers for block should not error")
|
|
assert.Len(t, subs, 50)
|
|
|
|
count, err := store.GetSubscribersCountForBlock(container, blocks[1].ID)
|
|
require.NoError(t, err, "get subscribers for block should not error")
|
|
assert.Equal(t, 50, count)
|
|
|
|
// make sure block[0] has zero users subscribed
|
|
subs, err = store.GetSubscribersForBlock(container, blocks[0].ID)
|
|
require.NoError(t, err, "get subscribers for block should not error")
|
|
assert.Empty(t, subs)
|
|
|
|
count, err = store.GetSubscribersCountForBlock(container, blocks[0].ID)
|
|
require.NoError(t, err, "get subscribers for block should not error")
|
|
assert.Zero(t, count)
|
|
})
|
|
|
|
t.Run("get subscribers for invalid block", func(t *testing.T) {
|
|
subs, err := store.GetSubscribersForBlock(container, "bogus")
|
|
require.NoError(t, err, "get subscribers for block should not error")
|
|
assert.Empty(t, subs)
|
|
})
|
|
}
|