github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/testlib/helper.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package testlib 5 6 import ( 7 "flag" 8 "fmt" 9 "io/ioutil" 10 "log" 11 "os" 12 "path/filepath" 13 "testing" 14 15 "github.com/pkg/errors" 16 17 "github.com/mattermost/mattermost-server/v5/mlog" 18 "github.com/mattermost/mattermost-server/v5/model" 19 "github.com/mattermost/mattermost-server/v5/services/searchengine" 20 "github.com/mattermost/mattermost-server/v5/store" 21 "github.com/mattermost/mattermost-server/v5/store/searchlayer" 22 "github.com/mattermost/mattermost-server/v5/store/sqlstore" 23 "github.com/mattermost/mattermost-server/v5/store/storetest" 24 "github.com/mattermost/mattermost-server/v5/utils" 25 ) 26 27 type MainHelper struct { 28 Settings *model.SqlSettings 29 Store store.Store 30 SearchEngine *searchengine.Broker 31 SQLStore *sqlstore.SqlStore 32 ClusterInterface *FakeClusterInterface 33 34 status int 35 testResourcePath string 36 } 37 38 type HelperOptions struct { 39 EnableStore bool 40 EnableResources bool 41 } 42 43 func NewMainHelper() *MainHelper { 44 return NewMainHelperWithOptions(&HelperOptions{ 45 EnableStore: true, 46 EnableResources: true, 47 }) 48 } 49 50 func NewMainHelperWithOptions(options *HelperOptions) *MainHelper { 51 var mainHelper MainHelper 52 flag.Parse() 53 54 // Setup a global logger to catch tests logging outside of app context 55 // The global logger will be stomped by apps initializing but that's fine for testing. 56 // Ideally this won't happen. 57 mlog.InitGlobalLogger(mlog.NewLogger(&mlog.LoggerConfiguration{ 58 EnableConsole: true, 59 ConsoleJson: true, 60 ConsoleLevel: "error", 61 EnableFile: false, 62 })) 63 64 utils.TranslationsPreInit() 65 66 if options != nil { 67 if options.EnableStore && !testing.Short() { 68 mainHelper.setupStore() 69 } 70 71 if options.EnableResources { 72 mainHelper.setupResources() 73 } 74 } 75 76 return &mainHelper 77 } 78 79 func (h *MainHelper) Main(m *testing.M) { 80 if h.testResourcePath != "" { 81 prevDir, err := os.Getwd() 82 if err != nil { 83 panic("Failed to get current working directory: " + err.Error()) 84 } 85 86 err = os.Chdir(h.testResourcePath) 87 if err != nil { 88 panic(fmt.Sprintf("Failed to set current working directory to %s: %s", h.testResourcePath, err.Error())) 89 } 90 91 defer func() { 92 err := os.Chdir(prevDir) 93 if err != nil { 94 panic(fmt.Sprintf("Failed to restore current working directory to %s: %s", prevDir, err.Error())) 95 } 96 }() 97 } 98 99 h.status = m.Run() 100 } 101 102 func (h *MainHelper) setupStore() { 103 driverName := os.Getenv("MM_SQLSETTINGS_DRIVERNAME") 104 if driverName == "" { 105 driverName = model.DATABASE_DRIVER_POSTGRES 106 } 107 108 h.Settings = storetest.MakeSqlSettings(driverName) 109 110 config := &model.Config{} 111 config.SetDefaults() 112 113 h.SearchEngine = searchengine.NewBroker(config, nil) 114 h.ClusterInterface = &FakeClusterInterface{} 115 h.SQLStore = sqlstore.New(*h.Settings, nil) 116 h.Store = searchlayer.NewSearchLayer(&TestStore{ 117 h.SQLStore, 118 }, h.SearchEngine, config) 119 } 120 121 func (h *MainHelper) setupResources() { 122 var err error 123 h.testResourcePath, err = SetupTestResources() 124 if err != nil { 125 panic("failed to setup test resources: " + err.Error()) 126 } 127 } 128 129 // PreloadMigrations preloads the migrations and roles into the database 130 // so that they are not run again when the migrations happen every time 131 // the server is started. 132 // This change is forward-compatible with new migrations and only new migrations 133 // will get executed. 134 // Only if the schema of either roles or systems table changes, this will break. 135 // In that case, just update the migrations or comment this out for the time being. 136 // In the worst case, only an optimization is lost. 137 // 138 // Re-generate the files with: 139 // pg_dump -a -h localhost -U mmuser -d <> --no-comments --inserts -t roles -t systems 140 // mysqldump -u root -p <> --no-create-info --extended-insert=FALSE Systems Roles 141 // And keep only the permission related rows in the systems table output. 142 func (h *MainHelper) PreloadMigrations() { 143 var buf []byte 144 var err error 145 basePath := os.Getenv("MM_SERVER_PATH") 146 relPath := "testlib/testdata" 147 switch *h.Settings.DriverName { 148 case model.DATABASE_DRIVER_POSTGRES: 149 var finalPath string 150 if basePath != "" { 151 finalPath = filepath.Join(basePath, relPath, "postgres_migration_warmup.sql") 152 } else { 153 finalPath = filepath.Join("mattermost-server", relPath, "postgres_migration_warmup.sql") 154 } 155 buf, err = ioutil.ReadFile(finalPath) 156 if err != nil { 157 panic(fmt.Errorf("cannot read file: %v", err)) 158 } 159 case model.DATABASE_DRIVER_MYSQL: 160 var finalPath string 161 if basePath != "" { 162 finalPath = filepath.Join(basePath, relPath, "mysql_migration_warmup.sql") 163 } else { 164 finalPath = filepath.Join("mattermost-server", relPath, "mysql_migration_warmup.sql") 165 } 166 buf, err = ioutil.ReadFile(finalPath) 167 if err != nil { 168 panic(fmt.Errorf("cannot read file: %v", err)) 169 } 170 } 171 handle := h.SQLStore.GetMaster() 172 _, err = handle.Exec(string(buf)) 173 if err != nil { 174 panic(errors.Wrap(err, "Error preloading migrations. Check if you have &multiStatements=true in your DSN if you are using MySQL. Or perhaps the schema changed? If yes, then update the warmup files accordingly")) 175 } 176 } 177 178 func (h *MainHelper) Close() error { 179 if h.SQLStore != nil { 180 h.SQLStore.Close() 181 } 182 if h.Settings != nil { 183 storetest.CleanupSqlSettings(h.Settings) 184 } 185 if h.testResourcePath != "" { 186 os.RemoveAll(h.testResourcePath) 187 } 188 189 if r := recover(); r != nil { 190 log.Fatalln(r) 191 } 192 193 os.Exit(h.status) 194 195 return nil 196 } 197 198 func (h *MainHelper) GetSQLSettings() *model.SqlSettings { 199 if h.Settings == nil { 200 panic("MainHelper not initialized with database access.") 201 } 202 203 return h.Settings 204 } 205 206 func (h *MainHelper) GetStore() store.Store { 207 if h.Store == nil { 208 panic("MainHelper not initialized with store.") 209 } 210 211 return h.Store 212 } 213 214 func (h *MainHelper) GetSQLStore() *sqlstore.SqlStore { 215 if h.SQLStore == nil { 216 panic("MainHelper not initialized with sql store.") 217 } 218 219 return h.SQLStore 220 } 221 222 func (h *MainHelper) GetClusterInterface() *FakeClusterInterface { 223 if h.ClusterInterface == nil { 224 panic("MainHelper not initialized with cluster interface.") 225 } 226 227 return h.ClusterInterface 228 } 229 230 func (h *MainHelper) GetSearchEngine() *searchengine.Broker { 231 if h.SearchEngine == nil { 232 panic("MainHelper not initialized with search engine") 233 } 234 235 return h.SearchEngine 236 }