MM-8796: Full implementation of "Schemes" in Store/Model/App layers. (#8357)

* Add Scheme model and stub store.

* Port ChannelStore to be Scheme aware.

* Make almost all the API/APP layer work with ChannelSchemes.

Only thing still hacky is UpdateChannelMemberRoles().

* Add basic SchemeStore implementation.

* Migrate UpdateChannelMemberRoles properly and fix tests.

* Update store tests and mocks so they work.

* Include creating default roles in Scheme create store function.

* Implement role deletion and start scheme deletion.

* Only use non-deleted roles for authorization.

* Add GetByScheme method to Team store.

* Add GetChannelsByScheme.

* Update store mocks.

* Implement scheme deletion in the store.

* Rename is valid function.

* Add offset and limit to queries to fetch teams and channels by scheme.

* Fix queries.

* Implement scheme awareness in Team store and add a migration.

* Tidy up ChannelStore mapping functions and add exhaustive unit tests.

* Add all missing i18n.

* Proper tests for TeamStore internal functions and fix them.

* Make additional TeamMember fields nullable.

* Make new ChannelMember fields nullable.

* Create new nullable columns without defaults.

* Make new fields in large tables nullalble.

* Fix empty list of TeamMembers.

* Deduplicate SQL queries.

* Fix spelling.

* Fix review comment.

* More review fixes.

* More review fixes.
This commit is contained in:
George Goldberg
2018-04-20 19:49:13 +01:00
committed by Martin Kraft
parent 853445dc2e
commit cd55c44c8f
48 changed files with 3605 additions and 176 deletions

View File

@@ -16,6 +16,8 @@ import (
)
func TestChannelStore(t *testing.T, ss store.Store) {
createDefaultRoles(t, ss)
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) })
@@ -49,6 +51,8 @@ func TestChannelStore(t *testing.T, ss store.Store) {
t.Run("AnalyticsDeletedTypeCount", func(t *testing.T) { testChannelStoreAnalyticsDeletedTypeCount(t, ss) })
t.Run("GetPinnedPosts", func(t *testing.T) { testChannelStoreGetPinnedPosts(t, ss) })
t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) })
t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(t, ss) })
}
func testChannelStoreSave(t *testing.T, ss store.Store) {
@@ -2186,3 +2190,67 @@ func testChannelStoreMaxChannelsPerTeam(t *testing.T, ss store.Store) {
result = <-ss.Channel().Save(channel, 1)
assert.Nil(t, result.Err)
}
func testChannelStoreGetChannelsByScheme(t *testing.T, ss store.Store) {
// Create some schemes.
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
}
s2 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
}
s1 = (<-ss.Scheme().Save(s1)).Data.(*model.Scheme)
s2 = (<-ss.Scheme().Save(s2)).Data.(*model.Scheme)
// Create and save some teams.
c1 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
SchemeId: &s1.Id,
}
c2 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
SchemeId: &s1.Id,
}
c3 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
}
c1 = (<-ss.Channel().Save(c1, 100)).Data.(*model.Channel)
c2 = (<-ss.Channel().Save(c2, 100)).Data.(*model.Channel)
c3 = (<-ss.Channel().Save(c3, 100)).Data.(*model.Channel)
// Get the channels by a valid Scheme ID.
res1 := <-ss.Channel().GetChannelsByScheme(s1.Id, 0, 100)
assert.Nil(t, res1.Err)
d1 := res1.Data.([]*model.Channel)
assert.Len(t, d1, 2)
// Get the channels by a valid Scheme ID where there aren't any matching Channel.
res2 := <-ss.Channel().GetChannelsByScheme(s2.Id, 0, 100)
assert.Nil(t, res2.Err)
d2 := res2.Data.([]*model.Channel)
assert.Len(t, d2, 0)
// Get the channels by an invalid Scheme ID.
res3 := <-ss.Channel().GetChannelsByScheme(model.NewId(), 0, 100)
assert.Nil(t, res3.Err)
d3 := res3.Data.([]*model.Channel)
assert.Len(t, d3, 0)
}

View File

@@ -258,6 +258,22 @@ func (_m *ChannelStore) GetChannels(teamId string, userId string) store.StoreCha
return r0
}
// GetChannelsByScheme provides a mock function with given fields: schemeId, offset, limit
func (_m *ChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(schemeId, offset, limit)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(schemeId, offset, limit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// GetDeleted provides a mock function with given fields: team_id, offset, limit
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int) store.StoreChannel {
ret := _m.Called(team_id, offset, limit)

View File

@@ -432,6 +432,29 @@ func (_m *LayeredStoreDatabaseLayer) Role() store.RoleStore {
return r0
}
// RoleDelete provides a mock function with given fields: ctx, roldId, hints
func (_m *LayeredStoreDatabaseLayer) RoleDelete(ctx context.Context, roldId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, roldId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, roldId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// RoleGet provides a mock function with given fields: ctx, roleId, hints
func (_m *LayeredStoreDatabaseLayer) RoleGet(ctx context.Context, roleId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
@@ -547,6 +570,91 @@ func (_m *LayeredStoreDatabaseLayer) RoleSave(ctx context.Context, role *model.R
return r0
}
// Scheme provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Scheme() store.SchemeStore {
ret := _m.Called()
var r0 store.SchemeStore
if rf, ok := ret.Get(0).(func() store.SchemeStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SchemeStore)
}
}
return r0
}
// SchemeDelete provides a mock function with given fields: ctx, schemeId, hints
func (_m *LayeredStoreDatabaseLayer) SchemeDelete(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, schemeId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, schemeId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeGet provides a mock function with given fields: ctx, schemeId, hints
func (_m *LayeredStoreDatabaseLayer) SchemeGet(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, schemeId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, schemeId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeSave provides a mock function with given fields: ctx, scheme, hints
func (_m *LayeredStoreDatabaseLayer) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, scheme)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, *model.Scheme, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, scheme, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// Session provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Session() store.SessionStore {
ret := _m.Called()

View File

@@ -145,6 +145,29 @@ func (_m *LayeredStoreSupplier) ReactionSave(ctx context.Context, reaction *mode
return r0
}
// RoleDelete provides a mock function with given fields: ctx, roldId, hints
func (_m *LayeredStoreSupplier) RoleDelete(ctx context.Context, roldId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, roldId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, roldId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// RoleGet provides a mock function with given fields: ctx, roleId, hints
func (_m *LayeredStoreSupplier) RoleGet(ctx context.Context, roleId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
@@ -260,6 +283,75 @@ func (_m *LayeredStoreSupplier) RoleSave(ctx context.Context, role *model.Role,
return r0
}
// SchemeDelete provides a mock function with given fields: ctx, schemeId, hints
func (_m *LayeredStoreSupplier) SchemeDelete(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, schemeId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, schemeId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeGet provides a mock function with given fields: ctx, schemeId, hints
func (_m *LayeredStoreSupplier) SchemeGet(ctx context.Context, schemeId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, schemeId)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, string, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, schemeId, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SchemeSave provides a mock function with given fields: ctx, scheme, hints
func (_m *LayeredStoreSupplier) SchemeSave(ctx context.Context, scheme *model.Scheme, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
_va := make([]interface{}, len(hints))
for _i := range hints {
_va[_i] = hints[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, scheme)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *store.LayeredStoreSupplierResult
if rf, ok := ret.Get(0).(func(context.Context, *model.Scheme, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok {
r0 = rf(ctx, scheme, hints...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*store.LayeredStoreSupplierResult)
}
}
return r0
}
// SetChainNext provides a mock function with given fields: _a0
func (_m *LayeredStoreSupplier) SetChainNext(_a0 store.LayeredStoreSupplier) {
_m.Called(_a0)

View File

@@ -13,6 +13,22 @@ type RoleStore struct {
mock.Mock
}
// Delete provides a mock function with given fields: roldId
func (_m *RoleStore) Delete(roldId string) store.StoreChannel {
ret := _m.Called(roldId)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string) store.StoreChannel); ok {
r0 = rf(roldId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Get provides a mock function with given fields: roleId
func (_m *RoleStore) Get(roleId string) store.StoreChannel {
ret := _m.Called(roleId)

View File

@@ -0,0 +1,62 @@
// Code generated by mockery v1.0.0
// Regenerate this file using `make store-mocks`.
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import store "github.com/mattermost/mattermost-server/store"
// SchemeStore is an autogenerated mock type for the SchemeStore type
type SchemeStore struct {
mock.Mock
}
// Delete provides a mock function with given fields: schemeId
func (_m *SchemeStore) Delete(schemeId string) store.StoreChannel {
ret := _m.Called(schemeId)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string) store.StoreChannel); ok {
r0 = rf(schemeId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Get provides a mock function with given fields: schemeId
func (_m *SchemeStore) Get(schemeId string) store.StoreChannel {
ret := _m.Called(schemeId)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string) store.StoreChannel); ok {
r0 = rf(schemeId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// Save provides a mock function with given fields: scheme
func (_m *SchemeStore) Save(scheme *model.Scheme) store.StoreChannel {
ret := _m.Called(scheme)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(*model.Scheme) store.StoreChannel); ok {
r0 = rf(scheme)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}

View File

@@ -554,6 +554,22 @@ func (_m *SqlStore) Role() store.RoleStore {
return r0
}
// Scheme provides a mock function with given fields:
func (_m *SqlStore) Scheme() store.SchemeStore {
ret := _m.Called()
var r0 store.SchemeStore
if rf, ok := ret.Get(0).(func() store.SchemeStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SchemeStore)
}
}
return r0
}
// Session provides a mock function with given fields:
func (_m *SqlStore) Session() store.SessionStore {
ret := _m.Called()

View File

@@ -299,6 +299,22 @@ func (_m *Store) Role() store.RoleStore {
return r0
}
// Scheme provides a mock function with given fields:
func (_m *Store) Scheme() store.SchemeStore {
ret := _m.Called()
var r0 store.SchemeStore
if rf, ok := ret.Get(0).(func() store.SchemeStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SchemeStore)
}
}
return r0
}
// Session provides a mock function with given fields:
func (_m *Store) Session() store.SessionStore {
ret := _m.Called()

View File

@@ -237,6 +237,22 @@ func (_m *TeamStore) GetMembersByIds(teamId string, userIds []string) store.Stor
return r0
}
// GetTeamsByScheme provides a mock function with given fields: schemeId, offset, limit
func (_m *TeamStore) GetTeamsByScheme(schemeId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(schemeId, offset, limit)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(schemeId, offset, limit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// GetTeamsByUserId provides a mock function with given fields: userId
func (_m *TeamStore) GetTeamsByUserId(userId string) store.StoreChannel {
ret := _m.Called(userId)

View File

@@ -17,6 +17,7 @@ func TestRoleStore(t *testing.T, ss store.Store) {
t.Run("Get", func(t *testing.T) { testRoleStoreGet(t, ss) })
t.Run("GetByName", func(t *testing.T) { testRoleStoreGetByName(t, ss) })
t.Run("GetNames", func(t *testing.T) { testRoleStoreGetByNames(t, ss) })
t.Run("Delete", func(t *testing.T) { testRoleStoreDelete(t, ss) })
t.Run("PermanentDeleteAll", func(t *testing.T) { testRoleStorePermanentDeleteAll(t, ss) })
}
@@ -244,6 +245,49 @@ func testRoleStoreGetByNames(t *testing.T, ss store.Store) {
assert.NotContains(t, roles6, d3)
}
func testRoleStoreDelete(t *testing.T, ss store.Store) {
// Save a role to test with.
r1 := &model.Role{
Name: model.NewId(),
DisplayName: model.NewId(),
Description: model.NewId(),
Permissions: []string{
"invite_user",
"create_public_channel",
"add_user_to_team",
},
SchemeManaged: false,
}
res1 := <-ss.Role().Save(r1)
assert.Nil(t, res1.Err)
d1 := res1.Data.(*model.Role)
assert.Len(t, d1.Id, 26)
// Check the role is there.
res2 := <-ss.Role().Get(d1.Id)
assert.Nil(t, res2.Err)
// Delete the role.
res3 := <-ss.Role().Delete(d1.Id)
assert.Nil(t, res3.Err)
// Check the role is deleted there.
res4 := <-ss.Role().Get(d1.Id)
assert.Nil(t, res4.Err)
d2 := res4.Data.(*model.Role)
assert.NotZero(t, d2.DeleteAt)
res5 := <-ss.Role().GetByName(d1.Name)
assert.Nil(t, res5.Err)
d3 := res5.Data.(*model.Role)
assert.NotZero(t, d3.DeleteAt)
// Try and delete a role that does not exist.
res6 := <-ss.Role().Delete(model.NewId())
assert.NotNil(t, res6.Err)
}
func testRoleStorePermanentDeleteAll(t *testing.T, ss store.Store) {
r1 := &model.Role{
Name: model.NewId(),
@@ -256,6 +300,7 @@ func testRoleStorePermanentDeleteAll(t *testing.T, ss store.Store) {
},
SchemeManaged: false,
}
r2 := &model.Role{
Name: model.NewId(),
DisplayName: model.NewId(),

View File

@@ -0,0 +1,303 @@
// Copyright (c) 2018-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 TestSchemeStore(t *testing.T, ss store.Store) {
createDefaultRoles(t, ss)
t.Run("Save", func(t *testing.T) { testSchemeStoreSave(t, ss) })
t.Run("Get", func(t *testing.T) { testSchemeStoreGet(t, ss) })
t.Run("Delete", func(t *testing.T) { testSchemeStoreDelete(t, ss) })
}
func createDefaultRoles(t *testing.T, ss store.Store) {
<-ss.Role().Save(&model.Role{
Name: model.TEAM_ADMIN_ROLE_ID,
DisplayName: model.TEAM_ADMIN_ROLE_ID,
Permissions: []string{
model.PERMISSION_EDIT_OTHERS_POSTS.Id,
model.PERMISSION_DELETE_OTHERS_POSTS.Id,
},
})
<-ss.Role().Save(&model.Role{
Name: model.TEAM_USER_ROLE_ID,
DisplayName: model.TEAM_USER_ROLE_ID,
Permissions: []string{
model.PERMISSION_VIEW_TEAM.Id,
model.PERMISSION_ADD_USER_TO_TEAM.Id,
},
})
<-ss.Role().Save(&model.Role{
Name: model.CHANNEL_ADMIN_ROLE_ID,
DisplayName: model.CHANNEL_ADMIN_ROLE_ID,
Permissions: []string{
model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
model.PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
},
})
<-ss.Role().Save(&model.Role{
Name: model.CHANNEL_USER_ROLE_ID,
DisplayName: model.CHANNEL_USER_ROLE_ID,
Permissions: []string{
model.PERMISSION_READ_CHANNEL.Id,
model.PERMISSION_CREATE_POST.Id,
},
})
}
func testSchemeStoreSave(t *testing.T, ss store.Store) {
// Save a new scheme.
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
// Check all fields saved correctly.
res1 := <-ss.Scheme().Save(s1)
assert.Nil(t, res1.Err)
d1 := res1.Data.(*model.Scheme)
assert.Len(t, d1.Id, 26)
assert.Equal(t, s1.Name, d1.Name)
assert.Equal(t, s1.Description, d1.Description)
assert.NotZero(t, d1.CreateAt)
assert.NotZero(t, d1.UpdateAt)
assert.Zero(t, d1.DeleteAt)
assert.Equal(t, s1.Scope, d1.Scope)
assert.Len(t, d1.DefaultTeamAdminRole, 26)
assert.Len(t, d1.DefaultTeamUserRole, 26)
assert.Len(t, d1.DefaultChannelAdminRole, 26)
assert.Len(t, d1.DefaultChannelUserRole, 26)
// Check the default roles were created correctly.
roleRes1 := <-ss.Role().Get(d1.DefaultTeamAdminRole)
assert.Nil(t, roleRes1.Err)
role1 := roleRes1.Data.(*model.Role)
assert.Equal(t, role1.Permissions, []string{"edit_others_posts", "delete_others_posts"})
assert.True(t, role1.SchemeManaged)
roleRes2 := <-ss.Role().Get(d1.DefaultTeamUserRole)
assert.Nil(t, roleRes2.Err)
role2 := roleRes2.Data.(*model.Role)
assert.Equal(t, role2.Permissions, []string{"view_team", "add_user_to_team"})
assert.True(t, role2.SchemeManaged)
roleRes3 := <-ss.Role().Get(d1.DefaultChannelAdminRole)
assert.Nil(t, roleRes3.Err)
role3 := roleRes3.Data.(*model.Role)
assert.Equal(t, role3.Permissions, []string{"manage_public_channel_members", "manage_private_channel_members"})
assert.True(t, role3.SchemeManaged)
roleRes4 := <-ss.Role().Get(d1.DefaultChannelUserRole)
assert.Nil(t, roleRes4.Err)
role4 := roleRes4.Data.(*model.Role)
assert.Equal(t, role4.Permissions, []string{"read_channel", "create_post"})
assert.True(t, role4.SchemeManaged)
// Change the scheme description and update.
d1.Description = model.NewId()
res2 := <-ss.Scheme().Save(d1)
assert.Nil(t, res2.Err)
d2 := res2.Data.(*model.Scheme)
assert.Equal(t, d1.Id, d2.Id)
assert.Equal(t, s1.Name, d2.Name)
assert.Equal(t, d1.Description, d2.Description)
assert.NotZero(t, d2.CreateAt)
assert.NotZero(t, d2.UpdateAt)
assert.Zero(t, d2.DeleteAt)
assert.Equal(t, s1.Scope, d2.Scope)
assert.Equal(t, d1.DefaultTeamAdminRole, d2.DefaultTeamAdminRole)
assert.Equal(t, d1.DefaultTeamUserRole, d2.DefaultTeamUserRole)
assert.Equal(t, d1.DefaultChannelAdminRole, d2.DefaultChannelAdminRole)
assert.Equal(t, d1.DefaultChannelUserRole, d2.DefaultChannelUserRole)
// Try saving one with an invalid ID set.
s3 := &model.Scheme{
Id: model.NewId(),
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
res3 := <-ss.Scheme().Save(s3)
assert.NotNil(t, res3.Err)
}
func testSchemeStoreGet(t *testing.T, ss store.Store) {
// Save a scheme to test with.
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
res1 := <-ss.Scheme().Save(s1)
assert.Nil(t, res1.Err)
d1 := res1.Data.(*model.Scheme)
assert.Len(t, d1.Id, 26)
// Get a valid scheme
res2 := <-ss.Scheme().Get(d1.Id)
assert.Nil(t, res2.Err)
d2 := res1.Data.(*model.Scheme)
assert.Equal(t, d1.Id, d2.Id)
assert.Equal(t, s1.Name, d2.Name)
assert.Equal(t, d1.Description, d2.Description)
assert.NotZero(t, d2.CreateAt)
assert.NotZero(t, d2.UpdateAt)
assert.Zero(t, d2.DeleteAt)
assert.Equal(t, s1.Scope, d2.Scope)
assert.Equal(t, d1.DefaultTeamAdminRole, d2.DefaultTeamAdminRole)
assert.Equal(t, d1.DefaultTeamUserRole, d2.DefaultTeamUserRole)
assert.Equal(t, d1.DefaultChannelAdminRole, d2.DefaultChannelAdminRole)
assert.Equal(t, d1.DefaultChannelUserRole, d2.DefaultChannelUserRole)
// Get an invalid scheme
res3 := <-ss.Scheme().Get(model.NewId())
assert.NotNil(t, res3.Err)
}
func testSchemeStoreDelete(t *testing.T, ss store.Store) {
// Save a new scheme.
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
// Check all fields saved correctly.
res1 := <-ss.Scheme().Save(s1)
assert.Nil(t, res1.Err)
d1 := res1.Data.(*model.Scheme)
assert.Len(t, d1.Id, 26)
assert.Equal(t, s1.Name, d1.Name)
assert.Equal(t, s1.Description, d1.Description)
assert.NotZero(t, d1.CreateAt)
assert.NotZero(t, d1.UpdateAt)
assert.Zero(t, d1.DeleteAt)
assert.Equal(t, s1.Scope, d1.Scope)
assert.Len(t, d1.DefaultTeamAdminRole, 26)
assert.Len(t, d1.DefaultTeamUserRole, 26)
assert.Len(t, d1.DefaultChannelAdminRole, 26)
assert.Len(t, d1.DefaultChannelUserRole, 26)
// Check the default roles were created correctly.
roleRes1 := <-ss.Role().Get(d1.DefaultTeamAdminRole)
assert.Nil(t, roleRes1.Err)
role1 := roleRes1.Data.(*model.Role)
assert.Equal(t, role1.Permissions, []string{"edit_others_posts", "delete_others_posts"})
assert.True(t, role1.SchemeManaged)
roleRes2 := <-ss.Role().Get(d1.DefaultTeamUserRole)
assert.Nil(t, roleRes2.Err)
role2 := roleRes2.Data.(*model.Role)
assert.Equal(t, role2.Permissions, []string{"view_team", "add_user_to_team"})
assert.True(t, role2.SchemeManaged)
roleRes3 := <-ss.Role().Get(d1.DefaultChannelAdminRole)
assert.Nil(t, roleRes3.Err)
role3 := roleRes3.Data.(*model.Role)
assert.Equal(t, role3.Permissions, []string{"manage_public_channel_members", "manage_private_channel_members"})
assert.True(t, role3.SchemeManaged)
roleRes4 := <-ss.Role().Get(d1.DefaultChannelUserRole)
assert.Nil(t, roleRes4.Err)
role4 := roleRes4.Data.(*model.Role)
assert.Equal(t, role4.Permissions, []string{"read_channel", "create_post"})
assert.True(t, role4.SchemeManaged)
// Delete the scheme.
res2 := <-ss.Scheme().Delete(d1.Id)
if !assert.Nil(t, res2.Err) {
t.Fatal(res2.Err)
}
d2 := res2.Data.(*model.Scheme)
assert.NotZero(t, d2.DeleteAt)
// Check that the roles are deleted too.
roleRes5 := <-ss.Role().Get(d1.DefaultTeamAdminRole)
assert.Nil(t, roleRes5.Err)
role5 := roleRes5.Data.(*model.Role)
assert.NotZero(t, role5.DeleteAt)
roleRes6 := <-ss.Role().Get(d1.DefaultTeamUserRole)
assert.Nil(t, roleRes6.Err)
role6 := roleRes6.Data.(*model.Role)
assert.NotZero(t, role6.DeleteAt)
roleRes7 := <-ss.Role().Get(d1.DefaultChannelAdminRole)
assert.Nil(t, roleRes7.Err)
role7 := roleRes7.Data.(*model.Role)
assert.NotZero(t, role7.DeleteAt)
roleRes8 := <-ss.Role().Get(d1.DefaultChannelUserRole)
assert.Nil(t, roleRes8.Err)
role8 := roleRes8.Data.(*model.Role)
assert.NotZero(t, role8.DeleteAt)
// Try deleting a scheme that does not exist.
res3 := <-ss.Scheme().Delete(model.NewId())
assert.NotNil(t, res3.Err)
// Try deleting a team scheme that's in use.
s4 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
res4 := <-ss.Scheme().Save(s4)
assert.Nil(t, res4.Err)
d4 := res4.Data.(*model.Scheme)
t4 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
SchemeId: &d4.Id,
}
tres4 := <-ss.Team().Save(t4)
assert.Nil(t, tres4.Err)
t4 = tres4.Data.(*model.Team)
sres4 := <-ss.Scheme().Delete(d4.Id)
assert.NotNil(t, sres4.Err)
// Try deleting a channel scheme that's in use.
s5 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_CHANNEL,
}
res5 := <-ss.Scheme().Save(s5)
assert.Nil(t, res5.Err)
d5 := res5.Data.(*model.Scheme)
c5 := &model.Channel{
TeamId: model.NewId(),
DisplayName: model.NewId(),
Name: model.NewId(),
Type: model.CHANNEL_OPEN,
SchemeId: &d5.Id,
}
cres5 := <-ss.Channel().Save(c5, -1)
assert.Nil(t, cres5.Err)
c5 = cres5.Data.(*model.Channel)
sres5 := <-ss.Scheme().Delete(d5.Id)
assert.NotNil(t, sres5.Err)
}

View File

@@ -44,6 +44,7 @@ type Store struct {
PluginStore mocks.PluginStore
ChannelMemberHistoryStore mocks.ChannelMemberHistoryStore
RoleStore mocks.RoleStore
SchemeStore mocks.SchemeStore
}
func (s *Store) Team() store.TeamStore { return &s.TeamStore }
@@ -70,6 +71,7 @@ func (s *Store) Job() store.JobStore { return &s.JobSt
func (s *Store) UserAccessToken() store.UserAccessTokenStore { return &s.UserAccessTokenStore }
func (s *Store) Plugin() store.PluginStore { return &s.PluginStore }
func (s *Store) Role() store.RoleStore { return &s.RoleStore }
func (s *Store) Scheme() store.SchemeStore { return &s.SchemeStore }
func (s *Store) ChannelMemberHistory() store.ChannelMemberHistoryStore {
return &s.ChannelMemberHistoryStore
}
@@ -107,5 +109,6 @@ func (s *Store) AssertExpectations(t mock.TestingT) bool {
&s.ChannelMemberHistoryStore,
&s.PluginStore,
&s.RoleStore,
&s.SchemeStore,
)
}

View File

@@ -7,11 +7,15 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
)
func TestTeamStore(t *testing.T, ss store.Store) {
createDefaultRoles(t, ss)
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) })
@@ -34,6 +38,7 @@ func TestTeamStore(t *testing.T, ss store.Store) {
t.Run("GetChannelUnreadsForAllTeams", func(t *testing.T) { testGetChannelUnreadsForAllTeams(t, ss) })
t.Run("GetChannelUnreadsForTeam", func(t *testing.T) { testGetChannelUnreadsForTeam(t, ss) })
t.Run("UpdateLastTeamIconUpdate", func(t *testing.T) { testUpdateLastTeamIconUpdate(t, ss) })
t.Run("GetTeamsByScheme", func(t *testing.T) { testGetTeamsByScheme(t, ss) })
}
func testTeamStoreSave(t *testing.T, ss store.Store) {
@@ -1029,3 +1034,67 @@ func testUpdateLastTeamIconUpdate(t *testing.T, ss store.Store) {
t.Fatal("LastTeamIconUpdate not updated")
}
}
func testGetTeamsByScheme(t *testing.T, ss store.Store) {
// Create some schemes.
s1 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
s2 := &model.Scheme{
Name: model.NewId(),
Description: model.NewId(),
Scope: model.SCHEME_SCOPE_TEAM,
}
s1 = (<-ss.Scheme().Save(s1)).Data.(*model.Scheme)
s2 = (<-ss.Scheme().Save(s2)).Data.(*model.Scheme)
// Create and save some teams.
t1 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
SchemeId: &s1.Id,
}
t2 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
SchemeId: &s1.Id,
}
t3 := &model.Team{
Name: model.NewId(),
DisplayName: model.NewId(),
Email: model.NewId() + "@nowhere.com",
Type: model.TEAM_OPEN,
}
t1 = (<-ss.Team().Save(t1)).Data.(*model.Team)
t2 = (<-ss.Team().Save(t2)).Data.(*model.Team)
t3 = (<-ss.Team().Save(t3)).Data.(*model.Team)
// Get the teams by a valid Scheme ID.
res1 := <-ss.Team().GetTeamsByScheme(s1.Id, 0, 100)
assert.Nil(t, res1.Err)
d1 := res1.Data.([]*model.Team)
assert.Len(t, d1, 2)
// Get the teams by a valid Scheme ID where there aren't any matching Teams.
res2 := <-ss.Team().GetTeamsByScheme(s2.Id, 0, 100)
assert.Nil(t, res2.Err)
d2 := res2.Data.([]*model.Team)
assert.Len(t, d2, 0)
// Get the teams by an invalid Scheme ID.
res3 := <-ss.Team().GetTeamsByScheme(model.NewId(), 0, 100)
assert.Nil(t, res3.Err)
d3 := res3.Data.([]*model.Team)
assert.Len(t, d3, 0)
}