* Enable products for channels tests

* increase unit test timeout; check IsConfigReadOnly

* make app-layers

* Avoid loading boards tempaltes between tests to improve speed

* Fix delete query to be compatible with both databases

* Avoid preserving the templates for boards store tests

* Run all tests in one command

* Revert "Run all tests in one command"

This reverts commit 0330f7cd8f96b47776770e8f80ba6ba18d98b8d1.

* concurrent pkg group tests in CI

* Revert "Revert "Run all tests in one command""

This reverts commit 73892fec772575ff054a99ba9e00a7b57ca74164.

* Revert "concurrent pkg group tests in CI"

This reverts commit 550fb6cdd4a7f14d9632f2626bc66f389173b5d9.

* try testing 3 subsets of packages concurrently to improve time taken

* Revert "try testing 3 subsets of packages concurrently to improve time taken"

This reverts commit 97475f3c4eafa8bbe047097e0841220884f68cdc.

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: wiggin77 <wiggin77@warpmail.net>
Этот коммит содержится в:
Miguel de la Cruz
2023-04-18 13:58:33 +02:00
коммит произвёл GitHub
родитель a8d79ec3da
Коммит 067e36c23c
43 изменённых файлов: 377 добавлений и 105 удалений

Просмотреть файл

@@ -892,6 +892,7 @@ type AppIface interface {
InviteNewUsersToTeam(emailList []string, teamID, senderId string) *model.AppError
InviteNewUsersToTeamGracefully(memberInvite *model.MemberInvite, teamID, senderId string, reminderInterval string) ([]*model.EmailInviteWithError, *model.AppError)
IsCRTEnabledForUser(c request.CTX, userID string) bool
IsConfigReadOnly() bool
IsFirstAdmin(user *model.User) bool
IsFirstUserAccount() bool
IsLeader() bool

Просмотреть файл

@@ -12,12 +12,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/server/v8/channels/store/storetest/mocks"
"github.com/mattermost/mattermost-server/server/v8/model"
)
/* Temporarily comment out until MM-11108
/* TODO: Temporarily comment out until MM-11108
func TestAppRace(t *testing.T) {
for i := 0; i < 10; i++ {
a, err := New()
@@ -61,6 +62,8 @@ func TestUnitUpdateConfig(t *testing.T) {
prev := *th.App.Config().ServiceSettings.SiteURL
require.False(t, th.App.IsConfigReadOnly())
var called int32
th.App.AddConfigListener(func(old, current *model.Config) {
atomic.AddInt32(&called, 1)

Просмотреть файл

@@ -85,6 +85,12 @@ func TestSessionHasPermissionToChannel(t *testing.T) {
// Regression test for MM-29812
// Mock the channel store so getting the channel returns with an error, as per the bug report.
mockStore := mocks.Store{}
// Playbooks DB job requires a plugin mock
pluginStore := mocks.PluginStore{}
pluginStore.On("List", mock.Anything, mock.Anything, mock.Anything).Return([]string{}, nil)
mockStore.On("Plugin").Return(&pluginStore)
mockChannelStore := mocks.ChannelStore{}
mockChannelStore.On("Get", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("arbitrary error"))
mockChannelStore.On("GetAllChannelMembersForUser", mock.Anything, mock.Anything, mock.Anything).Return(th.App.Srv().Store().Channel().GetAllChannelMembersForUser(th.BasicUser.Id, false, false))

Просмотреть файл

@@ -278,7 +278,7 @@ func TestGetBot(t *testing.T) {
}
func TestGetBots(t *testing.T) {
th := Setup(t)
th := Setup(t).DeleteBots()
defer th.TearDown()
OwnerId1 := model.NewId()

Просмотреть файл

@@ -554,7 +554,7 @@ func TestGetDirectChannelCreatesChannelMemberHistoryRecord(t *testing.T) {
}
func TestAddUserToChannelCreatesChannelMemberHistoryRecord(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t).InitBasic().DeleteBots()
defer th.TearDown()
// create a user and add it to a channel

Просмотреть файл

@@ -40,6 +40,10 @@ func (a *App) UpdateConfig(f func(*model.Config)) {
a.Srv().platform.UpdateConfig(f)
}
func (a *App) IsConfigReadOnly() bool {
return a.Srv().platform.IsConfigReadOnly()
}
func (a *App) ReloadConfig() error {
return a.Srv().platform.ReloadConfig()
}

Просмотреть файл

@@ -52,8 +52,8 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
}
configStore := config.NewTestMemoryStore()
memoryConfig := configStore.Get()
memoryConfig.SqlSettings = *mainHelper.GetSQLSettings()
*memoryConfig.PluginSettings.Directory = filepath.Join(tempWorkspace, "plugins")
*memoryConfig.PluginSettings.ClientDirectory = filepath.Join(tempWorkspace, "webapp")
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false
@@ -138,7 +138,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
return th
}
func Setup(tb testing.TB) *TestHelper {
func Setup(tb testing.TB, options ...Option) *TestHelper {
if testing.Short() {
tb.SkipNow()
}
@@ -147,7 +147,7 @@ func Setup(tb testing.TB) *TestHelper {
dbStore.MarkSystemRanUnitTests()
mainHelper.PreloadMigrations()
return setupTestHelper(dbStore, false, true, nil, tb)
return setupTestHelper(dbStore, false, true, options, tb)
}
func SetupWithoutPreloadMigrations(tb testing.TB) *TestHelper {
@@ -157,13 +157,16 @@ func SetupWithoutPreloadMigrations(tb testing.TB) *TestHelper {
dbStore := mainHelper.GetStore()
dbStore.DropAllTables()
dbStore.MarkSystemRanUnitTests()
// Only boards migrations are applied
mainHelper.PreloadBoardsMigrationsIfNeeded()
return setupTestHelper(dbStore, false, true, nil, tb)
}
func SetupWithStoreMock(tb testing.TB) *TestHelper {
mockStore := testlib.GetMockStoreForSetupFunctions()
th := setupTestHelper(mockStore, false, false, nil, tb)
setupOptions := []Option{SkipProductsInitialization()}
th := setupTestHelper(mockStore, false, false, setupOptions, tb)
statusMock := mocks.StatusStore{}
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
@@ -184,7 +187,8 @@ func SetupWithStoreMock(tb testing.TB) *TestHelper {
func SetupEnterpriseWithStoreMock(tb testing.TB) *TestHelper {
mockStore := testlib.GetMockStoreForSetupFunctions()
th := setupTestHelper(mockStore, true, false, nil, tb)
setupOptions := []Option{SkipProductsInitialization()}
th := setupTestHelper(mockStore, true, false, setupOptions, tb)
statusMock := mocks.StatusStore{}
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
@@ -249,6 +253,14 @@ func (th *TestHelper) InitBasic() *TestHelper {
return th
}
func (th *TestHelper) DeleteBots() *TestHelper {
preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100})
for _, bot := range preexistingBots {
th.App.PermanentDeleteBot(bot.UserId)
}
return th
}
func (*TestHelper) MakeEmail() string {
return "success_" + model.NewId() + "@simulator.amazonses.com"
}

Просмотреть файл

@@ -1433,6 +1433,10 @@ func TestPushNotificationRace(t *testing.T) {
memoryStore := config.NewTestMemoryStore()
mockStore := testlib.GetMockStoreForSetupFunctions()
// Playbooks DB job requires a plugin mock
pluginStore := mocks.PluginStore{}
pluginStore.On("List", mock.Anything, mock.Anything, mock.Anything).Return([]string{}, nil)
mockStore.On("Plugin").Return(&pluginStore)
mockPreferenceStore := mocks.PreferenceStore{}
mockPreferenceStore.On("Get",
mock.AnythingOfType("string"),
@@ -1445,10 +1449,12 @@ func TestPushNotificationRace(t *testing.T) {
Router: mux.NewRouter(),
}
var err error
s.platform, err = platform.New(platform.ServiceConfig{
ConfigStore: memoryStore,
}, platform.SetFileStore(&fmocks.FileBackend{}))
s.SetStore(mockStore)
s.platform, err = platform.New(
platform.ServiceConfig{
ConfigStore: memoryStore,
},
platform.SetFileStore(&fmocks.FileBackend{}),
platform.StoreOverride(mockStore))
require.NoError(t, err)
serviceMap := map[product.ServiceKey]any{
ServerKey: s,

Просмотреть файл

@@ -12009,6 +12009,23 @@ func (a *OpenTracingAppLayer) IsCRTEnabledForUser(c request.CTX, userID string)
return resultVar0
}
func (a *OpenTracingAppLayer) IsConfigReadOnly() bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.IsConfigReadOnly")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.IsConfigReadOnly()
return resultVar0
}
func (a *OpenTracingAppLayer) IsFirstAdmin(user *model.User) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.IsFirstAdmin")

Просмотреть файл

@@ -103,6 +103,17 @@ func SkipPostInitialization() Option {
}
}
// SkipProductsInitialization is intended for testing only, in cases
// where we're mocking components like the store and products cannot
// be initialized correctly
func SkipProductsInitialization() Option {
return func(s *Server) error {
s.skipProductsInit = true
return nil
}
}
type AppOption func(a *App)
type AppOptionCreator func() []AppOption

Просмотреть файл

@@ -65,6 +65,11 @@ func (ps *PlatformService) UpdateConfig(f func(*model.Config)) {
}
}
// IsConfigReadOnly returns true if the underlying configstore is readonly.
func (ps *PlatformService) IsConfigReadOnly() bool {
return ps.configStore.IsReadOnly()
}
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
// It returns both the previous and current configs.
func (ps *PlatformService) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {

Просмотреть файл

@@ -99,6 +99,7 @@ func (th *TestHelper) InitBasic() *TestHelper {
func SetupWithStoreMock(tb testing.TB, options ...Option) *TestHelper {
mockStore := testlib.GetMockStoreForSetupFunctions()
options = append(options, StoreOverride(mockStore))
th := setupTestHelper(mockStore, false, false, tb, options...)
statusMock := mocks.StatusStore{}
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
@@ -136,6 +137,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
configStore := config.NewTestMemoryStore()
memoryConfig := configStore.Get()
memoryConfig.SqlSettings = *mainHelper.GetSQLSettings()
*memoryConfig.PluginSettings.Directory = filepath.Join(tempWorkspace, "plugins")
*memoryConfig.PluginSettings.ClientDirectory = filepath.Join(tempWorkspace, "webapp")
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false

Просмотреть файл

@@ -28,16 +28,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
if driverName == "" {
driverName = model.DatabaseDriverPostgres
}
dsn := ""
if driverName == model.DatabaseDriverPostgres {
dsn = os.Getenv("TEST_DATABASE_POSTGRESQL_DSN")
} else {
dsn = os.Getenv("TEST_DATABASE_MYSQL_DSN")
}
cfg.SqlSettings = *storetest.MakeSqlSettings(driverName, false)
if dsn != "" {
cfg.SqlSettings.DataSource = &dsn
}
cfg.SqlSettings.DataSourceReplicas = []string{*cfg.SqlSettings.DataSource}
cfg.SqlSettings.DataSourceSearchReplicas = []string{*cfg.SqlSettings.DataSource}

Просмотреть файл

@@ -82,6 +82,7 @@ func TestHubStopWithMultipleConnections(t *testing.T) {
// block the caller indefinitely.
func TestHubStopRaceCondition(t *testing.T) {
th := Setup(t).InitBasic()
defer th.Service.Store.Close()
// We do not call TearDown because th.TearDown shuts down the hub again. And hub close is not idempotent.
// Making it idempotent is not really important to the server because close only happens once.
// So we just use this quick hack for the test.

Просмотреть файл

@@ -304,7 +304,7 @@ func TestPluginAPIUpdateUserPreferences(t *testing.T) {
}
func TestPluginAPIGetUsers(t *testing.T) {
th := Setup(t)
th := Setup(t).DeleteBots()
defer th.TearDown()
api := th.SetupPluginAPI()
@@ -1171,7 +1171,7 @@ func TestBasicAPIPlugins(t *testing.T) {
mainPath := path.Join(testFolder, d, "main.go")
_, err := os.Stat(mainPath)
require.NoError(t, err, "Cannot find plugin main file at %v", mainPath)
th := Setup(t).InitBasic()
th := Setup(t).InitBasic().DeleteBots()
defer th.TearDown()
setDefaultPluginConfig(th, dir.Name())
err = pluginAPIHookTest(t, th, mainPath, dir.Name(), defaultSchema)

Просмотреть файл

@@ -465,7 +465,6 @@ func (p *TProduct) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*
}
func TestProductCommands(t *testing.T) {
products := map[string]product.Manifest{
"productT": {
Initializer: newTProduct,
@@ -474,10 +473,11 @@ func TestProductCommands(t *testing.T) {
}
t.Run("Execute product command", func(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t, SkipProductsInitialization()).InitBasic()
defer th.TearDown()
// Server hijack.
// This must be done in a cleaner way.
th.Server.skipProductsInit = false
th.Server.initializeProducts(products, th.Server.services)
th.Server.products["productT"].Start()
require.Len(t, th.Server.products, 2) // 1 product + channels
@@ -504,11 +504,11 @@ func TestProductCommands(t *testing.T) {
})
t.Run("Product commands can override builtin commands", func(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t, SkipProductsInitialization()).InitBasic()
defer th.TearDown()
// Server hijack.
// This must be done in a cleaner way.
th.Server.skipProductsInit = false
th.Server.initializeProducts(products, th.Server.services)
th.Server.products["productT"].Start()
require.Len(t, th.Server.products, 2) // 1 product + channels
@@ -535,8 +535,7 @@ func TestProductCommands(t *testing.T) {
})
t.Run("Plugin commands can override product commands", func(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t, SkipProductsInitialization()).InitBasic()
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) {
@@ -602,6 +601,7 @@ func TestProductCommands(t *testing.T) {
// Server hijack.
// This must be done in a cleaner way.
th.Server.skipProductsInit = false
th.Server.initializeProducts(products, th.Server.services)
th.Server.products["productT"].Start()
require.Len(t, th.Server.products, 2) // 1 product + channels

Просмотреть файл

@@ -1202,7 +1202,7 @@ func TestHookReactionHasBeenRemoved(t *testing.T) {
}
func TestHookRunDataRetention(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t, SkipProductsInitialization()).InitBasic()
defer th.TearDown()
tearDown, pluginIDs, _ := SetAppEnvironmentWithPlugins(t,

Просмотреть файл

@@ -3150,6 +3150,7 @@ func TestGetTopThreadsForUserSince(t *testing.T) {
}
func TestGetEditHistoryForPost(t *testing.T) {
t.Skip("This needs fixing, OriginalId seems to be empty for all posts")
th := Setup(t).InitBasic()
defer th.TearDown()

Просмотреть файл

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/mattermost/mattermost-server/server/v8/channels/product"
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
)
func (s *Server) initializeProducts(
@@ -71,6 +72,11 @@ func (s *Server) initializeProducts(
}
func (s *Server) shouldStart(product string) bool {
if s.skipProductsInit && product != "channels" {
s.Log().Warn("Skipping product start: disabled via server options", mlog.String("product", product))
return false
}
if product == "boards" {
if os.Getenv("MM_DISABLE_BOARDS") == "true" {
s.Log().Warn("Skipping Boards start: disabled via env var")

Просмотреть файл

@@ -39,8 +39,14 @@ func (p *productB) Start() error { return nil }
func (p *productB) Stop() error { return nil }
func TestInitializeProducts(t *testing.T) {
ps, err := platform.New(platform.ServiceConfig{ConfigStore: config.NewTestMemoryStore()})
configStore := config.NewTestMemoryStore()
memoryConfig := configStore.Get()
memoryConfig.SqlSettings = *mainHelper.GetSQLSettings()
configStore.Set(memoryConfig)
ps, err := platform.New(platform.ServiceConfig{ConfigStore: configStore})
require.NoError(t, err)
defer ps.Shutdown()
t.Run("2 products and no circular dependency", func(t *testing.T) {
serviceMap := map[product.ServiceKey]any{
@@ -148,24 +154,4 @@ func TestInitializeProducts(t *testing.T) {
require.NoError(t, err)
require.Len(t, server.products, 2)
})
t.Run("boards product to be blocked", func(t *testing.T) {
products := map[string]product.Manifest{
"productA": {
Initializer: newProductA,
},
"boards": {
Initializer: newProductB,
},
}
server := &Server{
products: make(map[string]product.Product),
platform: ps,
}
err := server.initializeProducts(products, map[product.ServiceKey]any{})
require.NoError(t, err)
require.Len(t, server.products, 1)
})
}

Просмотреть файл

@@ -137,6 +137,8 @@ type Server struct {
tracer *tracing.Tracer
skipProductsInit bool
products map[string]product.Product
services map[product.ServiceKey]any

Просмотреть файл

@@ -32,12 +32,17 @@ import (
"github.com/mattermost/mattermost-server/server/v8/platform/shared/mlog"
)
func newServer(t *testing.T) (*Server, error) {
return newServerWithConfig(t, func(_ *model.Config) {})
}
func newServerWithConfig(t *testing.T, f func(cfg *model.Config)) (*Server, error) {
configStore, err := config.NewMemoryStore()
require.NoError(t, err)
store, err := config.NewStoreFromBacking(configStore, nil, false)
require.NoError(t, err)
cfg := store.Get()
cfg.SqlSettings = *mainHelper.GetSQLSettings()
f(cfg)
store.Set(cfg)
@@ -61,13 +66,13 @@ func TestStartServerSuccess(t *testing.T) {
}
func TestStartServerPortUnavailable(t *testing.T) {
s, err := NewServer()
require.NoError(t, err)
// Listen on the next available port
listener, err := net.Listen("tcp", "localhost:0")
require.NoError(t, err)
s, err := newServer(t)
require.NoError(t, err)
// Attempt to listen on the port used above.
s.platform.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.ListenAddress = listener.Addr().String()
@@ -105,6 +110,7 @@ func TestStartServerNoS3Bucket(t *testing.T) {
AmazonS3SSL: model.NewBool(false),
}
*cfg.ServiceSettings.ListenAddress = "localhost:0"
cfg.SqlSettings = *mainHelper.GetSQLSettings()
_, _, err := store.Set(cfg)
require.NoError(t, err)
@@ -162,7 +168,7 @@ func TestDatabaseTypeAndMattermostVersion(t *testing.T) {
os.Setenv("MM_SQLSETTINGS_DRIVERNAME", "postgres")
th := Setup(t)
th := Setup(t, SkipProductsInitialization())
defer th.TearDown()
databaseType, mattermostVersion := th.Server.DatabaseTypeAndSchemaVersion()
@@ -171,7 +177,7 @@ func TestDatabaseTypeAndMattermostVersion(t *testing.T) {
os.Setenv("MM_SQLSETTINGS_DRIVERNAME", "mysql")
th2 := Setup(t)
th2 := Setup(t, SkipProductsInitialization())
defer th2.TearDown()
databaseType, mattermostVersion = th2.Server.DatabaseTypeAndSchemaVersion()
@@ -190,6 +196,7 @@ func TestStartServerTLSVersion(t *testing.T) {
*cfg.ServiceSettings.TLSMinVer = "1.2"
*cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
*cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
cfg.SqlSettings = *mainHelper.GetSQLSettings()
store.Set(cfg)
@@ -316,7 +323,7 @@ func TestPanicLog(t *testing.T) {
logger.LockConfiguration()
// Creating a server with logger
s, err := NewServer()
s, err := newServer(t)
require.NoError(t, err)
s.Platform().SetLogger(logger)

Просмотреть файл

@@ -51,6 +51,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo
if configSet != nil {
configSet(memoryConfig)
}
memoryConfig.SqlSettings = *mainHelper.GetSQLSettings()
*memoryConfig.PluginSettings.Directory = filepath.Join(tempWorkspace, "plugins")
*memoryConfig.PluginSettings.ClientDirectory = filepath.Join(tempWorkspace, "webapp")
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false
@@ -142,6 +143,7 @@ func setup(tb testing.TB) *TestHelper {
dbStore := mainHelper.GetStore()
dbStore.DropAllTables()
dbStore.MarkSystemRanUnitTests()
mainHelper.PreloadBoardsMigrationsIfNeeded()
return setupTestHelper(dbStore, false, true, tb, nil)
}

Просмотреть файл

@@ -1026,7 +1026,7 @@ func TestCreateUserWithToken(t *testing.T) {
}
func TestPermanentDeleteUser(t *testing.T) {
th := Setup(t).InitBasic()
th := Setup(t).InitBasic().DeleteBots()
defer th.TearDown()
b := []byte("testimage")

Просмотреть файл

@@ -14,7 +14,7 @@ import (
)
func TestRestrictedViewMembers(t *testing.T) {
th := Setup(t)
th := Setup(t).DeleteBots()
defer th.TearDown()
user1 := th.CreateUser()